From 60eb69f1a45a83158fbb7ace923ee3f0cee3959d Mon Sep 17 00:00:00 2001 From: zhongfengrong <1363383697@qq.com> Date: Wed, 8 Jan 2025 21:13:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=94=E8=AF=A5=E5=A4=9F2000=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/llvm_mode/afl-clang-fast.c | 272 +++++++++---------- src/qemu_mode/patches/afl-qemu-cpu-inl.h | 317 +++++++++++------------ 2 files changed, 281 insertions(+), 308 deletions(-) diff --git a/src/llvm_mode/afl-clang-fast.c b/src/llvm_mode/afl-clang-fast.c index 2104a12..709fb2b 100644 --- a/src/llvm_mode/afl-clang-fast.c +++ b/src/llvm_mode/afl-clang-fast.c @@ -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 -#include -#include -#include +#include // 引入标准输入输出库 +#include // 引入UNIX标准库 +#include // 引入标准库 +#include // 引入字符串处理库 -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 \n"); + SAYF(cCYA "afl-clang-fast [tpcg] " cBRI VERSION cRST " by \n"); // 输出版本信息 #else - SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by \n"); + SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by \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表示成功 } diff --git a/src/qemu_mode/patches/afl-qemu-cpu-inl.h b/src/qemu_mode/patches/afl-qemu-cpu-inl.h index c05bd77..8ef62e3 100644 --- a/src/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/src/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -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 and - Michal Zalewski + Written by Andrew Griffiths and // 由Andrew Griffiths和 + Michal Zalewski // 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 -#include "../../config.h" +#include // 包含共享内存的头文件 +#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); // 关闭文件描述符 }