Merge pull request '注释了一部分mode' (#13) from dev-zhongfengrong into main

main^2
pm3eh4urb 8 months ago
commit 0ba4a4b23d

@ -28,172 +28,166 @@
of flags, and then calls the real compiler.
*/
#define AFL_MAIN
#define AFL_MAIN // 定义宏AFL_MAIN
#include "../config.h"
#include "../types.h"
#include "../debug.h"
#include "../alloc-inl.h"
#include "../config.h" // 引入配置文件
#include "../types.h" // 引入类型定义文件
#include "../debug.h" // 引入调试相关文件
#include "../alloc-inl.h" // 引入内存分配相关的文件
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h> // 引入标准输入输出库
#include <unistd.h> // 引入UNIX标准库
#include <stdlib.h> // 引入标准库
#include <string.h> // 引入字符串处理库
static u8* obj_path; /* Path to runtime libraries */
static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
/* Try to find the runtime libraries. If that fails, abort. */
static u8* obj_path; /* 运行时库的路径 */
static u8** cc_params; /* 传递给真实编译器的参数 */
static u32 cc_par_cnt = 1; /* 参数计数初始包含argv0 */
/* 尝试查找运行时库。如果失败,则中止。 */
static void find_obj(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH");
u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量AFL_PATH
u8 *slash, *tmp;
if (afl_path) {
if (afl_path) { // 如果设置了AFL_PATH
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path);
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); // 格式化路径
if (!access(tmp, R_OK)) {
obj_path = afl_path;
ck_free(tmp);
if (!access(tmp, R_OK)) { // 检查文件是否可读
obj_path = afl_path; // 设置运行时库路径
ck_free(tmp); // 释放临时字符串
return;
}
ck_free(tmp);
ck_free(tmp); // 释放临时字符串
}
slash = strrchr(argv0, '/');
slash = strrchr(argv0, '/'); // 查找路径中的最后一个斜杠
if (slash) {
if (slash) { // 如果找到斜杠
u8 *dir;
*slash = 0;
dir = ck_strdup(argv0);
*slash = '/';
*slash = 0; // 将斜杠替换为结束符
dir = ck_strdup(argv0); // 复制路径
*slash = '/'; // 恢复斜杠
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
tmp = alloc_printf("%s/afl-llvm-rt.o", dir); // 格式化路径
if (!access(tmp, R_OK)) {
obj_path = dir;
ck_free(tmp);
if (!access(tmp, R_OK)) { // 检查文件是否可读
obj_path = dir; // 设置运行时库路径
ck_free(tmp); // 释放临时字符串
return;
}
ck_free(tmp);
ck_free(dir);
ck_free(tmp); // 释放临时字符串
ck_free(dir); // 释放目录字符串
}
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
obj_path = AFL_PATH;
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { // 检查默认路径
obj_path = AFL_PATH; // 设置运行时库路径
return;
}
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH");
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH"); // 查找失败时提示错误
}
/* Copy argv to cc_params, making the necessary edits. */
/* 复制argv到cc_params并进行必要的编辑。 */
static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
u8 *name;
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0; // 初始化标志变量
u8 *name; // 当前文件名
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
cc_params = ck_alloc((argc + 128) * sizeof(u8*)); // 分配参数数组内存
name = strrchr(argv[0], '/');
if (!name) name = argv[0]; else name++;
name = strrchr(argv[0], '/'); // 获取程序名
if (!name) name = argv[0]; else name++; // 如果没有斜杠,则使用完整路径
// 根据程序名设置编译器
if (!strcmp(name, "afl-clang-fast++")) {
u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
u8* alt_cxx = getenv("AFL_CXX"); // 获取环境变量AFL_CXX
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 设置C++编译器
} else {
u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
u8* alt_cc = getenv("AFL_CC"); // 获取环境变量AFL_CC
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 设置C编译器
}
/* There are two ways to compile afl-clang-fast. In the traditional mode, we
use afl-llvm-pass.so to inject instrumentation. In the experimental
'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
instead. The latter is a very recent addition - see:
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */
/* 有两种编译afl-clang-fast的方式。传统模式下我们使用afl-llvm-pass.so注入插桩。
'trace-pc-guard'使LLVM */
#ifdef USE_TRACE_PC
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; // 添加Trace PC Guard标志
#ifndef __ANDROID__
cc_params[cc_par_cnt++] = "-mllvm";
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
cc_params[cc_par_cnt++] = "-mllvm"; // 添加LLVM的命令行标志
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设置阈值为0
#endif
#else
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
cc_params[cc_par_cnt++] = "-Xclang"; // 添加编译器的命令行标志
cc_params[cc_par_cnt++] = "-load"; // 加载指定共享库
cc_params[cc_par_cnt++] = "-Xclang"; // 添加编译器的命令行标志
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); // 添加动态库路径
#endif /* ^USE_TRACE_PC */
cc_params[cc_par_cnt++] = "-Qunused-arguments";
cc_params[cc_par_cnt++] = "-Qunused-arguments"; // 添加未使用参数警告
// 处理命令行参数
while (--argc) {
u8* cur = *(++argv);
u8* cur = *(++argv); // 当前参数
if (!strcmp(cur, "-m32")) bit_mode = 32;
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
if (!strcmp(cur, "-m64")) bit_mode = 64;
if (!strcmp(cur, "-m32")) bit_mode = 32; // 检查32位模式
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; // ARM平台
if (!strcmp(cur, "-m64")) bit_mode = 64; // 检查64位模式
if (!strcmp(cur, "-x")) x_set = 1;
if (!strcmp(cur, "-x")) x_set = 1; // 检查-x标志
// 检查Address Sanitizer
if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; // 检查FORTIFY_SOURCE
if (!strcmp(cur, "-Wl,-z,defs") ||
!strcmp(cur, "-Wl,--no-undefined")) continue;
cc_params[cc_par_cnt++] = cur;
!strcmp(cur, "-Wl,--no-undefined")) continue; // 跳过链接器选项
cc_params[cc_par_cnt++] = cur; // 添加当前参数到编译参数数组
}
// 检查环境变量AFL_HARDEN
if (getenv("AFL_HARDEN")) {
cc_params[cc_par_cnt++] = "-fstack-protector-all"; // 启用栈保护
cc_params[cc_par_cnt++] = "-fstack-protector-all";
if (!fortify_set)
if (!fortify_set) // 如果没有FORTIFY_SOURCE则添加相关标志
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
}
// 检查Address Sanitizer和Memory Sanitizer的互斥
if (!asan_set) {
if (getenv("AFL_USE_ASAN")) {
if (getenv("AFL_USE_ASAN")) { // 如果启用Address Sanitizer
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN和MSAN是互斥的"); // 互斥检查
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
FATAL("ASAN和AFL_HARDEN是互斥的"); // 互斥检查
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=address";
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 添加标志
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用Address Sanitizer
} else if (getenv("AFL_USE_MSAN")) {
} else if (getenv("AFL_USE_MSAN")) { // 如果启用Memory Sanitizer
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN和MSAN是互斥的"); // 互斥检查
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
FATAL("MSAN和AFL_HARDEN是互斥的"); // 互斥检查
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=memory";
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 添加标志
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用Memory Sanitizer
}
@ -202,49 +196,37 @@ static void edit_params(u32 argc, char** argv) {
#ifdef USE_TRACE_PC
if (getenv("AFL_INST_RATIO"))
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
FATAL("AFL_INST_RATIO在'trace-pc'模式下不可用"); // 提示用户
#endif /* USE_TRACE_PC */
if (!getenv("AFL_DONT_OPTIMIZE")) {
cc_params[cc_par_cnt++] = "-g";
cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops";
if (!getenv("AFL_DONT_OPTIMIZE")) { // 如果没有设置不优化选项
cc_params[cc_par_cnt++] = "-g"; // 添加调试信息
cc_params[cc_par_cnt++] = "-O3"; // 添加优化等级
cc_params[cc_par_cnt++] = "-funroll-loops"; // 启用循环展开
}
if (getenv("AFL_NO_BUILTIN")) {
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
if (getenv("AFL_NO_BUILTIN")) { // 检查是否使用内建函数
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; // 禁用strcmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; // 禁用strncmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; // 禁用strcasecmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; // 禁用strncasecmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; // 禁用memcmp内建
}
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
/* When the user tries to use persistent or deferred forkserver modes by
appending a single line to the program, we want to reliably inject a
signature into the binary (to be picked up by afl-fuzz) and we want
to call a function from the runtime .o file. This is unnecessarily
painful for three reasons:
1) We need to convince the compiler not to optimize out the signature.
This is done with __attribute__((used)).
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; // 添加手动控制标志
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; // 添加编译器标志
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; // 添加不安全模式标志
2) We need to convince the linker, when called with -Wl,--gc-sections,
not to do the same. This is done by forcing an assignment to a
'volatile' pointer.
/* 当用户尝试使用持久化或延迟fork服务器模式时
.o
3) We need to declare __afl_persistent_loop() in the global namespace,
but doing this within a method in a class is hard - :: and extern "C"
are forbidden and __attribute__((alias(...))) doesn't work. Hence the
__asm__ aliasing trick.
1) 使__attribute__((used))
2) 使-Wl,--gc-sections
'volatile'
3) __afl_persistent_loop()
使__asm__
*/
@ -272,58 +254,55 @@ static void edit_params(u32 argc, char** argv) {
#endif /* ^__APPLE__ */
"_I(); } while (0)";
if (x_set) {
cc_params[cc_par_cnt++] = "-x";
cc_params[cc_par_cnt++] = "none";
if (x_set) { // 检查是否有-x标志
cc_params[cc_par_cnt++] = "-x"; // 添加-x标志
cc_params[cc_par_cnt++] = "none"; // 设置参数
}
#ifndef __ANDROID__
switch (bit_mode) {
switch (bit_mode) { // 根据位模式选择运行时库
case 0:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); // 添加默认路径
break;
case 32:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); // 32位库路径
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
if (access(cc_params[cc_par_cnt - 1], R_OK)) // 检查权限
FATAL("-m32不被你的编译器支持"); // 提示不支持
break;
case 64:
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); // 64位库路径
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
if (access(cc_params[cc_par_cnt - 1], R_OK)) // 检查权限
FATAL("-m64不被你的编译器支持"); // 提示不支持
break;
}
#endif
cc_params[cc_par_cnt] = NULL;
cc_params[cc_par_cnt] = NULL; // 结束参数数组
}
/* Main entry point */
/* 主入口点 */
int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) {
if (isatty(2) && !getenv("AFL_QUIET")) { // 检查终端和环境变量
#ifdef USE_TRACE_PC
SAYF(cCYA "afl-clang-fast [tpcg] " cBRI VERSION cRST " by <lszekeres@google.com>\n");
SAYF(cCYA "afl-clang-fast [tpcg] " cBRI VERSION cRST " by <lszekeres@google.com>\n"); // 输出版本信息
#else
SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by <lszekeres@google.com>\n");
SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by <lszekeres@google.com>\n"); // 输出版本信息
#endif /* ^USE_TRACE_PC */
}
if (argc < 2) {
if (argc < 2) { // 检查参数数量
SAYF("\n"
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n"
"for clang, letting you recompile third-party code with the required runtime\n"
@ -337,23 +316,22 @@ int main(int argc, char** argv) {
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. Setting\n"
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
BIN_PATH, BIN_PATH);
BIN_PATH, BIN_PATH); // 输出用法说明
exit(1);
exit(1); // 退出程序
}
#ifndef __ANDROID__
find_obj(argv[0]);
find_obj(argv[0]); // 查找运行时库
#endif
edit_params(argc, argv);
edit_params(argc, argv); // 编辑参数
execvp(cc_params[0], (char**)cc_params);
execvp(cc_params[0], (char**)cc_params); // 执行真实编译器
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); // 执行失败提示
return 0;
return 0; // 返回0表示成功
}

@ -1,92 +1,94 @@
/*
Copyright 2015 Google LLC All rights reserved.
Copyright 2015 Google LLC All rights reserved. // 版权声明2015年谷歌公司所有权利保留
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
Licensed under the Apache License, Version 2.0 (the "License"); // 根据Apache许可证第2.0版授权
you may not use this file except in compliance with the License. // 除非遵守许可证,否则不得使用此文件
You may obtain a copy of the License at: // 可以通过以下网址获得许可证副本
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0 // 许可证的链接
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software // 除非相关法律要求或书面协议,软件
distributed under the License is distributed on an "AS IS" BASIS, // 在“按原样”基础上分发
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // 不提供任何形式的明示或暗示的保证或条件
See the License for the specific language governing permissions and // 请参阅许可证以获取约束和限制的具体语言
limitations under the License. // 在许可证下的限制条款
*/
/*
american fuzzy lop - high-performance binary-only instrumentation
american fuzzy lop - high-performance binary-only instrumentation // American Fuzzy Lop - 高性能二进制插桩
-----------------------------------------------------------------
Written by Andrew Griffiths <agriffiths@google.com> and
Michal Zalewski <lcamtuf@google.com>
Written by Andrew Griffiths <agriffiths@google.com> and // 由Andrew Griffiths和
Michal Zalewski <lcamtuf@google.com> // Michal Zalewski编写
Idea & design very much by Andrew Griffiths.
Idea & design very much by Andrew Griffiths. // 概念和设计主要由Andrew Griffiths提出。
This code is a shim patched into the separately-distributed source
code of QEMU 2.10.0. It leverages the built-in QEMU tracing functionality
to implement AFL-style instrumentation and to take care of the remaining
parts of the AFL fork server logic.
This code is a shim patched into the separately-distributed source // 此代码是补丁,插入到单独分发的源代码中
code of QEMU 2.10.0. It leverages the built-in QEMU tracing functionality // QEMU 2.10.0的源代码中。 该代码利用了内置的QEMU跟踪功能
to implement AFL-style instrumentation and to take care of the remaining // 实现AFL风格的插桩并处理剩余
parts of the AFL fork server logic. // AFL fork服务器逻辑的部分内容。
The resulting QEMU binary is essentially a standalone instrumentation
tool; for an example of how to leverage it for other purposes, you can
have a look at afl-showmap.c.
The resulting QEMU binary is essentially a standalone instrumentation // 生成的QEMU二进制文件基本上是一个独立的插桩工具
tool; for an example of how to leverage it for other purposes, you can // 用于其他目的的示例可以参考
have a look at afl-showmap.c. // afl-showmap.c
*/
#include <sys/shm.h>
#include "../../config.h"
#include <sys/shm.h> // 包含共享内存的头文件
#include "../../config.h" // 包含项目配置的头文件
/***************************
* VARIOUS AUXILIARY STUFF *
***************************/
/* A snippet patched into tb_find_slow to inform the parent process that
we have hit a new block that hasn't been translated yet, and to tell
it to translate within its own context, too (this avoids translation
overhead in the next forked-off copy). */
/* A snippet patched into tb_find_slow to inform the parent process that // 一段插入到tb_find_slow中的代码用于通知父进程
we have hit a new block that hasn't been translated yet, and to tell // 我们已经遇到了一个尚未翻译的新块,并告诉父进程
it to translate within its own context, too (this avoids translation // 也在其自己的上下文中翻译(这避免了在下一个
overhead in the next forked-off copy). // 被fork的副本中出现翻译开销
*/
#define AFL_QEMU_CPU_SNIPPET1 do { \
afl_request_tsl(pc, cs_base, flags); \
} while (0)
afl_request_tsl(pc, cs_base, flags); \ // 调用afl_request_tsl函数传入参数
} while (0) // 循环体
/* This snippet kicks in when the instruction pointer is positioned at
_start and does the usual forkserver stuff, not very different from
/* This snippet kicks in when the instruction pointer is positioned at // 当指令指针位于_start位置时此代码段生效
_start and does the usual forkserver stuff, not very different from // 并执行常规的forkserver逻辑与通过afl-as.h注入的逻辑没有太大区别
regular instrumentation injected via afl-as.h. */
#define AFL_QEMU_CPU_SNIPPET2 do { \
if(itb->pc == afl_entry_point) { \
afl_setup(); \
afl_forkserver(cpu); \
if(itb->pc == afl_entry_point) { \ // 如果当前程序计数器等于入口点
afl_setup(); \ // 设置插桩环境
afl_forkserver(cpu); \ // 启动fork服务器
} \
afl_maybe_log(itb->pc); \
} while (0)
afl_maybe_log(itb->pc); \ // 可能记录当前地址
} while (0) // 循环体
/* We use one additional file descriptor to relay "needs translation"
/* We use one additional file descriptor to relay "needs translation" // 我们使用一个附加文件描述符来传递“需要翻译”的信息
messages between the child and the fork server. */
#define TSL_FD (FORKSRV_FD - 1)
#define TSL_FD (FORKSRV_FD - 1) // 定义一个文件描述符,用于传递翻译请求
/* This is equivalent to afl-as.h: */
static unsigned char *afl_area_ptr;
static unsigned char *afl_area_ptr; // 定义指向AFL区域的指针
/* Exported variables populated by the code patched into elfload.c: */
abi_ulong afl_entry_point, /* ELF entry point (_start) */
afl_start_code, /* .text start pointer */
afl_end_code; /* .text end pointer */
abi_ulong afl_entry_point, /* ELF entry point (_start) */ // ELF入口点
afl_start_code, /* .text start pointer */ // .text段起始指针
afl_end_code; /* .text end pointer */ // .text段结束指针
/* Set in the child process in forkserver mode: */
static unsigned char afl_fork_child;
unsigned int afl_forksrv_pid;
static unsigned char afl_fork_child; // 用于标记是否在fork子进程中
unsigned int afl_forksrv_pid; // fork服务器进程的PID
/* Instrumentation ratio: */
static unsigned int afl_inst_rms = MAP_SIZE;
static unsigned int afl_inst_rms = MAP_SIZE; // 插桩比例
/* Function declarations. */
// 函数声明
static void afl_setup(void);
static void afl_forkserver(CPUState*);
static inline void afl_maybe_log(abi_ulong);
@ -96,16 +98,16 @@ static void afl_request_tsl(target_ulong, target_ulong, uint64_t);
/* Data structure passed around by the translate handlers: */
struct afl_tsl {
target_ulong pc;
target_ulong cs_base;
uint64_t flags;
struct afl_tsl { // 传递给翻译处理程序的数据结构
target_ulong pc; // 当前程序计数器
target_ulong cs_base; // 段基址
uint64_t flags; // 标志
};
/* Some forward decls: */
TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t);
static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int);
TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t); // 查找翻译块的函数
static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int); // 查找翻译块的内联函数
/*************************
* ACTUAL IMPLEMENTATION *
@ -113,201 +115,194 @@ static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int);
/* Set up SHM region and initialize other stuff. */
static void afl_setup(void) {
static void afl_setup(void) { // 设置共享内存区域并初始化其他内容
char *id_str = getenv(SHM_ENV_VAR),
*inst_r = getenv("AFL_INST_RATIO");
char *id_str = getenv(SHM_ENV_VAR), // 获取共享内存环境变量
*inst_r = getenv("AFL_INST_RATIO"); // 获取插桩比例环境变量
int shm_id;
int shm_id; // 共享内存标识符
if (inst_r) {
if (inst_r) { // 如果设置了插桩比例
unsigned int r;
unsigned int r; // 声明插桩比例变量
r = atoi(inst_r);
r = atoi(inst_r); // 将环境变量转为整数
if (r > 100) r = 100;
if (!r) r = 1;
if (r > 100) r = 100; // 最大为100
if (!r) r = 1; // 如果为0则设置为1
afl_inst_rms = MAP_SIZE * r / 100;
afl_inst_rms = MAP_SIZE * r / 100; // 计算实际插桩比例
}
if (id_str) {
shm_id = atoi(id_str);
afl_area_ptr = shmat(shm_id, NULL, 0);
if (id_str) { // 如果设定了共享内存ID
if (afl_area_ptr == (void*)-1) exit(1);
shm_id = atoi(id_str); // 将ID转为整数
afl_area_ptr = shmat(shm_id, NULL, 0); // 附加共享内存
/* With AFL_INST_RATIO set to a low value, we want to touch the bitmap
so that the parent doesn't give up on us. */
if (afl_area_ptr == (void*)-1) exit(1); // 失败则退出
if (inst_r) afl_area_ptr[0] = 1;
/* With AFL_INST_RATIO set to a low value, we want to touch the bitmap //
so that the parent doesn't give up on us. */ // 当插桩比例设置为较低值时,访问位图防止父进程放弃我们
if (inst_r) afl_area_ptr[0] = 1; // 访问位图的第一个字节
}
if (getenv("AFL_INST_LIBS")) {
afl_start_code = 0;
afl_end_code = (abi_ulong)-1;
if (getenv("AFL_INST_LIBS")) { // 如果设置了AFL_INST_LIBS环境变量
afl_start_code = 0; // 设置代码段起始位置
afl_end_code = (abi_ulong)-1; // 设置代码段结束位置
}
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm
not entirely sure what is the cause. This disables that
behaviour, and seems to work alright? */
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm //
not entirely sure what is the cause. This disables that //
behaviour, and seems to work alright? */ // pthread_atfork()在util/rcu.c中似乎存在问题这禁用此行为并且有效
rcu_disable_atfork();
rcu_disable_atfork(); // 禁用atfork功能
}
/* Fork server logic, invoked once we hit _start. */
static void afl_forkserver(CPUState *cpu) {
static unsigned char tmp[4];
static void afl_forkserver(CPUState *cpu) { // fork服务器逻辑在_start时调用
if (!afl_area_ptr) return;
static unsigned char tmp[4]; // 临时缓冲区
/* Tell the parent that we're alive. If the parent doesn't want
to talk, assume that we're not running in forkserver mode. */
if (!afl_area_ptr) return; // 如果指针为空则返回
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
/* Tell the parent that we're alive. If the parent doesn't want //
to talk, assume that we're not running in forkserver mode. */ // 告诉父进程我们已经活着如果父进程不响应则认为不在fork服务器模式
afl_forksrv_pid = getpid();
if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; // 写入父进程
/* All right, let's await orders... */
afl_forksrv_pid = getpid(); // 获取当前进程ID
while (1) {
/* All right, let's await orders... */ // 好的,让我们等待命令…
pid_t child_pid;
int status, t_fd[2];
while (1) { // 进入无限循环
/* Whoops, parent dead? */
pid_t child_pid; // 子进程ID
int status, t_fd[2]; // 状态和文件描述符数组
if (read(FORKSRV_FD, tmp, 4) != 4) exit(2);
/* Whoops, parent dead? */ // 哎呀,父进程死了?
/* Establish a channel with child to grab translation commands. We'll
read from t_fd[0], child will write to TSL_FD. */
if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); // 读取父进程信息失败则退出
if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3);
close(t_fd[1]);
/* Establish a channel with child to grab translation commands. We'll //
read from t_fd[0], child will write to TSL_FD. */ // 建立与子进程的通道获取翻译命令。我们从t_fd[0]读取子进程写入TSL_FD。
child_pid = fork();
if (child_pid < 0) exit(4);
if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); // 创建管道,复制描述符
close(t_fd[1]); // 关闭写入端
if (!child_pid) {
child_pid = fork(); // 创建子进程
if (child_pid < 0) exit(4); // 创建失败则退出
/* Child process. Close descriptors and run free. */
if (!child_pid) { // 如果是子进程
afl_fork_child = 1;
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
close(t_fd[0]);
return;
/* Child process. Close descriptors and run free. */ // 子进程。关闭描述符,进入自由运行。
afl_fork_child = 1; // 标记为子进程
close(FORKSRV_FD); // 关闭fork服务器文件描述符
close(FORKSRV_FD + 1); // 关闭fork服务器文件描述符的另一个副本
close(t_fd[0]); // 关闭读取端
return; // 返回
}
/* Parent. */
/* Parent. */ // 父进程。
close(TSL_FD);
close(TSL_FD); // 关闭TSL文件描述符
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5);
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5); // 向父进程写入子进程ID失败则退出。
/* Collect translation requests until child dies and closes the pipe. */
/* Collect translation requests until child dies and closes the pipe. */ // 收集翻译请求,直到子进程结束并关闭管道。
afl_wait_tsl(cpu, t_fd[0]);
afl_wait_tsl(cpu, t_fd[0]); // 等待翻译请求
/* Get and relay exit status to parent. */
/* Get and relay exit status to parent. */ // 获取子进程退出状态并传递给父进程。
if (waitpid(child_pid, &status, 0) < 0) exit(6);
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7);
if (waitpid(child_pid, &status, 0) < 0) exit(6); // 等待子进程结束,失败则退出
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); // 向父进程写入状态,失败则退出
}
}
/* The equivalent of the tuple logging routine from afl-as.h. */
static inline void afl_maybe_log(abi_ulong cur_loc) {
static inline void afl_maybe_log(abi_ulong cur_loc) { // 记录当前地址的内联函数
static __thread abi_ulong prev_loc;
static __thread abi_ulong prev_loc; // 上一个地址
/* Optimize for cur_loc > afl_end_code, which is the most likely case on
Linux systems. */
/* Optimize for cur_loc > afl_end_code, which is the most likely case on //
Linux systems. */ // 优化条件常见于Linux系统
if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr)
return;
if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) // 如果当前地址不在有效范围
return; // 返回
/* Looks like QEMU always maps to fixed locations, so ASAN is not a
concern. Phew. But instruction addresses may be aligned. Let's mangle
the value to get something quasi-uniform. */
/* Looks like QEMU always maps to fixed locations, so ASAN is not a //
concern. Phew. But instruction addresses may be aligned. Let's mangle //
the value to get something quasi-uniform. */ // QEMU似乎总是映射到固定位置因此不需要担心ASAN。但指令地址可能会对齐。通过一些操作来获取统一值。
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
cur_loc &= MAP_SIZE - 1;
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); // 按位操作获取新值
cur_loc &= MAP_SIZE - 1; // 避免越界
/* Implement probabilistic instrumentation by looking at scrambled block
address. This keeps the instrumented locations stable across runs. */
/* Implement probabilistic instrumentation by looking at scrambled block //
address. This keeps the instrumented locations stable across runs. */ // 通过查看混乱的块地址实现概率性插桩,这样可以在多次运行中保持插桩位置的稳定性。
if (cur_loc >= afl_inst_rms) return;
if (cur_loc >= afl_inst_rms) return; // 如果当前地址超过插桩比率,返回
afl_area_ptr[cur_loc ^ prev_loc]++;
prev_loc = cur_loc >> 1;
afl_area_ptr[cur_loc ^ prev_loc]++; // 增加对应计数
prev_loc = cur_loc >> 1; // 更新上一个位置
}
/* This code is invoked whenever QEMU decides that it doesn't have a //
translation of a particular block and needs to compute it. When this happens, //
we tell the parent to mirror the operation, so that the next fork() has a //
cached copy. */ // 每当QEMU决定没有特定块的翻译并需要计算时会调用此代码。当发生这种情况时我们告诉父进程镜像操作以便下一个fork()具有缓存副本。
/* This code is invoked whenever QEMU decides that it doesn't have a
translation of a particular block and needs to compute it. When this happens,
we tell the parent to mirror the operation, so that the next fork() has a
cached copy. */
static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) {
static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) { // 请求翻译
struct afl_tsl t;
struct afl_tsl t; // 创建AFI_TSL结构体
if (!afl_fork_child) return;
if (!afl_fork_child) return; // 如果不是子进程,返回
t.pc = pc;
t.cs_base = cb;
t.flags = flags;
t.pc = pc; // 设置程序计数器
t.cs_base = cb; // 设置基址
t.flags = flags; // 设置标志
if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl))
return;
if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) // 写入数据请求
return; // 返回
}
/* This is the other side of the same channel. Since timeouts are handled by
afl-fuzz simply killing the child, we can just wait until the pipe breaks. */
/* This is the other side of the same channel. Since timeouts are handled by //
afl-fuzz simply killing the child, we can just wait until the pipe breaks. */ // 这是同一通道的另一侧。由于超时通过afl-fuzz简单地终止子进程来处理我们只需等待管道断开即可。
static void afl_wait_tsl(CPUState *cpu, int fd) {
static void afl_wait_tsl(CPUState *cpu, int fd) { // 等待翻译请求
struct afl_tsl t;
TranslationBlock *tb;
struct afl_tsl t; // 请求结构体
TranslationBlock *tb; // 翻译块
while (1) {
while (1) { // 无限循环
/* Broken pipe means it's time to return to the fork server routine. */
/* Broken pipe means it's time to return to the fork server routine. */ // 异常管道表示可以返回fork服务器例程
if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl))
break;
if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) // 读取请求数据
break; // 读取失败,退出循环
tb = tb_htable_lookup(cpu, t.pc, t.cs_base, t.flags);
tb = tb_htable_lookup(cpu, t.pc, t.cs_base, t.flags); // 查找翻译块
if(!tb) {
mmap_lock();
tb_lock();
tb_gen_code(cpu, t.pc, t.cs_base, t.flags, 0);
mmap_unlock();
tb_unlock();
if(!tb) { // 如果没有找到翻译块
mmap_lock(); // 锁定内存映射
tb_lock(); // 锁定翻译块
tb_gen_code(cpu, t.pc, t.cs_base, t.flags, 0); // 生成新的翻译块
mmap_unlock(); // 解锁内存映射
tb_unlock(); // 解锁翻译块
}
}
close(fd);
close(fd); // 关闭文件描述符
}

Loading…
Cancel
Save