|
|
|
@ -28,209 +28,470 @@
|
|
|
|
|
of flags, and then calls the real compiler.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define AFL_MAIN // 定义宏AFL_MAIN
|
|
|
|
|
#define 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> // 引入UNIX标准库
|
|
|
|
|
#include <stdlib.h> // 引入标准库
|
|
|
|
|
#include <string.h> // 引入字符串处理库
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
static u8* obj_path; /* 运行时库的路径 */
|
|
|
|
|
static u8** cc_params; /* 传递给真实编译器的参数 */
|
|
|
|
|
static u32 cc_par_cnt = 1; /* 参数计数,初始包含argv0 */
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
|
|
/* 尝试查找运行时库。如果失败,则中止。 */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
尝试查找运行时库。如果失败,则中止程序。
|
|
|
|
|
*/
|
|
|
|
|
static void find_obj(u8* argv0) {
|
|
|
|
|
|
|
|
|
|
u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量AFL_PATH
|
|
|
|
|
u8 *afl_path = getenv("AFL_PATH"); // 获取环境变量 AFL_PATH 的值
|
|
|
|
|
u8 *slash, *tmp; // 定义用于存储路径分隔符和临时路径的变量
|
|
|
|
|
|
|
|
|
|
if (afl_path) { // 如果 AFL_PATH 环境变量存在
|
|
|
|
|
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); // 构造运行时库的路径
|
|
|
|
|
|
|
|
|
|
if (!access(tmp, R_OK)) { // 检查路径是否可读
|
|
|
|
|
obj_path = afl_path; // 如果可读,设置 obj_path 为 AFL_PATH
|
|
|
|
|
ck_free(tmp); // 释放临时路径的内存
|
|
|
|
|
return; // 返回,结束函数
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ck_free(tmp); // 如果路径不可读,释放临时路径的内存
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slash = strrchr(argv0, '/'); // 查找 argv0 中最后一个斜杠的位置
|
|
|
|
|
|
|
|
|
|
if (slash) { // 如果找到斜杠
|
|
|
|
|
u8 *dir; // 定义用于存储目录路径的变量
|
|
|
|
|
|
|
|
|
|
*slash = 0; // 将斜杠位置置为字符串结束符,以便提取目录路径
|
|
|
|
|
dir = ck_strdup(argv0); // 复制 argv0 的目录路径
|
|
|
|
|
*slash = '/'; // 恢复斜杠
|
|
|
|
|
|
|
|
|
|
tmp = alloc_printf("%s/afl-llvm-rt.o", dir); // 构造运行时库的路径
|
|
|
|
|
|
|
|
|
|
if (!access(tmp, R_OK)) { // 检查路径是否可读
|
|
|
|
|
obj_path = dir; // 如果可读,设置 obj_path 为当前目录
|
|
|
|
|
ck_free(tmp); // 释放临时路径的内存
|
|
|
|
|
return; // 返回,结束函数
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ck_free(tmp); // 如果路径不可读,释放临时路径的内存
|
|
|
|
|
ck_free(dir); // 释放目录路径的内存
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查默认的 AFL_PATH 目录下是否存在 'afl-llvm-rt.o' 文件
|
|
|
|
|
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
|
|
|
|
|
obj_path = AFL_PATH; // 如果存在,设置 obj_path 为 AFL_PATH
|
|
|
|
|
return; // 返回,结束函数
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果以上方法都未找到运行时库,抛出致命错误
|
|
|
|
|
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
复制 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; // 定义用于存储程序名的变量
|
|
|
|
|
|
|
|
|
|
// 为 cc_params 分配足够的内存,以容纳传入的参数加上额外的空间
|
|
|
|
|
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
|
|
|
|
|
|
|
|
|
|
// 提取程序名
|
|
|
|
|
name = strrchr(argv[0], '/'); // 查找 argv0 中最后一个斜杠的位置
|
|
|
|
|
if (!name) name = argv[0]; else name++; // 如果没有斜杠,使用完整的 argv[0]
|
|
|
|
|
|
|
|
|
|
// 根据程序名确定使用的编译器
|
|
|
|
|
if (!strcmp(name, "afl-clang-fast++")) { // 如果程序名是 afl-clang-fast++
|
|
|
|
|
u8* alt_cxx = getenv("AFL_CXX"); // 获取环境变量 AFL_CXX 的值
|
|
|
|
|
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 如果存在则使用其值,否则默认使用 clang++
|
|
|
|
|
} else { // 如果程序名不是 afl-clang-fast++
|
|
|
|
|
u8* alt_cc = getenv("AFL_CC"); // 获取环境变量 AFL_CC 的值
|
|
|
|
|
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 如果存在则使用其值,否则默认使用 clang
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef USE_TRACE_PC // 如果定义了 USE_TRACE_PC
|
|
|
|
|
// 添加用于 sanitization 的覆盖率参数
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; // 启用 trace-pc-guard 插桩
|
|
|
|
|
#ifndef __ANDROID__ // 如果不是 Android 平台
|
|
|
|
|
cc_params[cc_par_cnt++] = "-mllvm"; // 添加 LLVM 相关参数
|
|
|
|
|
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设置目标覆盖率的阈值为 0
|
|
|
|
|
#endif
|
|
|
|
|
#else // 如果没有定义 USE_TRACE_PC
|
|
|
|
|
// 添加 LLVM 插件的加载参数
|
|
|
|
|
cc_params[cc_par_cnt++] = "-Xclang"; // 添加 Clang 参数
|
|
|
|
|
cc_params[cc_par_cnt++] = "-load"; // 指定加载插件
|
|
|
|
|
cc_params[cc_par_cnt++] = "-Xclang"; // 添加 Clang 参数
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
|
|
|
|
|
// 追加 AFL 关键依赖项 afl-llvm-pass.so 到 cc_params,用于插桩分析
|
|
|
|
|
#endif /* ^USE_TRACE_PC */
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-Qunused-arguments";
|
|
|
|
|
// 添加一个参数,告诉编译器忽略未使用的命令行参数
|
|
|
|
|
|
|
|
|
|
while (--argc) { // 循环处理剩余的命令行参数
|
|
|
|
|
u8* cur = *(++argv); // 获取当前参数
|
|
|
|
|
|
|
|
|
|
if (!strcmp(cur, "-m32")) bit_mode = 32; // 如果参数是 -m32,设置 bit_mode 为 32
|
|
|
|
|
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; // 针对特定架构的设置
|
|
|
|
|
if (!strcmp(cur, "-m64")) bit_mode = 64; // 如果参数是 -m64,设置 bit_mode 为 64
|
|
|
|
|
|
|
|
|
|
if (!strcmp(cur, "-x")) x_set = 1; // 如果参数为 -x,设置 x_set 为 1,表示启用此选项
|
|
|
|
|
|
|
|
|
|
// 检查是否使用地址或内存的安全检测
|
|
|
|
|
if (!strcmp(cur, "-fsanitize=address") ||
|
|
|
|
|
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
|
|
|
|
|
|
|
|
|
|
// 检查是否启用了 FORTIFY_SOURCE
|
|
|
|
|
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
|
|
|
|
|
|
|
|
|
// 如果链接器选项是 -Wl,-z,defs 或 -Wl,--no-undefined,跳过该参数
|
|
|
|
|
if (!strcmp(cur, "-Wl,-z,defs") ||
|
|
|
|
|
!strcmp(cur, "-Wl,--no-undefined")) continue;
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = cur; // 将当前参数添加到 cc_params
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果环境变量 AFL_HARDEN 存在
|
|
|
|
|
if (getenv("AFL_HARDEN")) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fstack-protector-all"; // 启用所有堆栈保护
|
|
|
|
|
|
|
|
|
|
// 如果未启用 FORTIFY_SOURCE,添加定义以启用其功能
|
|
|
|
|
if (!fortify_set)
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果尚未启用 AddressSanitizer
|
|
|
|
|
if (!asan_set) {
|
|
|
|
|
// 检查是否设置了使用 AddressSanitizer 的环境变量
|
|
|
|
|
if (getenv("AFL_USE_ASAN")) {
|
|
|
|
|
// 检查 MSAN 和 ASAN 互斥
|
|
|
|
|
if (getenv("AFL_USE_MSAN"))
|
|
|
|
|
FATAL("ASAN and MSAN are mutually exclusive");
|
|
|
|
|
|
|
|
|
|
// 检查 AFL_HARDEN 是否与 ASAN 互斥
|
|
|
|
|
if (getenv("AFL_HARDEN"))
|
|
|
|
|
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 取消定义 FORTIFY_SOURCE
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用 AddressSanitizer
|
|
|
|
|
}
|
|
|
|
|
// 检查是否设置了使用 MemorySanitizer 的环境变量
|
|
|
|
|
else if (getenv("AFL_USE_MSAN")) {
|
|
|
|
|
// 检查 ASAN 和 MSAN 互斥
|
|
|
|
|
if (getenv("AFL_USE_ASAN"))
|
|
|
|
|
FATAL("ASAN and MSAN are mutually exclusive");
|
|
|
|
|
|
|
|
|
|
// 检查 AFL_HARDEN 是否与 MSAN 互斥
|
|
|
|
|
if (getenv("AFL_HARDEN"))
|
|
|
|
|
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 取消定义 FORTIFY_SOURCE
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用 MemorySanitizer
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果定义了 USE_TRACE_PC
|
|
|
|
|
#ifdef USE_TRACE_PC
|
|
|
|
|
// 检查 AFL_INST_RATIO 环境变量是否可用
|
|
|
|
|
if (getenv("AFL_INST_RATIO"))
|
|
|
|
|
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
|
|
|
|
|
#endif /* USE_TRACE_PC */
|
|
|
|
|
|
|
|
|
|
// 如果未设置 AFL_DONT_OPTIMIZE,则启用优化选项
|
|
|
|
|
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-g"; // 添加调试信息
|
|
|
|
|
cc_params[cc_par_cnt++] = "-O3"; // 启用高优化级别
|
|
|
|
|
cc_params[cc_par_cnt++] = "-funroll-loops"; // 启用循环展开
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果设置了 AFL_NO_BUILTIN,则禁用特定的内置函数
|
|
|
|
|
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 的内置实现
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加 AFL 控制宏,确保手动控制和编译器的定义
|
|
|
|
|
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"; // 表示为不安全的生产模式
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
当用户尝试通过在程序末尾添加单行来使用持久化或延迟的 forkserver 模式时,
|
|
|
|
|
我们想可靠地将签名注入二进制文件 (以便被 afl-fuzz 拿到)
|
|
|
|
|
并想调用运行时 .o 文件中的函数。由于以下三个原因,这非常复杂:
|
|
|
|
|
|
|
|
|
|
1) 我们需要说服编译器不要优化掉签名。
|
|
|
|
|
这是利用 __attribute__((used)) 实现的。
|
|
|
|
|
|
|
|
|
|
2) 我们需要说服链接器,在调用 -Wl,--gc-sections 时,
|
|
|
|
|
不要做同样的事情。 这是通过强制赋值给 'volatile' 指针来实现的。
|
|
|
|
|
|
|
|
|
|
3) 我们需要在全局命名空间中声明 __afl_persistent_loop(),
|
|
|
|
|
但在类的方法中做到这一点是困难的 - :: 和 extern "C"
|
|
|
|
|
是禁止的,且 __attribute__((alias(...))) 无效。因此使用了 __asm__ 别名技巧。
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 定义一个宏,用于处理 AFL 循环的持久化
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
|
|
|
|
|
// 开始一个代码块,其中静态的、易失的字符指针用于存放持久化的信号
|
|
|
|
|
"({ static volatile char *_B __attribute__((used)); "
|
|
|
|
|
" _B = (char*)\"" PERSIST_SIG "\"; "; // 将持久化信号字符串赋值给指针 _B
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__ // 根据系统平台选择合适的函数名称
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " // Apple 平台下的持久化函数
|
|
|
|
|
#else
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " // 其他平台下的持久化函数
|
|
|
|
|
#endif /* ^__APPLE__ */
|
|
|
|
|
"_L(_A); })"; // 调用持久化函数,并结束代码块
|
|
|
|
|
|
|
|
|
|
// 定义一个宏,用于初始化 AFL
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
|
|
|
|
|
"do { static volatile char *_A __attribute__((used)); "
|
|
|
|
|
" _A = (char*)\"" DEFER_SIG "\"; "; // 将延迟信号字符串赋值给指针 _A
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__ // 根据系统平台选择合适的初始化函数名称
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"void _I(void) __asm__(\"___afl_manual_init\"); " // Apple 平台下的初始化函数
|
|
|
|
|
#else
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"void _I(void) __asm__(\"__afl_manual_init\"); " // 其他平台下的初始化函数
|
|
|
|
|
#endif /* ^__APPLE__ */
|
|
|
|
|
"_I(); } while (0)"; // 调用初始化函数,并结束循环结构
|
|
|
|
|
|
|
|
|
|
// 如果 x_set 被设置,添加参数来指示关闭类型检查
|
|
|
|
|
if (x_set) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-x"; // 添加-x参数
|
|
|
|
|
cc_params[cc_par_cnt++] = "none"; // 指示后续没有特定类型
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果不是在 Android 平台下
|
|
|
|
|
#ifndef __ANDROID__
|
|
|
|
|
switch (bit_mode) { // 根据位数选择合适的运行时库
|
|
|
|
|
|
|
|
|
|
case 0: // 如果未设置位模式
|
|
|
|
|
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); // 使用默认的 afl-llvm-rt.o 路径
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 32: // 如果设置了 32 位模式
|
|
|
|
|
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"); // 抛出错误信息
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 64: // 如果设置了 64 位模式
|
|
|
|
|
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); // 使用 64 位运行时库路径
|
|
|
|
|
|
|
|
|
|
/* 查找运行时库的路径。如果找不到,则中止程序。 */
|
|
|
|
|
static void find_obj(u8* argv0) {
|
|
|
|
|
|
|
|
|
|
// 获取环境变量 AFL_PATH
|
|
|
|
|
u8 *afl_path = getenv("AFL_PATH");
|
|
|
|
|
u8 *slash, *tmp;
|
|
|
|
|
|
|
|
|
|
if (afl_path) { // 如果设置了AFL_PATH
|
|
|
|
|
// 如果找到 AFL_PATH
|
|
|
|
|
if (afl_path) {
|
|
|
|
|
|
|
|
|
|
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); // 格式化路径
|
|
|
|
|
// 生成 afl-llvm-rt.o 的完整路径
|
|
|
|
|
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path);
|
|
|
|
|
|
|
|
|
|
if (!access(tmp, R_OK)) { // 检查文件是否可读
|
|
|
|
|
obj_path = afl_path; // 设置运行时库路径
|
|
|
|
|
ck_free(tmp); // 释放临时字符串
|
|
|
|
|
return;
|
|
|
|
|
// 检查文件是否可读
|
|
|
|
|
if (!access(tmp, R_OK)) {
|
|
|
|
|
obj_path = afl_path; // 设置对象路径为 AFL_PATH
|
|
|
|
|
ck_free(tmp); // 释放临时路径内存
|
|
|
|
|
return; // 找到文件,结束函数
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ck_free(tmp); // 释放临时字符串
|
|
|
|
|
ck_free(tmp); // 释放临时路径内存
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slash = strrchr(argv0, '/'); // 查找路径中的最后一个斜杠
|
|
|
|
|
// 查找 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); // 格式化路径
|
|
|
|
|
// 生成 afl-llvm-rt.o 的完整路径
|
|
|
|
|
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
|
|
|
|
|
|
|
|
|
|
if (!access(tmp, R_OK)) { // 检查文件是否可读
|
|
|
|
|
obj_path = dir; // 设置运行时库路径
|
|
|
|
|
ck_free(tmp); // 释放临时字符串
|
|
|
|
|
return;
|
|
|
|
|
// 检查文件是否可读
|
|
|
|
|
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; // 设置运行时库路径
|
|
|
|
|
return;
|
|
|
|
|
// 检查默认路径下的 afl-llvm-rt.o 是否可读
|
|
|
|
|
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) {
|
|
|
|
|
obj_path = AFL_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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 复制argv到cc_params,并进行必要的编辑。 */
|
|
|
|
|
|
|
|
|
|
/* 复制 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"); // 获取环境变量AFL_CXX
|
|
|
|
|
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; // 设置C++编译器
|
|
|
|
|
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"); // 获取环境变量AFL_CC
|
|
|
|
|
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 设置C编译器
|
|
|
|
|
u8* alt_cc = getenv("AFL_CC"); // 获取环境变量 AFL_CC
|
|
|
|
|
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; // 设置 C 编译器
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 有两种编译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"; // 添加Trace PC Guard标志
|
|
|
|
|
// 启用跟踪 PC 的覆盖率
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
|
|
|
|
|
#ifndef __ANDROID__
|
|
|
|
|
cc_params[cc_par_cnt++] = "-mllvm"; // 添加LLVM的命令行标志
|
|
|
|
|
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0"; // 设置阈值为0
|
|
|
|
|
cc_params[cc_par_cnt++] = "-mllvm"; // LLVM 选项
|
|
|
|
|
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=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); // 添加动态库路径
|
|
|
|
|
// 加载 afl-llvm-pass.so 插件
|
|
|
|
|
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; // 检查32位模式
|
|
|
|
|
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; // ARM平台
|
|
|
|
|
if (!strcmp(cur, "-m64")) bit_mode = 64; // 检查64位模式
|
|
|
|
|
// 检查位模式
|
|
|
|
|
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, "-x")) x_set = 1; // 检查-x标志
|
|
|
|
|
// 检查其他编译选项
|
|
|
|
|
if (!strcmp(cur, "-x")) x_set = 1;
|
|
|
|
|
|
|
|
|
|
// 检查Address Sanitizer
|
|
|
|
|
// 检查是否启用地址/内存的 sanitization
|
|
|
|
|
if (!strcmp(cur, "-fsanitize=address") ||
|
|
|
|
|
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
|
|
|
|
|
|
|
|
|
|
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; // 检查FORTIFY_SOURCE
|
|
|
|
|
// 检查 FORTIFY_SOURCE 是否启用
|
|
|
|
|
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
|
|
|
|
|
|
|
|
|
|
// 跳过某些链接器选项
|
|
|
|
|
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_params[cc_par_cnt++] = cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查环境变量AFL_HARDEN
|
|
|
|
|
// 如果启用了硬化选项
|
|
|
|
|
if (getenv("AFL_HARDEN")) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fstack-protector-all"; // 启用栈保护
|
|
|
|
|
|
|
|
|
|
if (!fortify_set) // 如果没有FORTIFY_SOURCE,则添加相关标志
|
|
|
|
|
// 如果没有启用 FORTIFY_SOURCE 则添加对应宏定义
|
|
|
|
|
if (!fortify_set)
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查Address Sanitizer和Memory Sanitizer的互斥
|
|
|
|
|
// 检查地址或内存 sanitization 的设置
|
|
|
|
|
if (!asan_set) {
|
|
|
|
|
if (getenv("AFL_USE_ASAN")) { // 如果启用Address Sanitizer
|
|
|
|
|
|
|
|
|
|
if (getenv("AFL_USE_ASAN")) {
|
|
|
|
|
if (getenv("AFL_USE_MSAN"))
|
|
|
|
|
FATAL("ASAN和MSAN是互斥的"); // 互斥检查
|
|
|
|
|
|
|
|
|
|
FATAL("ASAN and MSAN are mutually exclusive"); // 互斥检查
|
|
|
|
|
if (getenv("AFL_HARDEN"))
|
|
|
|
|
FATAL("ASAN和AFL_HARDEN是互斥的"); // 互斥检查
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 添加标志
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用Address Sanitizer
|
|
|
|
|
|
|
|
|
|
} else if (getenv("AFL_USE_MSAN")) { // 如果启用Memory Sanitizer
|
|
|
|
|
|
|
|
|
|
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); // 互斥检查
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 禁用 FORTIFY_SOURCE
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=address"; // 启用地址条件检测
|
|
|
|
|
} else if (getenv("AFL_USE_MSAN")) {
|
|
|
|
|
if (getenv("AFL_USE_ASAN"))
|
|
|
|
|
FATAL("ASAN和MSAN是互斥的"); // 互斥检查
|
|
|
|
|
|
|
|
|
|
FATAL("ASAN and MSAN are mutually exclusive"); // 互斥检查
|
|
|
|
|
if (getenv("AFL_HARDEN"))
|
|
|
|
|
FATAL("MSAN和AFL_HARDEN是互斥的"); // 互斥检查
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 添加标志
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用Memory Sanitizer
|
|
|
|
|
|
|
|
|
|
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); // 互斥检查
|
|
|
|
|
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE"; // 禁用 FORTIFY_SOURCE
|
|
|
|
|
cc_params[cc_par_cnt++] = "-fsanitize=memory"; // 启用内存条件检测
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef USE_TRACE_PC
|
|
|
|
|
|
|
|
|
|
// 检查 AFL_INST_RATIO 环境变量的设置
|
|
|
|
|
if (getenv("AFL_INST_RATIO"))
|
|
|
|
|
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"; // 启用循环展开
|
|
|
|
|
}
|
|
|
|
|
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");
|
|
|
|
|
|
|
|
|
|
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"; // 添加不安全模式标志
|
|
|
|
|
#endif /* USE_TRACE_PC */
|
|
|
|
|
|
|
|
|
|
/* 当用户尝试使用持久化或延迟fork服务器模式时,
|
|
|
|
|
我们需要在二进制文件中注入一个签名,并调用运行时.o文件中的函数。
|
|
|
|
|
这有三个原因:
|
|
|
|
|
// 检查是否不优化
|
|
|
|
|
if (!getenv("AFL_DONT_OPTIMIZE")) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-g"; // 启用调试信息
|
|
|
|
|
cc_params[cc_par_cnt++] = "-O3"; // 启用最高级别的优化
|
|
|
|
|
cc_params[cc_par_cnt++] = "-funroll-loops"; // 循环展开以提高性能
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
1) 我们需要说服编译器不要优化掉签名。使用__attribute__((used))实现。
|
|
|
|
|
2) 我们需要说服链接器在使用-Wl,--gc-sections时不要做同样的事情。
|
|
|
|
|
通过强制赋值给'volatile'指针实现。
|
|
|
|
|
3) 我们需要在全局命名空间中声明__afl_persistent_loop(),但在类的方法中这样做很困难。
|
|
|
|
|
使用__asm__别名技巧来解决。
|
|
|
|
|
// 检查是否禁用内置函数的使用
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
// 添加 AFL 相关的宏定义
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; // 手动控制
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; // 标记为 AFL 编译器
|
|
|
|
|
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; // 不适合生产的模糊构建模式
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
|
|
|
|
|
// 添加 AFL 循环的实现
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
|
|
|
|
|
"({ static volatile char *_B __attribute__((used)); "
|
|
|
|
|
" _B = (char*)\"" PERSIST_SIG "\"; "
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
@ -240,9 +501,10 @@ static void edit_params(u32 argc, char** argv) {
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
|
|
|
|
|
#endif /* ^__APPLE__ */
|
|
|
|
|
"_L(_A); })";
|
|
|
|
|
"_L(_A); })"; // 定义 AFL 循环的宏
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
|
|
|
|
|
// 添加 AFL 初始化函数的实现
|
|
|
|
|
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
|
|
|
|
|
"do { static volatile char *_A __attribute__((used)); "
|
|
|
|
|
" _A = (char*)\"" DEFER_SIG "\"; "
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
@ -252,57 +514,59 @@ static void edit_params(u32 argc, char** argv) {
|
|
|
|
|
"__attribute__((visibility(\"default\"))) "
|
|
|
|
|
"void _I(void) __asm__(\"__afl_manual_init\"); "
|
|
|
|
|
#endif /* ^__APPLE__ */
|
|
|
|
|
"_I(); } while (0)";
|
|
|
|
|
"_I(); } while (0)"; // 定义 AFL 初始化的宏
|
|
|
|
|
|
|
|
|
|
if (x_set) { // 检查是否有-x标志
|
|
|
|
|
cc_params[cc_par_cnt++] = "-x"; // 添加-x标志
|
|
|
|
|
cc_params[cc_par_cnt++] = "none"; // 设置参数
|
|
|
|
|
}
|
|
|
|
|
// 如果启用 -x 选项
|
|
|
|
|
if (x_set) {
|
|
|
|
|
cc_params[cc_par_cnt++] = "-x"; // 添加 -x 选项
|
|
|
|
|
cc_params[cc_par_cnt++] = "none"; // 设置为 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); // 添加默认路径
|
|
|
|
|
break;
|
|
|
|
|
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); // 32位库路径
|
|
|
|
|
|
|
|
|
|
if (access(cc_params[cc_par_cnt - 1], R_OK)) // 检查权限
|
|
|
|
|
FATAL("-m32不被你的编译器支持"); // 提示不支持
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
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"); // 如果不可读则报错
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
|
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不被你的编译器支持"); // 提示不支持
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
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"); // 如果不可读则报错
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
// 结束参数数组,以空指针结尾
|
|
|
|
|
cc_params[cc_par_cnt] = NULL;
|
|
|
|
|
|
|
|
|
|
cc_params[cc_par_cnt] = NULL; // 结束参数数组
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 主入口点 */
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
if (isatty(2) && !getenv("AFL_QUIET")) { // 检查终端和环境变量
|
|
|
|
|
// 检查标准错误是否连接到终端且 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"); // 输出版本信息
|
|
|
|
|
// 如果启用了 USE_TRACE_PC,打印版本信息
|
|
|
|
|
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) { // 检查参数数量
|
|
|
|
|
// 如果参数数量小于 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"
|
|
|
|
@ -316,22 +580,25 @@ 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); // 退出程序,返回错误码 1
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef __ANDROID__
|
|
|
|
|
find_obj(argv[0]); // 查找运行时库
|
|
|
|
|
// 在非 Android 平台下调用 find_obj 函数查找运行时库
|
|
|
|
|
find_obj(argv[0]);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
edit_params(argc, argv); // 编辑参数
|
|
|
|
|
|
|
|
|
|
execvp(cc_params[0], (char**)cc_params); // 执行真实编译器
|
|
|
|
|
// 调用 edit_params 函数处理命令行参数并设置编译参数
|
|
|
|
|
edit_params(argc, argv);
|
|
|
|
|
|
|
|
|
|
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); // 执行失败提示
|
|
|
|
|
// 使用 execvp 执行指定的编译器命令
|
|
|
|
|
execvp(cc_params[0], (char**)cc_params);
|
|
|
|
|
|
|
|
|
|
return 0; // 返回0表示成功
|
|
|
|
|
// 如果 execvp 失败,抛出致命错误并打印相关信息
|
|
|
|
|
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
|
|
|
|
|
|
|
|
|
|
return 0; // 正常结束程序
|
|
|
|
|
}
|
|
|
|
|