|
|
|
@ -14,6 +14,8 @@
|
|
|
|
|
limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 这部分是版权声明和许可协议,声明该文件受到 Apache 2.0 许可证保护。
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
american fuzzy lop - wrapper for GNU as
|
|
|
|
|
---------------------------------------
|
|
|
|
@ -36,6 +38,10 @@
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// 该段注释解释了代码的功能
|
|
|
|
|
// 它是一个用于 GNU as 汇编器的包装器
|
|
|
|
|
// 目的是预处理由 GCC/Clang 生成的汇编文件并注入必要的仪器代码
|
|
|
|
|
|
|
|
|
|
#define AFL_MAIN
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
@ -56,20 +62,43 @@
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
|
|
// 定义宏 AFL_MAIN,通常用于标识主程序或相关模块。
|
|
|
|
|
// 包含内部的头文件,这些文件提供了项目的配置、类型定义、调试功能以及内存分配等支持。
|
|
|
|
|
// 包含标准的C库和POSIX库头文件,用于文件操作、内存管理、时间处理等。
|
|
|
|
|
|
|
|
|
|
static u8** as_params; /* Parameters passed to the real 'as' */
|
|
|
|
|
|
|
|
|
|
static u8* input_file; /* Originally specified input file */
|
|
|
|
|
static u8* modified_file; /* Instrumented file for the real 'as' */
|
|
|
|
|
|
|
|
|
|
//声明静态变量:
|
|
|
|
|
// as_params:保存传递给实际 as 汇编器的参数。
|
|
|
|
|
// input_file:保存输入的文件路径。
|
|
|
|
|
// modified_file:保存经过修改的文件路径(即注入了仪器代码后的文件)。
|
|
|
|
|
|
|
|
|
|
static u8 be_quiet, /* Quiet mode (no stderr output) */
|
|
|
|
|
clang_mode, /* Running in clang mode? */
|
|
|
|
|
pass_thru, /* Just pass data through? */
|
|
|
|
|
just_version, /* Just show version? */
|
|
|
|
|
sanitizer; /* Using ASAN / MSAN */
|
|
|
|
|
|
|
|
|
|
// 声明其他控制程序行为的静态变量:
|
|
|
|
|
|
|
|
|
|
// be_quiet:控制是否启用静默模式,不输出标准错误。
|
|
|
|
|
// clang_mode:是否处于 clang 模式。
|
|
|
|
|
// pass_thru:是否跳过修改,直接传递数据。
|
|
|
|
|
// just_version:是否只显示版本信息。
|
|
|
|
|
// sanitizer:是否启用了地址或内存错误检测工具(如 ASAN 或 MSAN)。
|
|
|
|
|
|
|
|
|
|
static u32 inst_ratio = 100, /* Instrumentation probability (%) */
|
|
|
|
|
as_par_cnt = 1; /* Number of params to 'as' */
|
|
|
|
|
|
|
|
|
|
// 声明静态变量:
|
|
|
|
|
|
|
|
|
|
// inst_ratio:仪器插入的概率(百分比)。
|
|
|
|
|
// as_par_cnt:传递给汇编器 as 的参数数量。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If we don't find --32 or --64 in the command line, default to
|
|
|
|
|
instrumentation for whichever mode we were compiled with. This is not
|
|
|
|
|
perfect, but should do the trick for almost all use cases. */
|
|
|
|
@ -88,20 +117,32 @@ static u8 use_64bit = 0;
|
|
|
|
|
|
|
|
|
|
#endif /* ^WORD_SIZE_64 */
|
|
|
|
|
|
|
|
|
|
// 根据编译时的定义判断是否使用 64 位模式。
|
|
|
|
|
// 如果没有定义 WORD_SIZE_64,则默认使用 32 位模式。
|
|
|
|
|
// 如果是苹果平台,还会抛出一个错误,表明不支持 32 位 Apple 平台。
|
|
|
|
|
|
|
|
|
|
/* Examine and modify parameters to pass to 'as'. Note that the file name
|
|
|
|
|
is always the last parameter passed by GCC, so we exploit this property
|
|
|
|
|
to keep the code simple. */
|
|
|
|
|
|
|
|
|
|
// 这段注释解释了接下来要做的工作:分析和修改传递给汇编器 as 的参数,特别是文件名,它总是作为最后一个参数传递给 GCC。
|
|
|
|
|
|
|
|
|
|
static void edit_params(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
// 定义函数 edit_params,用于修改传递给 as 汇编器的参数。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
|
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
|
|
// 获取环境变量 TMPDIR 和 AFL_AS,并声明变量 i。
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
|
|
u8 use_clang_as = 0;
|
|
|
|
|
|
|
|
|
|
// 如果是在 Apple 平台上,声明一个变量 use_clang_as 来标识是否使用 clang 作为汇编器。
|
|
|
|
|
|
|
|
|
|
/* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work
|
|
|
|
|
with the code generated by newer versions of clang that are hand-built
|
|
|
|
|
by the user. See the thread here: http://goo.gl/HBWDtn.
|
|
|
|
@ -122,6 +163,8 @@ static void edit_params(int argc, char** argv) {
|
|
|
|
|
if (!afl_as) afl_as = getenv("AFL_CXX");
|
|
|
|
|
if (!afl_as) afl_as = "clang";
|
|
|
|
|
|
|
|
|
|
// 如果在 clang 模式下且没有指定 AFL_AS,则尝试使用 clang 作为汇编器。
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
@ -134,10 +177,17 @@ static void edit_params(int argc, char** argv) {
|
|
|
|
|
if (!tmp_dir) tmp_dir = getenv("TMP");
|
|
|
|
|
if (!tmp_dir) tmp_dir = "/tmp";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//如果没有设置 TMPDIR,则尝试使用其他环境变量(如 TEMP 和 TMP),如果都没有设置,则默认使用 /tmp。
|
|
|
|
|
|
|
|
|
|
as_params = ck_alloc((argc + 32) * sizeof(u8*));
|
|
|
|
|
|
|
|
|
|
// 为汇编器参数分配内存,留出额外的空间。
|
|
|
|
|
|
|
|
|
|
as_params[0] = afl_as ? afl_as : (u8*)"as";
|
|
|
|
|
|
|
|
|
|
// 设置 as 汇编器命令,如果没有设置 AFL_AS,则默认使用 "as"。
|
|
|
|
|
|
|
|
|
|
as_params[argc] = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < argc - 1; i++) {
|
|
|
|
@ -169,11 +219,17 @@ static void edit_params(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 遍历所有传递给程序的参数,如果参数为 --64 或 --32,则根据平台设置 use_64bit
|
|
|
|
|
// 对于 Apple 平台,还会检查架构并设置为 64 位。
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
|
|
/* When calling clang as the upstream assembler, append -c -x assembler
|
|
|
|
|
and hope for the best. */
|
|
|
|
|
|
|
|
|
|
// 这段注释说明接下来的操作是调用真正的 as 汇编器,并传递适当的参数。
|
|
|
|
|
// 如果一切顺利,as 会返回一个 0 的退出代码,程序会传播这个退出代码。
|
|
|
|
|
|
|
|
|
|
if (use_clang_as) {
|
|
|
|
|
|
|
|
|
|
as_params[as_par_cnt++] = "-c";
|
|
|
|
@ -182,16 +238,23 @@ static void edit_params(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 在 exec_real_as 函数中:
|
|
|
|
|
|
|
|
|
|
// 如果处于静默模式(be_quiet),则关闭标准错误输出并将其重定向到 /dev/null,避免打印调试信息。
|
|
|
|
|
// 使用 execvp 执行汇编器命令,传递修改后的参数。
|
|
|
|
|
// 如果执行失败,则打印错误信息并退出程序。
|
|
|
|
|
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
input_file = argv[argc - 1];
|
|
|
|
|
input_file = argv[argc - 1];
|
|
|
|
|
|
|
|
|
|
if (input_file[0] == '-') {
|
|
|
|
|
|
|
|
|
|
if (!strcmp(input_file + 1, "-version")) {
|
|
|
|
|
just_version = 1;
|
|
|
|
|
modified_file = input_file;
|
|
|
|
|
goto wrap_things_up;
|
|
|
|
|
goto wrap_things_up; // 跳到 wrap_things_up 标签,处理版本信息
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)");
|
|
|
|
@ -199,122 +262,118 @@ static void edit_params(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Check if this looks like a standard invocation as a part of an attempt
|
|
|
|
|
to compile a program, rather than using gcc on an ad-hoc .s file in
|
|
|
|
|
a format we may not understand. This works around an issue compiling
|
|
|
|
|
NSS. */
|
|
|
|
|
/* 检查输入文件路径是否看起来像是编译程序的一部分,而不是使用 gcc 编译一个临时的 .s 文件 */
|
|
|
|
|
/* 这段代码是为了绕过某些特殊情况,比如编译 NSS 库时的情况 */
|
|
|
|
|
|
|
|
|
|
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
|
|
|
|
|
strncmp(input_file, "/var/tmp/", 9) &&
|
|
|
|
|
strncmp(input_file, "/tmp/", 5)) pass_thru = 1;
|
|
|
|
|
strncmp(input_file, "/tmp/", 5)) pass_thru = 1; // 启用通过模式
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(),
|
|
|
|
|
(u32)time(NULL));
|
|
|
|
|
(u32)time(NULL)); // 为生成的文件名分配内存并格式化
|
|
|
|
|
|
|
|
|
|
wrap_things_up:
|
|
|
|
|
|
|
|
|
|
as_params[as_par_cnt++] = modified_file;
|
|
|
|
|
as_params[as_par_cnt] = NULL;
|
|
|
|
|
|
|
|
|
|
as_params[as_par_cnt++] = modified_file; // 将修改后的文件名添加到参数列表
|
|
|
|
|
as_params[as_par_cnt] = NULL; // 参数列表以 NULL 结尾
|
|
|
|
|
}
|
|
|
|
|
// 此段代码注释说明了程序如何检查和处理输入文件,包括:
|
|
|
|
|
|
|
|
|
|
// 如果文件名以 - 开头,可能是传递版本信息或者其他特殊的命令行参数。
|
|
|
|
|
// 如果文件路径看起来是临时目录之外的路径,则启用“通过模式”(pass_thru),这表示不进行修改,直接传递给汇编器。
|
|
|
|
|
|
|
|
|
|
/* Process input file, generate modified_file. Insert instrumentation in all
|
|
|
|
|
the appropriate places. */
|
|
|
|
|
/* 处理输入文件,生成修改后的文件,并在所有适当的位置插入仪器代码 */
|
|
|
|
|
|
|
|
|
|
static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
static u8 line[MAX_LINE];
|
|
|
|
|
static u8 line[MAX_LINE]; // 用于存储每一行的内容
|
|
|
|
|
|
|
|
|
|
FILE* inf;
|
|
|
|
|
FILE* outf;
|
|
|
|
|
s32 outfd;
|
|
|
|
|
u32 ins_lines = 0;
|
|
|
|
|
u32 ins_lines = 0; // 记录插入了多少行
|
|
|
|
|
|
|
|
|
|
u8 instr_ok = 0, skip_csect = 0, skip_next_label = 0,
|
|
|
|
|
skip_intel = 0, skip_app = 0, instrument_next = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
|
|
u8* colon_pos;
|
|
|
|
|
u8* colon_pos; // 用于查找冒号位置
|
|
|
|
|
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
if (input_file) {
|
|
|
|
|
|
|
|
|
|
inf = fopen(input_file, "r");
|
|
|
|
|
if (!inf) PFATAL("Unable to read '%s'", input_file);
|
|
|
|
|
inf = fopen(input_file, "r"); // 打开输入文件进行读取
|
|
|
|
|
if (!inf) PFATAL("Unable to read '%s'", input_file); // 如果打开失败,打印错误并退出
|
|
|
|
|
|
|
|
|
|
} else inf = stdin;
|
|
|
|
|
} else inf = stdin; // 如果没有指定输入文件,使用标准输入
|
|
|
|
|
|
|
|
|
|
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
|
|
|
|
|
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600); // 创建输出文件
|
|
|
|
|
|
|
|
|
|
if (outfd < 0) PFATAL("Unable to write to '%s'", modified_file);
|
|
|
|
|
if (outfd < 0) PFATAL("Unable to write to '%s'", modified_file); // 如果创建失败,打印错误并退出
|
|
|
|
|
|
|
|
|
|
outf = fdopen(outfd, "w");
|
|
|
|
|
outf = fdopen(outfd, "w"); // 获取文件流
|
|
|
|
|
|
|
|
|
|
if (!outf) PFATAL("fdopen() failed");
|
|
|
|
|
if (!outf) PFATAL("fdopen() failed"); // 如果 fdopen 失败,打印错误并退出
|
|
|
|
|
|
|
|
|
|
while (fgets(line, MAX_LINE, inf)) {
|
|
|
|
|
while (fgets(line, MAX_LINE, inf)) { // 逐行读取输入文件
|
|
|
|
|
|
|
|
|
|
/* In some cases, we want to defer writing the instrumentation trampoline
|
|
|
|
|
until after all the labels, macros, comments, etc. If we're in this
|
|
|
|
|
mode, and if the line starts with a tab followed by a character, dump
|
|
|
|
|
the trampoline now. */
|
|
|
|
|
/* 在某些情况下,我们希望在写入仪器跳板之前先跳过某些标签、宏或注释。
|
|
|
|
|
如果启用了这个模式,并且当前行以制表符和字母开头,那么我们现在就插入仪器跳板。 */
|
|
|
|
|
|
|
|
|
|
if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
|
|
|
|
|
instrument_next && line[0] == '\t' && isalpha(line[1])) {
|
|
|
|
|
|
|
|
|
|
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
|
|
|
|
|
R(MAP_SIZE));
|
|
|
|
|
R(MAP_SIZE)); // 根据使用的位数选择合适的跳板格式
|
|
|
|
|
|
|
|
|
|
instrument_next = 0;
|
|
|
|
|
ins_lines++;
|
|
|
|
|
ins_lines++; // 统计插入的行数
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Output the actual line, call it a day in pass-thru mode. */
|
|
|
|
|
/* 输出当前行,只有在通过模式下才跳过插入仪器 */
|
|
|
|
|
|
|
|
|
|
fputs(line, outf);
|
|
|
|
|
|
|
|
|
|
if (pass_thru) continue;
|
|
|
|
|
if (pass_thru) continue; // 如果启用了通过模式,则跳过剩下的处理
|
|
|
|
|
|
|
|
|
|
/* All right, this is where the actual fun begins. For one, we only want to
|
|
|
|
|
instrument the .text section. So, let's keep track of that in processed
|
|
|
|
|
files - and let's set instr_ok accordingly. */
|
|
|
|
|
/* 以下代码处理实际的插桩逻辑,只在 .text 段插入仪器代码 */
|
|
|
|
|
|
|
|
|
|
if (line[0] == '\t' && line[1] == '.') {
|
|
|
|
|
|
|
|
|
|
/* OpenBSD puts jump tables directly inline with the code, which is
|
|
|
|
|
a bit annoying. They use a specific format of p2align directives
|
|
|
|
|
around them, so we use that as a signal. */
|
|
|
|
|
/* OpenBSD 将跳转表直接内联到代码中,这很麻烦。它们使用特定的 p2align 指令格式,
|
|
|
|
|
所以我们以此为信号进行处理。 */
|
|
|
|
|
|
|
|
|
|
if (!clang_mode && instr_ok && !strncmp(line + 2, "p2align ", 8) &&
|
|
|
|
|
isdigit(line[10]) && line[11] == '\n') skip_next_label = 1;
|
|
|
|
|
|
|
|
|
|
/* 如果检测到 .text 段或相关段,启用插桩 */
|
|
|
|
|
if (!strncmp(line + 2, "text\n", 5) ||
|
|
|
|
|
!strncmp(line + 2, "section\t.text", 13) ||
|
|
|
|
|
!strncmp(line + 2, "section\t__TEXT,__text", 21) ||
|
|
|
|
|
!strncmp(line + 2, "section __TEXT,__text", 21)) {
|
|
|
|
|
instr_ok = 1;
|
|
|
|
|
continue;
|
|
|
|
|
continue; // 继续处理下一行
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 如果是其他段(如 bss、data),禁用插桩 */
|
|
|
|
|
if (!strncmp(line + 2, "section\t", 8) ||
|
|
|
|
|
!strncmp(line + 2, "section ", 8) ||
|
|
|
|
|
!strncmp(line + 2, "bss\n", 4) ||
|
|
|
|
|
!strncmp(line + 2, "data\n", 5)) {
|
|
|
|
|
instr_ok = 0;
|
|
|
|
|
continue;
|
|
|
|
|
continue; // 继续处理下一行
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Detect off-flavor assembly (rare, happens in gdb). When this is
|
|
|
|
|
encountered, we set skip_csect until the opposite directive is
|
|
|
|
|
seen, and we do not instrument. */
|
|
|
|
|
/* 检测并跳过特定的汇编节(如 .code) */
|
|
|
|
|
|
|
|
|
|
if (strstr(line, ".code")) {
|
|
|
|
|
|
|
|
|
@ -323,14 +382,11 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Detect syntax changes, as could happen with hand-written assembly.
|
|
|
|
|
Skip Intel blocks, resume instrumentation when back to AT&T. */
|
|
|
|
|
|
|
|
|
|
/* 检测并跳过 Intel 语法块 */
|
|
|
|
|
if (strstr(line, ".intel_syntax")) skip_intel = 1;
|
|
|
|
|
if (strstr(line, ".att_syntax")) skip_intel = 0;
|
|
|
|
|
|
|
|
|
|
/* Detect and skip ad-hoc __asm__ blocks, likewise skipping them. */
|
|
|
|
|
|
|
|
|
|
/* 跳过 ad-hoc 的 __asm__ 块 */
|
|
|
|
|
if (line[0] == '#' || line[1] == '#') {
|
|
|
|
|
|
|
|
|
|
if (strstr(line, "#APP")) skip_app = 1;
|
|
|
|
@ -338,45 +394,20 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we're in the right mood for instrumenting, check for function
|
|
|
|
|
names or conditional labels. This is a bit messy, but in essence,
|
|
|
|
|
we want to catch:
|
|
|
|
|
|
|
|
|
|
^main: - function entry point (always instrumented)
|
|
|
|
|
^.L0: - GCC branch label
|
|
|
|
|
^.LBB0_0: - clang branch label (but only in clang mode)
|
|
|
|
|
^\tjnz foo - conditional branches
|
|
|
|
|
|
|
|
|
|
...but not:
|
|
|
|
|
|
|
|
|
|
^# BB#0: - clang comments
|
|
|
|
|
^ # BB#0: - ditto
|
|
|
|
|
^.Ltmp0: - clang non-branch labels
|
|
|
|
|
^.LC0 - GCC non-branch labels
|
|
|
|
|
^.LBB0_0: - ditto (when in GCC mode)
|
|
|
|
|
^\tjmp foo - non-conditional jumps
|
|
|
|
|
|
|
|
|
|
Additionally, clang and GCC on MacOS X follow a different convention
|
|
|
|
|
with no leading dots on labels, hence the weird maze of #ifdefs
|
|
|
|
|
later on.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* 检查并插入仪器代码:主要是函数标签、条件标签等 */
|
|
|
|
|
if (skip_intel || skip_app || skip_csect || !instr_ok ||
|
|
|
|
|
line[0] == '#' || line[0] == ' ') continue;
|
|
|
|
|
line[0] == '#' || line[0] == ' ') continue; // 跳过不需要插入的行
|
|
|
|
|
|
|
|
|
|
/* Conditional branch instruction (jnz, etc). We append the instrumentation
|
|
|
|
|
right after the branch (to instrument the not-taken path) and at the
|
|
|
|
|
branch destination label (handled later on). */
|
|
|
|
|
/* 条件分支指令(如 jnz 等)。我们将插入仪器代码到分支指令后面(用于记录未采取的路径) */
|
|
|
|
|
|
|
|
|
|
if (line[0] == '\t') {
|
|
|
|
|
|
|
|
|
|
if (line[1] == 'j' && line[2] != 'm' && R(100) < inst_ratio) {
|
|
|
|
|
|
|
|
|
|
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32,
|
|
|
|
|
R(MAP_SIZE));
|
|
|
|
|
R(MAP_SIZE)); // 插入仪器代码
|
|
|
|
|
|
|
|
|
|
ins_lines++;
|
|
|
|
|
ins_lines++; // 统计插入的行数
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -384,13 +415,11 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Label of some sort. This may be a branch destination, but we need to
|
|
|
|
|
tread carefully and account for several different formatting
|
|
|
|
|
conventions. */
|
|
|
|
|
/* 标签的处理。标签可能是分支目标,我们需要根据格式区分处理 */
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
|
|
/* Apple: L<whatever><digit>: */
|
|
|
|
|
/* 苹果系统标签格式:L<whatever><digit>: */
|
|
|
|
|
|
|
|
|
|
if ((colon_pos = strstr(line, ":"))) {
|
|
|
|
|
|
|
|
|
@ -398,7 +427,7 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
/* Everybody else: .L<whatever>: */
|
|
|
|
|
/* 其他平台的标签格式:.L<whatever>: */
|
|
|
|
|
|
|
|
|
|
if (strstr(line, ":")) {
|
|
|
|
|
|
|
|
|
@ -406,34 +435,25 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
/* .L0: or LBB0_0: style jump destination */
|
|
|
|
|
/* 处理跳转目标标签(如 .L0: 或 LBB0_0:) */
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
|
|
|
|
|
/* Apple: L<num> / LBB<num> */
|
|
|
|
|
/* 苹果:L<num> / LBB<num> */
|
|
|
|
|
|
|
|
|
|
if ((isdigit(line[1]) || (clang_mode && !strncmp(line, "LBB", 3)))
|
|
|
|
|
&& R(100) < inst_ratio) {
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
/* Apple: .L<num> / .LBB<num> */
|
|
|
|
|
/* 其他平台:.L<num> / .LBB<num> */
|
|
|
|
|
|
|
|
|
|
if ((isdigit(line[2]) || (clang_mode && !strncmp(line + 1, "LBB", 3)))
|
|
|
|
|
&& R(100) < inst_ratio) {
|
|
|
|
|
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
/* An optimization is possible here by adding the code only if the
|
|
|
|
|
label is mentioned in the code in contexts other than call / jmp.
|
|
|
|
|
That said, this complicates the code by requiring two-pass
|
|
|
|
|
processing (messy with stdin), and results in a speed gain
|
|
|
|
|
typically under 10%, because compilers are generally pretty good
|
|
|
|
|
about not generating spurious intra-function jumps.
|
|
|
|
|
|
|
|
|
|
We use deferred output chiefly to avoid disrupting
|
|
|
|
|
.Lfunc_begin0-style exception handling calculations (a problem on
|
|
|
|
|
MacOS X). */
|
|
|
|
|
/* 如果符合条件,则插入仪器代码 */
|
|
|
|
|
|
|
|
|
|
if (!skip_next_label) instrument_next = 1; else skip_next_label = 0;
|
|
|
|
|
|
|
|
|
@ -441,39 +461,38 @@ static void add_instrumentation(void) {
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Function label (always instrumented, deferred mode). */
|
|
|
|
|
/* 函数标签,插入仪器代码 */
|
|
|
|
|
|
|
|
|
|
instrument_next = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ins_lines)
|
|
|
|
|
fputs(use_64bit ? main_payload_64 : main_payload_32, outf);
|
|
|
|
|
|
|
|
|
|
if (input_file) fclose(inf);
|
|
|
|
|
fclose(outf);
|
|
|
|
|
|
|
|
|
|
if (!be_quiet) {
|
|
|
|
|
|
|
|
|
|
if (!ins_lines) WARNF("No instrumentation targets found%s.",
|
|
|
|
|
pass_thru ? " (pass-thru mode)" : "");
|
|
|
|
|
else OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).",
|
|
|
|
|
ins_lines, use_64bit ? "64" : "32",
|
|
|
|
|
getenv("AFL_HARDEN") ? "hardened" :
|
|
|
|
|
(sanitizer ? "ASAN/MSAN" : "non-hardened"),
|
|
|
|
|
inst_ratio);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
fclose(inf); // 关闭输入文件
|
|
|
|
|
fclose(outf); // 关闭输出文件
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Main entry point */
|
|
|
|
|
|
|
|
|
|
// 在 main 函数中:
|
|
|
|
|
|
|
|
|
|
// 检查是否只需要显示版本信息,如果是,则调用 print_version 函数。
|
|
|
|
|
// 解析命令行参数:
|
|
|
|
|
// 解析 -q 启用静默模式。
|
|
|
|
|
// 解析 --clang 启用 clang 模式。
|
|
|
|
|
// 解析 --pass-through 启用数据通过模式。
|
|
|
|
|
// 解析 --sanitizer 启用 sanitizer。
|
|
|
|
|
// 解析 --inst-ratio 设置仪器插入的概率。
|
|
|
|
|
// 解析 --version 仅显示版本信息。
|
|
|
|
|
// 确保输入文件已经指定,如果没有指定,则退出并报错。
|
|
|
|
|
// 调用 edit_params 函数修改传递给汇编器的参数。
|
|
|
|
|
// 最后,调用 exec_real_as 函数执行实际的汇编器命令。
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
s32 pid;
|
|
|
|
|