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. of flags, and then calls the real compiler.
*/ */
#define AFL_MAIN #define AFL_MAIN // 定义宏AFL_MAIN
#include "../config.h" #include "../config.h" // 引入配置文件
#include "../types.h" #include "../types.h" // 引入类型定义文件
#include "../debug.h" #include "../debug.h" // 引入调试相关文件
#include "../alloc-inl.h" #include "../alloc-inl.h" // 引入内存分配相关的文件
#include <stdio.h> #include <stdio.h> // 引入标准输入输出库
#include <unistd.h> #include <unistd.h> // 引入UNIX标准库
#include <stdlib.h> #include <stdlib.h> // 引入标准库
#include <string.h> #include <string.h> // 引入字符串处理库
static u8* obj_path; /* Path to runtime libraries */ static u8* obj_path; /* 运行时库的路径 */
static u8** cc_params; /* Parameters passed to the real CC */ static u8** cc_params; /* 传递给真实编译器的参数 */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */ static u32 cc_par_cnt = 1; /* 参数计数初始包含argv0 */
/* Try to find the runtime libraries. If that fails, abort. */
/* 尝试查找运行时库。如果失败,则中止。 */
static void find_obj(u8* argv0) { static void find_obj(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH"); u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量AFL_PATH
u8 *slash, *tmp; 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)) { if (!access(tmp, R_OK)) { // 检查文件是否可读
obj_path = afl_path; obj_path = afl_path; // 设置运行时库路径
ck_free(tmp); ck_free(tmp); // 释放临时字符串
return; return;
} }
ck_free(tmp); ck_free(tmp); // 释放临时字符串
} }
slash = strrchr(argv0, '/'); slash = strrchr(argv0, '/'); // 查找路径中的最后一个斜杠
if (slash) { if (slash) { // 如果找到斜杠
u8 *dir; u8 *dir;
*slash = 0; *slash = 0; // 将斜杠替换为结束符
dir = ck_strdup(argv0); dir = ck_strdup(argv0); // 复制路径
*slash = '/'; *slash = '/'; // 恢复斜杠
tmp = alloc_printf("%s/afl-llvm-rt.o", dir); tmp = alloc_printf("%s/afl-llvm-rt.o", dir); // 格式化路径
if (!access(tmp, R_OK)) { if (!access(tmp, R_OK)) { // 检查文件是否可读
obj_path = dir; obj_path = dir; // 设置运行时库路径
ck_free(tmp); ck_free(tmp); // 释放临时字符串
return; return;
} }
ck_free(tmp); ck_free(tmp); // 释放临时字符串
ck_free(dir); ck_free(dir); // 释放目录字符串
} }
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { // 检查默认路径
obj_path = AFL_PATH; obj_path = AFL_PATH; // 设置运行时库路径
return; 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"); // 查找失败时提示错误
} }
/* 复制argv到cc_params并进行必要的编辑。 */
/* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char** argv) { static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0; u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0; // 初始化标志变量
u8 *name; u8 *name; // 当前文件名
cc_params = ck_alloc((argc + 128) * sizeof(u8*)); cc_params = ck_alloc((argc + 128) * sizeof(u8*)); // 分配参数数组内存
name = strrchr(argv[0], '/'); name = strrchr(argv[0], '/'); // 获取程序名
if (!name) name = argv[0]; else name++; if (!name) name = argv[0]; else name++; // 如果没有斜杠,则使用完整路径
// 根据程序名设置编译器
if (!strcmp(name, "afl-clang-fast++")) { if (!strcmp(name, "afl-clang-fast++")) {
u8* alt_cxx = getenv("AFL_CXX"); u8* alt_cxx = getenv("AFL_CXX"); // 获取环境变量AFL_CXX
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 设置C++编译器
} else { } else {
u8* alt_cc = getenv("AFL_CC"); u8* alt_cc = getenv("AFL_CC"); // 获取环境变量AFL_CC
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 设置C编译器
} }
/* There are two ways to compile afl-clang-fast. In the traditional mode, we /* 有两种编译afl-clang-fast的方式。传统模式下我们使用afl-llvm-pass.so注入插桩。
use afl-llvm-pass.so to inject instrumentation. In the experimental 'trace-pc-guard'使LLVM */
'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 */
#ifdef USE_TRACE_PC #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__ #ifndef __ANDROID__
cc_params[cc_par_cnt++] = "-mllvm"; cc_params[cc_par_cnt++] = "-mllvm"; // 添加LLVM的命令行标志
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设置阈值为0
#endif #endif
#else #else
cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-Xclang"; // 添加编译器的命令行标志
cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-load"; // 加载指定共享库
cc_params[cc_par_cnt++] = "-Xclang"; 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++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); // 添加动态库路径
#endif /* ^USE_TRACE_PC */ #endif /* ^USE_TRACE_PC */
cc_params[cc_par_cnt++] = "-Qunused-arguments"; cc_params[cc_par_cnt++] = "-Qunused-arguments"; // 添加未使用参数警告
// 处理命令行参数
while (--argc) { while (--argc) {
u8* cur = *(++argv); u8* cur = *(++argv); // 当前参数
if (!strcmp(cur, "-m32")) bit_mode = 32; if (!strcmp(cur, "-m32")) bit_mode = 32; // 检查32位模式
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; // ARM平台
if (!strcmp(cur, "-m64")) bit_mode = 64; 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") || if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1; !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") || if (!strcmp(cur, "-Wl,-z,defs") ||
!strcmp(cur, "-Wl,--no-undefined")) continue; !strcmp(cur, "-Wl,--no-undefined")) continue; // 跳过链接器选项
cc_params[cc_par_cnt++] = cur;
cc_params[cc_par_cnt++] = cur; // 添加当前参数到编译参数数组
} }
// 检查环境变量AFL_HARDEN
if (getenv("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) // 如果没有FORTIFY_SOURCE则添加相关标志
if (!fortify_set)
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
} }
// 检查Address Sanitizer和Memory Sanitizer的互斥
if (!asan_set) { if (!asan_set) {
if (getenv("AFL_USE_ASAN")) { // 如果启用Address Sanitizer
if (getenv("AFL_USE_ASAN")) {
if (getenv("AFL_USE_MSAN")) if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN和MSAN是互斥的"); // 互斥检查
if (getenv("AFL_HARDEN")) 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++] = "-U_FORTIFY_SOURCE"; // 添加标志
cc_params[cc_par_cnt++] = "-fsanitize=address"; 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")) if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN和MSAN是互斥的"); // 互斥检查
if (getenv("AFL_HARDEN")) 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++] = "-U_FORTIFY_SOURCE"; // 添加标志
cc_params[cc_par_cnt++] = "-fsanitize=memory"; 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 #ifdef USE_TRACE_PC
if (getenv("AFL_INST_RATIO")) 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 */ #endif /* USE_TRACE_PC */
if (!getenv("AFL_DONT_OPTIMIZE")) { if (!getenv("AFL_DONT_OPTIMIZE")) { // 如果没有设置不优化选项
cc_params[cc_par_cnt++] = "-g"; // 添加调试信息
cc_params[cc_par_cnt++] = "-g"; cc_params[cc_par_cnt++] = "-O3"; // 添加优化等级
cc_params[cc_par_cnt++] = "-O3"; cc_params[cc_par_cnt++] = "-funroll-loops"; // 启用循环展开
cc_params[cc_par_cnt++] = "-funroll-loops";
} }
if (getenv("AFL_NO_BUILTIN")) { if (getenv("AFL_NO_BUILTIN")) { // 检查是否使用内建函数
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; // 禁用strcmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; // 禁用strncmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; // 禁用strcasecmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; // 禁用strncasecmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; // 禁用memcmp内建
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
} }
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; 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++] = "-D__AFL_COMPILER=1"; // 添加编译器标志
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=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)).
2) We need to convince the linker, when called with -Wl,--gc-sections, /* 当用户尝试使用持久化或延迟fork服务器模式时
not to do the same. This is done by forcing an assignment to a .o
'volatile' pointer.
3) We need to declare __afl_persistent_loop() in the global namespace, 1) 使__attribute__((used))
but doing this within a method in a class is hard - :: and extern "C" 2) 使-Wl,--gc-sections
are forbidden and __attribute__((alias(...))) doesn't work. Hence the 'volatile'
__asm__ aliasing trick. 3) __afl_persistent_loop()
使__asm__
*/ */
@ -272,58 +254,55 @@ static void edit_params(u32 argc, char** argv) {
#endif /* ^__APPLE__ */ #endif /* ^__APPLE__ */
"_I(); } while (0)"; "_I(); } while (0)";
if (x_set) { if (x_set) { // 检查是否有-x标志
cc_params[cc_par_cnt++] = "-x"; cc_params[cc_par_cnt++] = "-x"; // 添加-x标志
cc_params[cc_par_cnt++] = "none"; cc_params[cc_par_cnt++] = "none"; // 设置参数
} }
#ifndef __ANDROID__ #ifndef __ANDROID__
switch (bit_mode) { switch (bit_mode) { // 根据位模式选择运行时库
case 0: 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; break;
case 32: 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)) if (access(cc_params[cc_par_cnt - 1], R_OK)) // 检查权限
FATAL("-m32 is not supported by your compiler"); FATAL("-m32不被你的编译器支持"); // 提示不支持
break; break;
case 64: 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)) if (access(cc_params[cc_par_cnt - 1], R_OK)) // 检查权限
FATAL("-m64 is not supported by your compiler"); FATAL("-m64不被你的编译器支持"); // 提示不支持
break; break;
} }
#endif #endif
cc_params[cc_par_cnt] = NULL; cc_params[cc_par_cnt] = NULL; // 结束参数数组
} }
/* 主入口点 */
/* Main entry point */
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) { if (isatty(2) && !getenv("AFL_QUIET")) { // 检查终端和环境变量
#ifdef USE_TRACE_PC #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 #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 */ #endif /* ^USE_TRACE_PC */
} }
if (argc < 2) { if (argc < 2) { // 检查参数数量
SAYF("\n" SAYF("\n"
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\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" "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" "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", "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__ #ifndef __ANDROID__
find_obj(argv[0]); find_obj(argv[0]); // 查找运行时库
#endif #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"); 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 not use this file except in compliance with the License. // 除非遵守许可证,否则不得使用此文件
You may obtain a copy of the License at: 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 Unless required by applicable law or agreed to in writing, software // 除非相关法律要求或书面协议,软件
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS, // 在“按原样”基础上分发
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // 不提供任何形式的明示或暗示的保证或条件
See the License for the specific language governing permissions and See the License for the specific language governing permissions and // 请参阅许可证以获取约束和限制的具体语言
limitations under the License. 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 Written by Andrew Griffiths <agriffiths@google.com> and // 由Andrew Griffiths和
Michal Zalewski <lcamtuf@google.com> 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 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 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 to implement AFL-style instrumentation and to take care of the remaining // 实现AFL风格的插桩并处理剩余
parts of the AFL fork server logic. parts of the AFL fork server logic. // AFL fork服务器逻辑的部分内容。
The resulting QEMU binary is essentially a standalone instrumentation The resulting QEMU binary is essentially a standalone instrumentation // 生成的QEMU二进制文件基本上是一个独立的插桩工具
tool; for an example of how to leverage it for other purposes, you can tool; for an example of how to leverage it for other purposes, you can // 用于其他目的的示例可以参考
have a look at afl-showmap.c. have a look at afl-showmap.c. // afl-showmap.c
*/ */
#include <sys/shm.h> #include <sys/shm.h> // 包含共享内存的头文件
#include "../../config.h" #include "../../config.h" // 包含项目配置的头文件
/*************************** /***************************
* VARIOUS AUXILIARY STUFF * * VARIOUS AUXILIARY STUFF *
***************************/ ***************************/
/* A snippet patched into tb_find_slow to inform the parent process that /* 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 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 it to translate within its own context, too (this avoids translation // 也在其自己的上下文中翻译(这避免了在下一个
overhead in the next forked-off copy). */ overhead in the next forked-off copy). // 被fork的副本中出现翻译开销
*/
#define AFL_QEMU_CPU_SNIPPET1 do { \ #define AFL_QEMU_CPU_SNIPPET1 do { \
afl_request_tsl(pc, cs_base, flags); \ afl_request_tsl(pc, cs_base, flags); \ // 调用afl_request_tsl函数传入参数
} while (0) } while (0) // 循环体
/* This snippet kicks in when the instruction pointer is positioned at /* This snippet kicks in when the instruction pointer is positioned at // 当指令指针位于_start位置时此代码段生效
_start and does the usual forkserver stuff, not very different from _start and does the usual forkserver stuff, not very different from // 并执行常规的forkserver逻辑与通过afl-as.h注入的逻辑没有太大区别
regular instrumentation injected via afl-as.h. */ regular instrumentation injected via afl-as.h. */
#define AFL_QEMU_CPU_SNIPPET2 do { \ #define AFL_QEMU_CPU_SNIPPET2 do { \
if(itb->pc == afl_entry_point) { \ if(itb->pc == afl_entry_point) { \ // 如果当前程序计数器等于入口点
afl_setup(); \ afl_setup(); \ // 设置插桩环境
afl_forkserver(cpu); \ afl_forkserver(cpu); \ // 启动fork服务器
} \ } \
afl_maybe_log(itb->pc); \ afl_maybe_log(itb->pc); \ // 可能记录当前地址
} while (0) } 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. */ 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: */ /* 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: */ /* Exported variables populated by the code patched into elfload.c: */
abi_ulong afl_entry_point, /* ELF entry point (_start) */ abi_ulong afl_entry_point, /* ELF entry point (_start) */ // ELF入口点
afl_start_code, /* .text start pointer */ afl_start_code, /* .text start pointer */ // .text段起始指针
afl_end_code; /* .text end pointer */ afl_end_code; /* .text end pointer */ // .text段结束指针
/* Set in the child process in forkserver mode: */ /* Set in the child process in forkserver mode: */
static unsigned char afl_fork_child; static unsigned char afl_fork_child; // 用于标记是否在fork子进程中
unsigned int afl_forksrv_pid; unsigned int afl_forksrv_pid; // fork服务器进程的PID
/* Instrumentation ratio: */ /* Instrumentation ratio: */
static unsigned int afl_inst_rms = MAP_SIZE; static unsigned int afl_inst_rms = MAP_SIZE; // 插桩比例
/* Function declarations. */ /* Function declarations. */
// 函数声明
static void afl_setup(void); static void afl_setup(void);
static void afl_forkserver(CPUState*); static void afl_forkserver(CPUState*);
static inline void afl_maybe_log(abi_ulong); 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: */ /* Data structure passed around by the translate handlers: */
struct afl_tsl { struct afl_tsl { // 传递给翻译处理程序的数据结构
target_ulong pc; target_ulong pc; // 当前程序计数器
target_ulong cs_base; target_ulong cs_base; // 段基址
uint64_t flags; uint64_t flags; // 标志
}; };
/* Some forward decls: */ /* Some forward decls: */
TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t); TranslationBlock *tb_htable_lookup(CPUState*, target_ulong, target_ulong, uint32_t); // 查找翻译块的函数
static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int); static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int); // 查找翻译块的内联函数
/************************* /*************************
* ACTUAL IMPLEMENTATION * * ACTUAL IMPLEMENTATION *
@ -113,201 +115,194 @@ static inline TranslationBlock *tb_find(CPUState*, TranslationBlock*, int);
/* Set up SHM region and initialize other stuff. */ /* 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), char *id_str = getenv(SHM_ENV_VAR), // 获取共享内存环境变量
*inst_r = getenv("AFL_INST_RATIO"); *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 > 100) r = 100; // 最大为100
if (!r) r = 1; if (!r) r = 1; // 如果为0则设置为1
afl_inst_rms = MAP_SIZE * r / 100; afl_inst_rms = MAP_SIZE * r / 100; // 计算实际插桩比例
} }
if (id_str) { if (id_str) { // 如果设定了共享内存ID
shm_id = atoi(id_str);
afl_area_ptr = shmat(shm_id, NULL, 0);
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 if (afl_area_ptr == (void*)-1) exit(1); // 失败则退出
so that the parent doesn't give up on us. */
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")) { if (getenv("AFL_INST_LIBS")) { // 如果设置了AFL_INST_LIBS环境变量
afl_start_code = 0; // 设置代码段起始位置
afl_start_code = 0; afl_end_code = (abi_ulong)-1; // 设置代码段结束位置
afl_end_code = (abi_ulong)-1;
} }
/* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm /* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm //
not entirely sure what is the cause. This disables that not entirely sure what is the cause. This disables that //
behaviour, and seems to work alright? */ 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. */ /* Fork server logic, invoked once we hit _start. */
static void afl_forkserver(CPUState *cpu) { static void afl_forkserver(CPUState *cpu) { // fork服务器逻辑在_start时调用
static unsigned char tmp[4];
if (!afl_area_ptr) return; static unsigned char tmp[4]; // 临时缓冲区
/* Tell the parent that we're alive. If the parent doesn't want if (!afl_area_ptr) return; // 如果指针为空则返回
to talk, assume that we're not running in forkserver mode. */
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; while (1) { // 进入无限循环
int status, t_fd[2];
/* 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 if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); // 读取父进程信息失败则退出
read from t_fd[0], child will write to TSL_FD. */
if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); /* Establish a channel with child to grab translation commands. We'll //
close(t_fd[1]); read from t_fd[0], child will write to TSL_FD. */ // 建立与子进程的通道获取翻译命令。我们从t_fd[0]读取子进程写入TSL_FD。
child_pid = fork(); if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); // 创建管道,复制描述符
if (child_pid < 0) exit(4); 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; /* Child process. Close descriptors and run free. */ // 子进程。关闭描述符,进入自由运行。
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
close(t_fd[0]);
return;
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 (waitpid(child_pid, &status, 0) < 0) exit(6); // 等待子进程结束,失败则退出
if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); // 向父进程写入状态,失败则退出
} }
} }
/* The equivalent of the tuple logging routine from afl-as.h. */ /* 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 /* Optimize for cur_loc > afl_end_code, which is the most likely case on //
Linux systems. */ Linux systems. */ // 优化条件常见于Linux系统
if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) // 如果当前地址不在有效范围
return; return; // 返回
/* Looks like QEMU always maps to fixed locations, so ASAN is not a /* Looks like QEMU always maps to fixed locations, so ASAN is not a //
concern. Phew. But instruction addresses may be aligned. Let's mangle concern. Phew. But instruction addresses may be aligned. Let's mangle //
the value to get something quasi-uniform. */ the value to get something quasi-uniform. */ // QEMU似乎总是映射到固定位置因此不需要担心ASAN。但指令地址可能会对齐。通过一些操作来获取统一值。
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); // 按位操作获取新值
cur_loc &= MAP_SIZE - 1; cur_loc &= MAP_SIZE - 1; // 避免越界
/* Implement probabilistic instrumentation by looking at scrambled block /* Implement probabilistic instrumentation by looking at scrambled block //
address. This keeps the instrumented locations stable across runs. */ 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]++; afl_area_ptr[cur_loc ^ prev_loc]++; // 增加对应计数
prev_loc = cur_loc >> 1; 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 static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) { // 请求翻译
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) {
struct afl_tsl t; struct afl_tsl t; // 创建AFI_TSL结构体
if (!afl_fork_child) return; if (!afl_fork_child) return; // 如果不是子进程,返回
t.pc = pc; t.pc = pc; // 设置程序计数器
t.cs_base = cb; t.cs_base = cb; // 设置基址
t.flags = flags; t.flags = flags; // 设置标志
if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) // 写入数据请求
return; return; // 返回
} }
/* This is the other side of the same channel. Since timeouts are handled by /* 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 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; struct afl_tsl t; // 请求结构体
TranslationBlock *tb; 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)) if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) // 读取请求数据
break; 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) { if(!tb) { // 如果没有找到翻译块
mmap_lock(); mmap_lock(); // 锁定内存映射
tb_lock(); tb_lock(); // 锁定翻译块
tb_gen_code(cpu, t.pc, t.cs_base, t.flags, 0); tb_gen_code(cpu, t.pc, t.cs_base, t.flags, 0); // 生成新的翻译块
mmap_unlock(); mmap_unlock(); // 解锁内存映射
tb_unlock(); tb_unlock(); // 解锁翻译块
} }
} }
close(fd); close(fd); // 关闭文件描述符
} }

Loading…
Cancel
Save