“18670363079” 2 months ago
parent 3a57a58e66
commit 3bf32e4de2

@ -113,6 +113,7 @@ static u8 count_class_lookup[256] = {
};
//对内存中的元组计数进行分类。如果edges_only标志被设置则只标记边界情况否则使用count_class_lookup数组对每个字节的计数进行分类
static void classify_counts(u8* mem) {
u32 i = MAP_SIZE;
@ -137,7 +138,7 @@ static void classify_counts(u8* mem) {
/* See if any bytes are set in the bitmap. */
//检查在追踪位图中是否有任何字节被设置。如果有则返回1表示有变化如果没有则返回0。
static inline u8 anything_set(void) {
u32* ptr = (u32*)trace_bits;
@ -151,7 +152,7 @@ static inline u8 anything_set(void) {
/* Get rid of shared memory and temp files (atexit handler). */
//用于在程序退出时清理共享内存和临时文件。它会尝试删除程序输入文件并调用shmctl来删除共享内存标识符
static void remove_shm(void) {
unlink(prog_in); /* Ignore errors */
@ -161,7 +162,7 @@ static void remove_shm(void) {
/* Configure shared memory. */
//配置共享内存。创建一个共享内存段并将其ID设置到环境变量中以便子进程可以使用。同时将trace_bits指向共享内存的起始地址
static void setup_shm(void) {
u8* shm_str;
@ -186,7 +187,7 @@ static void setup_shm(void) {
/* Read initial file. */
//读取要分析的初始文件并将其内容存储在in_data中。同时记录文件的长度并检查文件大小是否在允许的范围内
static void read_initial_file(void) {
struct stat st;
@ -213,7 +214,7 @@ static void read_initial_file(void) {
/* Write output file. */
//将内存中的数据写入到指定的文件路径。如果文件已存在,则先删除。然后创建新文件,并将数据写入
static s32 write_to_file(u8* path, u8* mem, u32 len) {
s32 ret;
@ -234,7 +235,7 @@ static s32 write_to_file(u8* path, u8* mem, u32 len) {
/* Handle timeout signal. */
//处理超时信号。设置child_timed_out标志并尝试杀死子进程
static void handle_timeout(int sig) {
child_timed_out = 1;
@ -245,7 +246,7 @@ static void handle_timeout(int sig) {
/* Execute target application. Returns exec checksum, or 0 if program
times out. */
//执行目标程序并返回执行的校验和或者如果程序超时则返回0。这个函数负责设置环境执行程序并分析退出条件
static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
static struct itimerval it;
@ -370,7 +371,7 @@ static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
#ifdef USE_COLOR
/* Helper function to display a human-readable character. */
//显示一个可读的字符。如果字符是控制字符或非打印字符,则显示其十六进制代码
static void show_char(u8 val) {
switch (val) {
@ -386,7 +387,7 @@ static void show_char(u8 val) {
/* Show the legend */
//显示图例,解释不同颜色和标记的含义
static void show_legend(void) {
SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block "
@ -403,7 +404,7 @@ static void show_legend(void) {
/* Interpret and report a pattern in the input file. */
//解释并报告输入文件中的模式。它分析文件中的每个字节,并根据其对程序执行路径的影响对其进行分类
static void dump_hex(u8* buf, u32 len, u8* b_data) {
u32 i;
@ -558,7 +559,7 @@ static void dump_hex(u8* buf, u32 len, u8* b_data) {
/* Actually analyze! */
//实际执行分析。它通过改变输入文件中的字节并观察对执行路径的影响来推断文件格式的结构
static void analyze(char** argv) {
u32 i;
@ -652,7 +653,7 @@ static void analyze(char** argv) {
/* Handle Ctrl-C and the like. */
//处理停止信号如Ctrl-C。设置stop_soon标志并尝试杀死子进程
static void handle_stop_sig(int sig) {
stop_soon = 1;
@ -663,7 +664,7 @@ static void handle_stop_sig(int sig) {
/* Do basic preparations - persistent fds, filenames, etc. */
//进行基本的准备工作,包括设置持久的文件描述符、文件名等,并配置环境变量
static void set_up_environment(void) {
u8* x;
@ -733,7 +734,7 @@ static void set_up_environment(void) {
/* Setup signal handlers, duh. */
//设置信号处理程序,以便处理停止和超时信号
static void setup_signal_handlers(void) {
struct sigaction sa;
@ -760,7 +761,7 @@ static void setup_signal_handlers(void) {
/* Detect @@ in args. */
//检测@@在参数中的位置,并替换为实际的文件路径
static void detect_file_args(char** argv) {
u32 i = 0;
@ -802,7 +803,7 @@ static void detect_file_args(char** argv) {
/* Display usage hints. */
//显示使用提示
static void usage(u8* argv0) {
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
@ -836,7 +837,7 @@ static void usage(u8* argv0) {
/* Find binary. */
//查找并验证二进制文件的路径
static void find_binary(u8* fname) {
u8* env_path = 0;
@ -889,7 +890,7 @@ static void find_binary(u8* fname) {
/* Fix up argv for QEMU. */
//为QEMU模式修复argv设置QEMU的参数
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
@ -952,7 +953,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
/* Main entry point */
//程序的主入口点。处理命令行参数,设置环境,执行分析,并输出结果
int main(int argc, char** argv) {
s32 opt;

@ -56,19 +56,19 @@
#include <sys/wait.h>
#include <sys/time.h>
static u8** as_params; /* Parameters passed to the real 'as' */
static u8** as_params; /* Parameters passed to the real 'as' */ //传递给as的参数数组
static u8* input_file; /* Originally specified input file */
static u8* modified_file; /* Instrumented file for the real 'as' */
static u8* input_file; /* Originally specified input file */
static u8* modified_file; /* Instrumented file for the real 'as' */ //用于as的插有instrumentation的文件
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 */
static u8 be_quiet, /* Quiet mode (no stderr output) */ //是否开启安静模式不输出到stderr
clang_mode, /* Running in clang mode? */ // 是否在clang模式下运行
pass_thru, /* Just pass data through? */ //是否只是简单地传递数据
just_version, /* Just show version? */ //是否只显示版本号
sanitizer; /* Using ASAN / MSAN */ //是否使用ASAN或MSAN
static u32 inst_ratio = 100, /* Instrumentation probability (%) */
as_par_cnt = 1; /* Number of params to 'as' */
static u32 inst_ratio = 100, /* Instrumentation probability (%) */ //Instrumentation概率%
as_par_cnt = 1; /* Number of params to 'as' */ //传递给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
@ -92,7 +92,7 @@ static u8 use_64bit = 0;
/* 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. */
//处理和修改传递给asGNU assembler的参数。这个函数会检查命令行参数并根据这些参数来设置全局变量如use_64bit和as_params
static void edit_params(int argc, char** argv) {
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
@ -129,7 +129,7 @@ static void edit_params(int argc, char** argv) {
/* Although this is not documented, GCC also uses TEMP and TMP when TMPDIR
is not set. We need to check these non-standard variables to properly
handle the pass_thru logic later on. */
//检查TMPDIR、AFL_AS等环境变量确定临时目录和汇编器路径
if (!tmp_dir) tmp_dir = getenv("TEMP");
if (!tmp_dir) tmp_dir = getenv("TMP");
if (!tmp_dir) tmp_dir = "/tmp";
@ -148,7 +148,9 @@ static void edit_params(int argc, char** argv) {
#ifdef __APPLE__
/* The Apple case is a bit different... */
//这段代码检查命令行参数中是否有 -arch并检查其后的参数。
//如果 -arch 后面是 x86_64则设置 use_64bit 为 1表示使用 64 位模式。
//如果 -arch 后面是 i386则输出错误信息并终止程序因为 32 位的 Apple 平台不被支持
if (!strcmp(argv[i], "-arch") && i + 1 < argc) {
if (!strcmp(argv[i + 1], "x86_64")) use_64bit = 1;
@ -159,12 +161,12 @@ static void edit_params(int argc, char** argv) {
/* Strip options that set the preference for a particular upstream
assembler in Xcode. */
//如果当前处于 clang 模式,并且命令行参数中有 -q 或 -Q则跳过这些参数不将它们传递给汇编器
if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
continue;
#endif /* __APPLE__ */
//将当前处理的命令行参数 argv[i] 添加到 as_params 数组中as_par_cnt 用于记录已添加的参数数量
as_params[as_par_cnt++] = argv[i];
}
@ -173,7 +175,9 @@ static void edit_params(int argc, char** argv) {
/* When calling clang as the upstream assembler, append -c -x assembler
and hope for the best. */
//如果 use_clang_as 为真(即在 macOS 下使用 clang 作为汇编器)
//则向 as_params 数组中添加 -c、-x 和 assembler 参数
//以确保 clang 正确处理汇编文件
if (use_clang_as) {
as_params[as_par_cnt++] = "-c";
@ -183,7 +187,9 @@ static void edit_params(int argc, char** argv) {
}
#endif /* __APPLE__ */
//如果是 --version则设置 just_version 为 1并跳转到 wrap_things_up直接返回版本信息。
//如果输入文件以 - 开头但不是 --version则输出错误信息并终止程序。
//如果输入文件是单独的 -,则将 input_file 设置为 NULL表示从标准输入读取
input_file = argv[argc - 1];
if (input_file[0] == '-') {
@ -203,16 +209,17 @@ static void edit_params(int argc, char** argv) {
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. */
//检查输入文件是否位于临时目录(如 /tmp 或 /var/tmp
//如果输入文件不在临时目录中,则设置 pass_thru 为 1表示直接传递文件内容而不进行插桩
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) &&
strncmp(input_file, "/tmp/", 5)) pass_thru = 1;
}
//生成一个临时文件名,用于存储插桩后的汇编文件。文件名格式为 tmp_dir/.afl-PID-TIMESTAMP.s
modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(),
(u32)time(NULL));
//将生成的临时文件名添加到 as_params 数组中,作为汇编器的输入文件,并将数组末尾设置为 NULL表示参数列表结束
wrap_things_up:
as_params[as_par_cnt++] = modified_file;
@ -223,9 +230,13 @@ wrap_things_up:
/* Process input file, generate modified_file. Insert instrumentation in all
the appropriate places. */
//处理输入文件并生成一个修改过的文件modified_file在其中插入 instrumentation仪器化代码。这个函数会读取原始的汇编文件根据配置插入instrumentation代码并将结果写入新的文件
static void add_instrumentation(void) {
//line[MAX_LINE]:用于存储从输入文件中读取的每一行。
//inf 和 outf分别表示输入文件和输出文件的指针。
//outfd输出文件的文件描述符。
//ins_lines记录插桩的行数。
static u8 line[MAX_LINE];
FILE* inf;
@ -241,14 +252,16 @@ static void add_instrumentation(void) {
u8* colon_pos;
#endif /* __APPLE__ */
//打开输入文件以供读取。
//如果 input_file 不为空,则打开该文件;否则从标准输入读取
if (input_file) {
inf = fopen(input_file, "r");
if (!inf) PFATAL("Unable to read '%s'", input_file);
} else inf = stdin;
//创建并打开输出文件以供写入。
//使用 open 创建文件,并使用 fdopen 将其转换为 FILE* 类型
outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600);
if (outfd < 0) PFATAL("Unable to write to '%s'", modified_file);
@ -256,14 +269,15 @@ static void add_instrumentation(void) {
outf = fdopen(outfd, "w");
if (!outf) PFATAL("fdopen() failed");
//
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. */
//在适当的位置插入插桩代码。
//如果满足条件(如不在跳过模式、处于 .text 段、需要插桩等),则插入插桩代码,并增加插桩行数
if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
instrument_next && line[0] == '\t' && isalpha(line[1])) {
@ -276,15 +290,17 @@ static void add_instrumentation(void) {
}
/* Output the actual line, call it a day in pass-thru mode. */
//将当前行写入输出文件。
fputs(line, outf);
//如果处于 pass_thru 模式,则跳过后续处理
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 段。
//如果当前行表示 .text 段,则设置 instr_ok 为 1表示可以插桩。
//如果当前行表示其他段(如 .bss 或 .data则设置 instr_ok 为 0表示跳过插桩
if (line[0] == '\t' && line[1] == '.') {
/* OpenBSD puts jump tables directly inline with the code, which is
@ -315,7 +331,8 @@ static void add_instrumentation(void) {
/* 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 指令。
//如果检测到 .code32 或 .code64则根据当前模式设置 skip_csect跳过插桩
if (strstr(line, ".code")) {
if (strstr(line, ".code32")) skip_csect = use_64bit;
@ -325,12 +342,14 @@ 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_syntax则跳过插桩如果检测到 .att_syntax则恢复插桩
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. */
//处理 #APP 和 #NO_APP 块。
//如果检测到 #APP则跳过插桩如果检测到 #NO_APP则恢复插桩
if (line[0] == '#' || line[1] == '#') {
if (strstr(line, "#APP")) skip_app = 1;
@ -361,7 +380,8 @@ static void add_instrumentation(void) {
later on.
*/
//处理函数标签和条件分支。
//如果当前行是条件分支指令(如 jnz则插入插桩代码
if (skip_intel || skip_app || skip_csect || !instr_ok ||
line[0] == '#' || line[0] == ' ') continue;
@ -391,7 +411,8 @@ static void add_instrumentation(void) {
#ifdef __APPLE__
/* Apple: L<whatever><digit>: */
//处理标签。
//如果当前行是标签(如 .L0: 或 LBB0_0:),则根据需要设置 instrument_next表示后续需要插桩
if ((colon_pos = strstr(line, ":"))) {
if (line[0] == 'L' && isdigit(*(colon_pos - 1))) {
@ -450,10 +471,11 @@ static void add_instrumentation(void) {
}
}
//在所有插桩完成后,插入主插桩代码
if (ins_lines)
fputs(use_64bit ? main_payload_64 : main_payload_32, outf);
//关闭文件并输出插桩结果。
//如果没有插桩目标,则输出警告;否则输出插桩的详细信息
if (input_file) fclose(inf);
fclose(outf);
@ -473,25 +495,30 @@ static void add_instrumentation(void) {
/* Main entry point */
//程序的主入口点。处理命令行参数设置随机种子调用edit_params来编辑参数
//根据环境变量AFL_INST_RATIO设置instrumentation概率
//然后调用add_instrumentation来添加instrumentation代码并最终执行as
int main(int argc, char** argv) {
s32 pid;
u32 rand_seed;
int status;
u8* inst_ratio_str = getenv("AFL_INST_RATIO");
s32 pid; //用于存储 fork 后的子进程 ID
u32 rand_seed; //用于存储随机种子
int status; //用于存储子进程的退出状态
u8* inst_ratio_str = getenv("AFL_INST_RATIO"); //从环境变量 AFL_INST_RATIO 中获取插桩比例
struct timeval tv;
struct timezone tz;
//检查是否处于 clang 模式。
//如果环境变量 CLANG_ENV_VAR 存在,则设置 clang_mode 为 1否则为 0
clang_mode = !!getenv(CLANG_ENV_VAR);
//检查是否在终端运行,并输出提示信息。
//如果标准错误输出是终端且未设置 AFL_QUIET则输出程序名称和版本信息否则设置 be_quiet 为 1表示静默模式
if (isatty(2) && !getenv("AFL_QUIET")) {
SAYF(cCYA "afl-as " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
} else be_quiet = 1;
//检查命令行参数是否足够。
//如果参数少于 2 个,则输出帮助信息并退出程序
if (argc < 2) {
SAYF("\n"
@ -506,22 +533,27 @@ int main(int argc, char** argv) {
exit(1);
}
//生成并设置随机种子。
//使用当前时间、微秒数和进程 ID 生成随机种子,并调用 srandom 设置随机数生成器
gettimeofday(&tv, &tz);
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
srandom(rand_seed);
//调用 edit_params 函数处理命令行参数。
//该函数会解析命令行参数并设置相关变量(如 input_file、modified_file 等)
edit_params(argc, argv);
//从环境变量 AFL_INST_RATIO 中读取插桩比例。
//如果插桩比例无效(不在 0 到 100 之间),则输出错误信息并终止程序
if (inst_ratio_str) {
if (sscanf(inst_ratio_str, "%u", &inst_ratio) != 1 || inst_ratio > 100)
FATAL("Bad value of AFL_INST_RATIO (must be between 0 and 100)");
}
//检查并设置环境变量 AS_LOOP_ENV_VAR。
//如果该环境变量已存在,则输出错误信息并终止程序(防止无限循环)。
//否则设置该环境变量为 "1"
if (getenv(AS_LOOP_ENV_VAR))
FATAL("Endless loop when calling 'as' (remove '.' from your PATH)");
@ -530,27 +562,34 @@ int main(int argc, char** argv) {
/* When compiling with ASAN, we don't have a particularly elegant way to skip
ASAN-specific branches. But we can probabilistically compensate for
that... */
//处理 ASAN 或 MSAN 模式。
//如果启用了 ASAN 或 MSAN则设置 sanitizer 为 1并将插桩比例除以 3
if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) {
sanitizer = 1;
inst_ratio /= 3;
}
//调用 add_instrumentation 函数进行插桩。
//如果未设置 just_version则执行插桩操作
if (!just_version) add_instrumentation();
//创建子进程并执行 as 命令。
//使用 fork 创建子进程,并在子进程中调用 execvp 执行 as 命令。
//如果执行失败,则输出错误信息并终止程序
if (!(pid = fork())) {
execvp(as_params[0], (char**)as_params);
execvp(as_params[0], (char**)as_params);//传递给as的参数数组
FATAL("Oops, failed to execute '%s' - check your PATH", as_params[0]);
}
//等待子进程结束。
//如果 fork 失败,则输出错误信息并终止程序。
//使用 waitpid 等待子进程结束,并获取其退出状态
if (pid < 0) PFATAL("fork() failed");
if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
//删除临时文件。
//如果未设置 AFL_KEEP_ASSEMBLY则删除生成的临时文件
if (!getenv("AFL_KEEP_ASSEMBLY")) unlink(modified_file);
//使用 WEXITSTATUS 获取子进程的退出状态,并将其作为程序的返回值
exit(WEXITSTATUS(status));
}

@ -111,7 +111,7 @@
oddball register it may touch.
*/
//32位系统的_trampoline_格式用于在函数调用前后保存和恢复寄存器状态并调用__afl_maybe_log函数
static const u8* trampoline_fmt_32 =
"\n"
@ -135,6 +135,7 @@ static const u8* trampoline_fmt_32 =
"/* --- END --- */\n"
"\n";
//64位系统的_trampoline_格式功能与32位版本类似
static const u8* trampoline_fmt_64 =
"\n"
@ -156,6 +157,7 @@ static const u8* trampoline_fmt_64 =
"/* --- END --- */\n"
"\n";
//这些是32位和64位系统的主要payload包含了AFL的instrumentation逻辑
static const u8* main_payload_32 =
"\n"
@ -167,7 +169,7 @@ static const u8* main_payload_32 =
".align 8\n"
"\n"
"__afl_maybe_log:\n"
"__afl_maybe_log:\n" //检查共享内存区域是否已经映射并调用__afl_store来记录分支信息
"\n"
" lahf\n"
" seto %al\n"
@ -178,7 +180,7 @@ static const u8* main_payload_32 =
" testl %edx, %edx\n"
" je __afl_setup\n"
"\n"
"__afl_store:\n"
"__afl_store:\n" //计算并存储指定代码位置的分支信息
"\n"
" /* Calculate and store hit for the code location specified in ecx. There\n"
" is a double-XOR way of doing this without tainting another register,\n"
@ -199,7 +201,7 @@ static const u8* main_payload_32 =
" incb (%edx, %edi, 1)\n"
#endif /* ^SKIP_COUNTS */
"\n"
"__afl_return:\n"
"__afl_return:\n" //处理返回前的标志寄存器
"\n"
" addb $127, %al\n"
" sahf\n"
@ -207,7 +209,7 @@ static const u8* main_payload_32 =
"\n"
".align 8\n"
"\n"
"__afl_setup:\n"
"__afl_setup:\n" //设置共享内存区域如果设置失败则跳转到__afl_setup_abort
"\n"
" /* Do not retry setup if we had previous failures. */\n"
"\n"
@ -249,7 +251,7 @@ static const u8* main_payload_32 =
" popl %ecx\n"
" popl %eax\n"
"\n"
"__afl_forkserver:\n"
"__afl_forkserver:\n" //进入fork服务器模式避免execve()调用的开销
"\n"
" /* Enter the fork server mode to avoid the overhead of execve() calls. */\n"
"\n"
@ -269,9 +271,9 @@ static const u8* main_payload_32 =
" addl $12, %esp\n"
"\n"
" cmpl $4, %eax\n"
" jne __afl_fork_resume\n"
" jne __afl_fork_resume\n" //在子进程中关闭文件描述符并继续执行
"\n"
"__afl_fork_wait_loop:\n"
"__afl_fork_wait_loop:\n" //等待父进程的指令如果读取失败则跳转到__afl_die
"\n"
" /* Wait for parent by reading from the pipe. Abort if read fails. */\n"
"\n"
@ -282,7 +284,7 @@ static const u8* main_payload_32 =
" addl $12, %esp\n"
"\n"
" cmpl $4, %eax\n"
" jne __afl_die\n"
" jne __afl_die\n" //终止当前进程
"\n"
" /* Once woken up, create a clone of our process. This is an excellent use\n"
" case for syscall(__NR_clone, 0, CLONE_PARENT), but glibc boneheadedly\n"
@ -346,7 +348,7 @@ static const u8* main_payload_32 =
" xorl %eax, %eax\n"
" call _exit\n"
"\n"
"__afl_setup_abort:\n"
"__afl_setup_abort:\n" //记录设置失败避免重复调用shmget()/shmat()
"\n"
" /* Record setup failure so that we don't keep calling\n"
" shmget() / shmat() over and over again. */\n"
@ -356,7 +358,7 @@ static const u8* main_payload_32 =
" popl %eax\n"
" jmp __afl_return\n"
"\n"
".AFL_VARS:\n"
".AFL_VARS:\n" //定义了一系列全局变量包括共享内存区域指针、设置失败标志、前一个位置指针、fork的PID和临时变量
"\n"
" .comm __afl_area_ptr, 4, 32\n"
" .comm __afl_setup_failure, 1, 32\n"
@ -366,7 +368,7 @@ static const u8* main_payload_32 =
" .comm __afl_fork_pid, 4, 32\n"
" .comm __afl_temp, 4, 32\n"
"\n"
".AFL_SHM_ENV:\n"
".AFL_SHM_ENV:\n" //定义了共享内存环境变量的名称
" .asciz \"" SHM_ENV_VAR "\"\n"
"\n"
"/* --- END --- */\n"
@ -379,7 +381,7 @@ static const u8* main_payload_32 =
they are doing relocations differently from everybody else. We also need
to work around the crash issue with .lcomm and the fact that they don't
recognize .string. */
//由于这些平台在指令识别和库函数调用方面与其他平台不同,因此需要特定的代码来处理这些差异
#ifdef __APPLE__
# define CALL_L64(str) "call _" str "\n"
#else

Loading…
Cancel
Save