Compare commits

..

8 Commits

Binary file not shown.

@ -1,2 +0,0 @@
# QQLLMW

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -21,6 +21,8 @@
its structure by observing how changes to it affect the execution path. its structure by observing how changes to it affect the execution path.
If the output scrolls past the edge of the screen, pipe it to 'less -r'. If the output scrolls past the edge of the screen, pipe it to 'less -r'.
shashaqingkuangwoq
*/ */
@ -96,7 +98,7 @@ static afl_forkserver_t fsrv = {0}; /* The forkserver */
/* Classify tuple counts. This is a slow & naive version, but good enough here. /* Classify tuple counts. This is a slow & naive version, but good enough here.
*/ */
//将模糊测试的错误数进行归并,在不造成太大影响的情况下减少运算、提升性能 //分类计数,并通过不同的范围将输入映射到特定的值上。
static u8 count_class_lookup[256] = { static u8 count_class_lookup[256] = {
[0] = 0, [0] = 0,
@ -111,29 +113,27 @@ static u8 count_class_lookup[256] = {
}; };
//结束子进程 //终止一个子进程
static void kill_child() { static void kill_child() {
// 判断fsrv结构体中的child_pid是否大于0即是否有有效的子进程ID
if (fsrv.child_pid > 0) { if (fsrv.child_pid > 0) {
// 使用kill函数向子进程发送终止信号信号类型为fsrv.child_kill_signal
//kill函数杀死对应pid的子进程并将其标志位置为1
kill(fsrv.child_pid, fsrv.child_kill_signal); kill(fsrv.child_pid, fsrv.child_kill_signal);
//将子进程的pid置为-1即无法选中
fsrv.child_pid = -1; fsrv.child_pid = -1;
} }
} }
//对内存中的字节进行分类通过预定的count_class_lookup数组实现分类的效果 //对给定内存块中的数据进行分类处理。根据模糊测试的模式决定是将非零值设置为1还是根据count_class_lookup数组对每个字节进行分类映射。
static void classify_counts(u8 *mem, u32 mem_size) { static void classify_counts(u8 *mem, u32 mem_size) {
u32 i = mem_size; u32 i = mem_size;
//如果只对边缘探测有要求只用设置为bool变量
if (edges_only) { if (edges_only) {
while (i--) { while (i--) {
// 如果当前指针所指向的值非零则将其设置为1
if (*mem) { *mem = 1; } if (*mem) { *mem = 1; }
mem++; mem++;
@ -142,7 +142,7 @@ static void classify_counts(u8 *mem, u32 mem_size) {
} else { } else {
while (i--) { while (i--) {
// 根据count_class_lookup数组将当前指针所指向的值进行分类替换
*mem = count_class_lookup[*mem]; *mem = count_class_lookup[*mem];
mem++; mem++;
@ -153,11 +153,10 @@ static void classify_counts(u8 *mem, u32 mem_size) {
} }
/* See if any bytes are set in the bitmap. */ /* See if any bytes are set in the bitmap. */
//遍历整个bitmap检查是否有字节在bitmap里面被设置了 // 检查bitmap中是否存在零值
static inline u8 anything_set(void) { static inline u8 anything_set(void) {
//使用fsrv.trace_bits模拟bitmap // 将 fsrv.trace_bits 转换为指向 u32 类型的指针
u32 *ptr = (u32 *)fsrv.trace_bits; u32 *ptr = (u32 *)fsrv.trace_bits;
//map_size的大小除以4因为是按字节进行搜索
u32 i = (map_size >> 2); u32 i = (map_size >> 2);
while (i--) { while (i--) {
@ -165,30 +164,30 @@ static inline u8 anything_set(void) {
if (*(ptr++)) { return 1; } if (*(ptr++)) { return 1; }
} }
// 如果所有值均为零,返回 0
return 0; return 0;
} }
/* Get rid of temp files (atexit handler). */ /* Get rid of temp files (atexit handler). */
//在函数结束时调用,删除临时文件
static void at_exit_handler(void) {
static void at_exit_handler(void) {
//退出
unlink(fsrv.out_file); /* Ignore errors */ unlink(fsrv.out_file); /* Ignore errors */
} }
/* Read initial file. */ /* Read initial file. */
//读取需要分析的文件的起始状态 // 读取初始文件并进行检查
static void read_initial_file(void) { static void read_initial_file(void) {
struct stat st; struct stat st;
s32 fd = open(in_file, O_RDONLY); s32 fd = open(in_file, O_RDONLY);
//无法读取分支 // 检查文件打开是否成功,若失败则打印错误信息并终止程序
if (fd < 0) { PFATAL("Unable to open '%s'", in_file); } if (fd < 0) { PFATAL("Unable to open '%s'", in_file); }
//读取到的文件内容为空分支 // 获取文件状态信息,并检查文件大小,若获取失败或文件大小为零,则终止程序
if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); } if (fstat(fd, &st) || !st.st_size) { FATAL("Zero-sized input file."); }
//读取文件内容超过缓存最大值分支 // 检查文件大小是否超过最大限制 TMIN_MAX_FILE若超过则终止程序
if (st.st_size >= TMIN_MAX_FILE) { if (st.st_size >= TMIN_MAX_FILE) {
FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024); FATAL("Input file is too large (%ld MB max)", TMIN_MAX_FILE / 1024 / 1024);
@ -196,75 +195,70 @@ static void read_initial_file(void) {
} }
in_len = st.st_size; in_len = st.st_size;
// 分配内存以存储文件内容,并确保内存初始化为零
in_data = ck_alloc_nozero(in_len); in_data = ck_alloc_nozero(in_len);
ck_read(fd, in_data, in_len, in_file); ck_read(fd, in_data, in_len, in_file);
close(fd); close(fd);
// 打印读取成功的信息,包括读取的字节数
OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file); OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
} }
/* Execute target application. Returns exec checksum, or 0 if program /* Execute target application. Returns exec checksum, or 0 if program
times out. */ times out. */
//起一个目标程序的镜像进程,用于在不影响程序正常使用的前提下对程序进行模糊测试 // 分析目标程序的运行结果
static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) { static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
//将该程序的镜像地址写入到测试栈中 // 将输入数据写入测试用例
afl_fsrv_write_to_testcase(&fsrv, mem, len); afl_fsrv_write_to_testcase(&fsrv, mem, len);
//使用afl_fsrv_run_target函数尝试运行镜像进程并将结果返回到fsrv_run_result_t对象中 // 运行目标程序并获取运行结果
fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon); fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
//创建镜像失败分支
if (ret == FSRV_RUN_ERROR) {
if (ret == FSRV_RUN_ERROR) {
// forkserver 错误
FATAL("Error in forkserver"); FATAL("Error in forkserver");
} } else if (ret == FSRV_RUN_NOINST) {
//运行镜像缺失分支 // 目标未被插桩
else if (ret == FSRV_RUN_NOINST) {
FATAL("Target not instrumented"); FATAL("Target not instrumented");
} } else if (ret == FSRV_RUN_NOBITS) {
//运行报错分支 // 运行目标失败
else if (ret == FSRV_RUN_NOBITS) {
FATAL("Failed to run target"); FATAL("Failed to run target");
} }
//调用classify_counts函数对测试进程内存中的字节进行分类以作进一步模糊测试 // 根据跟踪位图分类计数
classify_counts(fsrv.trace_bits, fsrv.map_size); classify_counts(fsrv.trace_bits, fsrv.map_size);
//全局变量中total_execs自增对测试程序数进行记录
total_execs++; total_execs++;
if (stop_soon) { if (stop_soon) {
//用户操作退出Ctrl+C弹出退出示警 // 检查用户是否中止了分析
SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST); SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
exit(1); exit(1);
} }
/* Always discard inputs that time out. */ /* Always discard inputs that time out. */
//镜像运行超时全局变量中exec_hangs自增对测试程序超时数进行记录
if (fsrv.last_run_timed_out) {
if (fsrv.last_run_timed_out) {
// 统计超时次数
exec_hangs++; exec_hangs++;
return 0; return 0;
} }
//校验和
u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST); u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
if (ret == FSRV_RUN_CRASH) { if (ret == FSRV_RUN_CRASH) {
// 如果目标程序崩溃,修改哈希值
/* We don't actually care if the target is crashing or not, /* We don't actually care if the target is crashing or not,
except that when it does, the checksum should be different. */ except that when it does, the checksum should be different. */
//校验和全1异或每位取反
cksum ^= 0xffffffff; cksum ^= 0xffffffff;
} }
//记录初始校验和 // 如果是第一次运行,将原始哈希值保存
if (first_run) { orig_cksum = cksum; } if (first_run) { orig_cksum = cksum; }
return cksum; return cksum;
@ -272,16 +266,15 @@ static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
} }
#ifdef USE_COLOR #ifdef USE_COLOR
//如果给出颜色,规范化表达
/* Helper function to display a human-readable character. */ /* Helper function to display a human-readable character. */
//将内存内字节打印成用户可读字符
static void show_char(u8 val) { static void show_char(u8 val) {
switch (val) { switch (val) {
case 0 ... 32: case 0 ... 32:
case 127 ... 255: case 127 ... 255:
//通过格式化输出实现
SAYF("#%02x", val); SAYF("#%02x", val);
break; break;
@ -293,7 +286,7 @@ static void show_char(u8 val) {
} }
/* Show the legend */ /* Show the legend */
//将内存字节设置为不同字体颜色,方便用户区分
static void show_legend(void) { static void show_legend(void) {
SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block " cBLK bgLGN
@ -312,7 +305,7 @@ static void show_legend(void) {
#endif /* USE_COLOR */ #endif /* USE_COLOR */
/* Interpret and report a pattern in the input file. */ /* Interpret and report a pattern in the input file. */
//以16进制形式储存文件分析字节行为 // 以十六进制格式转储二进制数据并进行分类
static void dump_hex(u32 len, u8 *b_data) { static void dump_hex(u32 len, u8 *b_data) {
u32 i; u32 i;
@ -324,13 +317,13 @@ static void dump_hex(u32 len, u8 *b_data) {
#else #else
u32 rlen = 1; u32 rlen = 1;
#endif /* ^USE_COLOR */ #endif /* ^USE_COLOR */
// 获取当前字节的类型,提取低 4 位
u8 rtype = b_data[i] & 0x0f; u8 rtype = b_data[i] & 0x0f;
/* Look ahead to determine the length of run. */ /* Look ahead to determine the length of run. */
//确定运行长度 //向前查看以确定当前字节的运行长度
while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) { while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
// 更新当前运行的类型
if (rtype < (b_data[i + rlen] & 0x0f)) { if (rtype < (b_data[i + rlen] & 0x0f)) {
rtype = b_data[i + rlen] & 0x0f; rtype = b_data[i + rlen] & 0x0f;
@ -342,7 +335,7 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
/* Try to do some further classification based on length & value. */ /* Try to do some further classification based on length & value. */
//对字节相应类型进行分类 //根据长度和类型进行进一步分类
if (rtype == RESP_FIXED) { if (rtype == RESP_FIXED) {
switch (rlen) { switch (rlen) {
@ -352,9 +345,9 @@ static void dump_hex(u32 len, u8 *b_data) {
u16 val = *(u16 *)(in_data + i); u16 val = *(u16 *)(in_data + i);
/* Small integers may be length fields. */ /* Small integers may be length fields. */
if (val && (val <= in_len || SWAP16(val) <= in_len)) { if (val && (val <= in_len || SWAP16(val) <= in_len)) {
//判断为运行长度 // 将类型更改为长度字段
rtype = RESP_LEN; rtype = RESP_LEN;
break; break;
@ -363,7 +356,7 @@ static void dump_hex(u32 len, u8 *b_data) {
/* Uniform integers may be checksums. */ /* Uniform integers may be checksums. */
if (val && abs(in_data[i] - in_data[i + 1]) > 32) { if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
//判断为校验和 // 将类型更改为校验和
rtype = RESP_CKSUM; rtype = RESP_CKSUM;
break; break;
@ -374,13 +367,13 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
case 4: { case 4: {
//同上
u32 val = *(u32 *)(in_data + i); u32 val = *(u32 *)(in_data + i);
/* Small integers may be length fields. */ /* Small integers may be length fields. */
if (val && (val <= in_len || SWAP32(val) <= in_len)) { if (val && (val <= in_len || SWAP32(val) <= in_len)) {
// 将类型更改为长度字段
rtype = RESP_LEN; rtype = RESP_LEN;
break; break;
@ -391,7 +384,7 @@ static void dump_hex(u32 len, u8 *b_data) {
if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 || if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
in_data[i] >> 7 != in_data[i + 2] >> 7 || in_data[i] >> 7 != in_data[i + 2] >> 7 ||
in_data[i] >> 7 != in_data[i + 3] >> 7)) { in_data[i] >> 7 != in_data[i + 3] >> 7)) {
// 将类型更改为校验和
rtype = RESP_CKSUM; rtype = RESP_CKSUM;
break; break;
@ -400,7 +393,7 @@ static void dump_hex(u32 len, u8 *b_data) {
break; break;
} }
// 对于 1, 3, 5 到 MAX_AUTO_EXTRA - 1 的情况,不做处理
case 1: case 1:
case 3: case 3:
case 5 ... MAX_AUTO_EXTRA - 1: case 5 ... MAX_AUTO_EXTRA - 1:
@ -414,23 +407,23 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
/* Print out the entire run. */ /* Print out the entire run. */
//如果使用颜色模板,下面代码会规范化输出
#ifdef USE_COLOR #ifdef USE_COLOR
for (off = 0; off < rlen; off++) { for (off = 0; off < rlen; off++) {
/* Every 16 digits, display offset. */ /* Every 16 digits, display offset. */
//每4个字节作为一组进行输出
if (!((i + off) % 16)) { if (!((i + off) % 16)) {
if (off) { SAYF(cRST cLCY ">"); } if (off) { SAYF(cRST cLCY ">"); }
if (use_hex_offsets) { if (use_hex_offsets) {
//规格化输出
SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off); SAYF(cRST cGRA "%s[%06x] " cRST, (i + off) ? "\n" : "", i + off);
} else { } else {
//规格化输出
SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off); SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
} }
@ -438,7 +431,7 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
switch (rtype) { switch (rtype) {
//根据rtype分析的不同类型进行不同的上色便于用户区分
case RESP_NONE: case RESP_NONE:
SAYF(cLGR bgGRA); SAYF(cLGR bgGRA);
break; break;
@ -462,11 +455,11 @@ static void dump_hex(u32 len, u8 *b_data) {
break; break;
} }
//输出
show_char(in_data[i + off]); show_char(in_data[i + off]);
if (off != rlen - 1 && (i + off + 1) % 16) { if (off != rlen - 1 && (i + off + 1) % 16) {
//补齐
SAYF(" "); SAYF(" ");
} else { } else {
@ -478,14 +471,14 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
#else #else
//根据用户是否需求16进制进行输出的处理
if (use_hex_offsets) if (use_hex_offsets)
SAYF(" Offset %x, length %u: ", i, rlen); SAYF(" Offset %x, length %u: ", i, rlen);
else else
SAYF(" Offset %u, length %u: ", i, rlen); SAYF(" Offset %u, length %u: ", i, rlen);
switch (rtype) { switch (rtype) {
//输出测试分析得到的信息
case RESP_NONE: case RESP_NONE:
SAYF("no-op block\n"); SAYF("no-op block\n");
break; break;
@ -523,17 +516,17 @@ static void dump_hex(u32 len, u8 *b_data) {
} }
/* Actually analyze! */ /* Actually analyze! */
//分析函数 // 分析输入文件
static void analyze() { static void analyze() {
//初始化变量 // 定义变量
u32 i; u32 i;
u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0; u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
// 动态分配内存,用于存储分析结果
u8 *b_data = ck_alloc(in_len + 1); u8 *b_data = ck_alloc(in_len + 1);
u8 seq_byte = 0; u8 seq_byte = 0;
// 在末尾添加一个故意的终止符
b_data[in_len] = 0xff; /* Intentional terminator. */ b_data[in_len] = 0xff; /* Intentional terminator. */
// 输出分析开始的信息
ACTF("Analyzing input file (this may take a while)...\n"); ACTF("Analyzing input file (this may take a while)...\n");
#ifdef USE_COLOR #ifdef USE_COLOR
@ -541,76 +534,80 @@ static void analyze() {
#endif /* USE_COLOR */ #endif /* USE_COLOR */
for (i = 0; i < in_len; i++) { for (i = 0; i < in_len; i++) {
//遍历程序的每一个字节 // 定义变量用于存储不同操作的结果
u64 xor_ff, xor_01, sub_10, add_10; u64 xor_ff, xor_01, sub_10, add_10;
// 定义变量用于存储原始校验和比较结果
u8 xff_orig, x01_orig, s10_orig, a10_orig; u8 xff_orig, x01_orig, s10_orig, a10_orig;
/* Perform walking byte adjustments across the file. We perform four /* Perform walking byte adjustments across the file. We perform four
operations designed to elicit some response from the underlying operations designed to elicit some response from the underlying
code. */ code. */
//对程序的每个字节进行异或0xff、异或0x01、减0x10、加0x20操作然后进行运行分析查看是否会对程序的运行产生影响 // 对文件中的每一个字节进行四种操作以引发响应
// 对当前字节进行异或操作
in_data[i] ^= 0xff; in_data[i] ^= 0xff;
// 运行目标分析并获取结果
xor_ff = analyze_run_target(in_data, in_len, 0); xor_ff = analyze_run_target(in_data, in_len, 0);
// 进行另一种异或操作
in_data[i] ^= 0xfe; in_data[i] ^= 0xfe;
xor_01 = analyze_run_target(in_data, in_len, 0); xor_01 = analyze_run_target(in_data, in_len, 0);
// 进行减法和异或操作
in_data[i] = (in_data[i] ^ 0x01) - 0x10; in_data[i] = (in_data[i] ^ 0x01) - 0x10;
sub_10 = analyze_run_target(in_data, in_len, 0); sub_10 = analyze_run_target(in_data, in_len, 0);
// 进行加法操作
in_data[i] += 0x20; in_data[i] += 0x20;
add_10 = analyze_run_target(in_data, in_len, 0); add_10 = analyze_run_target(in_data, in_len, 0);
// 恢复当前字节的值
in_data[i] -= 0x10; in_data[i] -= 0x10;
/* Classify current behavior. */ /* Classify current behavior. */
//记录校验和,以观察是否有影响 // 根据不同操作的结果分类当前字节的行为
xff_orig = (xor_ff == orig_cksum); xff_orig = (xor_ff == orig_cksum);
x01_orig = (xor_01 == orig_cksum); x01_orig = (xor_01 == orig_cksum);
s10_orig = (sub_10 == orig_cksum); s10_orig = (sub_10 == orig_cksum);
a10_orig = (add_10 == orig_cksum); a10_orig = (add_10 == orig_cksum);
if (xff_orig && x01_orig && s10_orig && a10_orig) { if (xff_orig && x01_orig && s10_orig && a10_orig) {
//如果都不报错,则将该字节标记为无用项 // 如果所有操作的结果均与原始校验和相同,则将当前字节的行为设置为 RESP_NONE
b_data[i] = RESP_NONE; b_data[i] = RESP_NONE;
boring_len++; boring_len++;
} else if (xff_orig || x01_orig || s10_orig || a10_orig) { } else if (xff_orig || x01_orig || s10_orig || a10_orig) {
//报错则标记为错误项 // 如果有一个操作的结果与原始校验和相同,则将当前字节的行为设置为 RESP_MINOR
b_data[i] = RESP_MINOR; b_data[i] = RESP_MINOR;
boring_len++; boring_len++;
} else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) { } else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
//如果经过不同方式修改后的校验和相等,则将该字节标记为可自修复项 // 如果所有操作的结果均相同,则将当前字节的行为设置为 RESP_FIXED
b_data[i] = RESP_FIXED; b_data[i] = RESP_FIXED;
} else { } else {
//否则则将该字节标记为变异项 // 否则将当前字节的行为设置为 RESP_VARIABLE
b_data[i] = RESP_VARIABLE; b_data[i] = RESP_VARIABLE;
} }
/* When all checksums change, flip most significant bit of b_data. */ /* When all checksums change, flip most significant bit of b_data. */
//如果所有变异操作都与上一个字节的测试不一样,就翻转最高位
if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 && if (prev_xff != xor_ff && prev_x01 != xor_01 && prev_s10 != sub_10 &&
prev_a10 != add_10) { prev_a10 != add_10) {
// 当所有校验和都发生变化时,将 b_data 的最高位翻转
seq_byte ^= 0x80; seq_byte ^= 0x80;
} }
// 将当前字节的行为与序列字节进行合并
b_data[i] |= seq_byte; b_data[i] |= seq_byte;
// 更新序列字节
prev_xff = xor_ff; prev_xff = xor_ff;
prev_x01 = xor_01; prev_x01 = xor_01;
prev_s10 = sub_10; prev_s10 = sub_10;
prev_a10 = add_10; prev_a10 = add_10;
} }
//输出分析结果 // 输出分析结果
dump_hex(in_len, b_data); dump_hex(in_len, b_data);
// 输出分析结束信息
SAYF("\n"); SAYF("\n");
// 输出分析完成的信息,包括异常数据的百分比
OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.", OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
100.0 - ((double)boring_len * 100) / in_len); 100.0 - ((double)boring_len * 100) / in_len);
@ -620,15 +617,15 @@ static void analyze() {
exec_hangs); exec_hangs);
} }
// 释放分配的内存
ck_free(b_data); ck_free(b_data);
} }
/* Handle Ctrl-C and the like. */ /* Handle Ctrl-C and the like. */
//用户自出终止程序的代理函数
static void handle_stop_sig(int sig) {
static void handle_stop_sig(int sig) {
//处理用户退出事件即 Ctrl-C 事件
(void)sig; (void)sig;
stop_soon = 1; stop_soon = 1;
@ -637,39 +634,41 @@ static void handle_stop_sig(int sig) {
} }
/* Do basic preparations - persistent fds, filenames, etc. */ /* Do basic preparations - persistent fds, filenames, etc. */
//设置测试环境 //设置环境打开必要的系统文件设置临时输出文件处理和配置与内存分析、QEMU 和 Frida 相关的环境变量
static void set_up_environment(char **argv) { static void set_up_environment(char **argv) {
u8 *x; u8 *x;
char *afl_preload; char *afl_preload;
char *frida_afl_preload = NULL; char *frida_afl_preload = NULL;
// 尝试打开 /dev/null获取文件描述符
fsrv.dev_null_fd = open("/dev/null", O_RDWR); fsrv.dev_null_fd = open("/dev/null", O_RDWR);
// 如果打开失败,则打印错误信息并终止程序
if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
// 如果输出文件未设置,默认使用当前目录
if (!fsrv.out_file) { if (!fsrv.out_file) {
u8 *use_dir = "."; u8 *use_dir = ".";
// 检查当前目录是否可读、可写和可执行,若不可读、可写和可执行,则使用 /tmp 目录
if (access(use_dir, R_OK | W_OK | X_OK)) { if (access(use_dir, R_OK | W_OK | X_OK)) {
use_dir = get_afl_env("TMPDIR"); use_dir = get_afl_env("TMPDIR");
if (!use_dir) { use_dir = "/tmp"; } if (!use_dir) { use_dir = "/tmp"; }
} }
// 分配临时输出文件名
fsrv.out_file = fsrv.out_file =
alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
} }
// 删除已存在的临时输出文件
unlink(fsrv.out_file); unlink(fsrv.out_file);
fsrv.out_fd = fsrv.out_fd =
open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
// 如果打开失败,则打印错误信息并终止程序
if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
/* Set sane defaults... */ /* Set sane defaults... */
// 获取 MSAN_OPTIONS 环境变量,并检查是否包含 exitcode=MSAN_ERROR
x = get_afl_env("MSAN_OPTIONS"); x = get_afl_env("MSAN_OPTIONS");
if (x) { if (x) {
@ -682,9 +681,9 @@ static void set_up_environment(char **argv) {
} }
} }
// 设置默认的清理工具
set_sanitizer_defaults(); set_sanitizer_defaults();
// 检查 AFL_PRELOAD 环境变量
if (get_afl_env("AFL_PRELOAD")) { if (get_afl_env("AFL_PRELOAD")) {
if (qemu_mode) { if (qemu_mode) {
@ -692,9 +691,11 @@ static void set_up_environment(char **argv) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */ /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
} else if (frida_mode) { } else if (frida_mode) {
// 从环境变量获取 AFL_PRELOAD
afl_preload = getenv("AFL_PRELOAD"); afl_preload = getenv("AFL_PRELOAD");
// 查找 frida 二进制文件
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
// 根据 AFL_PRELOAD 是否设置,构建 frida_afl_preload
if (afl_preload) { if (afl_preload) {
frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
@ -704,9 +705,9 @@ static void set_up_environment(char **argv) {
frida_afl_preload = alloc_printf("%s", frida_binary); frida_afl_preload = alloc_printf("%s", frida_binary);
} }
// 释放 frida_binary 的内存
ck_free(frida_binary); ck_free(frida_binary);
// 设置 LD_PRELOAD 和 DYLD_INSERT_LIBRARIES 环境变量
setenv("LD_PRELOAD", frida_afl_preload, 1); setenv("LD_PRELOAD", frida_afl_preload, 1);
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
@ -718,22 +719,23 @@ static void set_up_environment(char **argv) {
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
} }
// 如果没有设置 AFL_PRELOAD但处于 frida 模式
} else if (frida_mode) { } else if (frida_mode) {
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
setenv("LD_PRELOAD", frida_binary, 1); setenv("LD_PRELOAD", frida_binary, 1);
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
ck_free(frida_binary); // 释放 frida_binary 的内存
ck_free(frida_binary);
} }
// 如果 frida_afl_preload 被分配了,释放其内存
if (frida_afl_preload) { ck_free(frida_afl_preload); } if (frida_afl_preload) { ck_free(frida_afl_preload); }
} }
/* Setup signal handlers, duh. */ /* Setup signal handlers, duh. */
//设置信号处理程序,进行初始化 //设置程序的信号处理机制,通过设置 sa.sa_mask 和 sa.sa_flags确保程序行为符合预期。
static void setup_signal_handlers(void) { static void setup_signal_handlers(void) {
struct sigaction sa; struct sigaction sa;
@ -758,7 +760,7 @@ static void setup_signal_handlers(void) {
} }
/* Display usage hints. */ /* Display usage hints. */
//当用户输入-h时调用此函数回显该工具的使用方法 //用户指引手册
static void usage(u8 *argv0) { static void usage(u8 *argv0) {
SAYF( SAYF(
@ -815,40 +817,42 @@ static void usage(u8 *argv0) {
} }
/* Main entry point */ /* Main entry point */
//main函数用户使用的实际接口
int main(int argc, char **argv_orig, char **envp) { int main(int argc, char **argv_orig, char **envp) {
s32 opt; s32 opt;
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
char **use_argv; char **use_argv;
char **argv = argv_cpy_dup(argc, argv_orig); char **argv = argv_cpy_dup(argc, argv_orig);
// 检查文档路径是否存在,如果不存在,使用默认的文档路径
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
// 输出程序的基本信息
SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n");
// 初始化文件服务
afl_fsrv_init(&fsrv); afl_fsrv_init(&fsrv);
// 解析命令行参数
while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) { while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
switch (opt) { switch (opt) {
case 'i': case 'i':
// 检查是否重复指定
if (in_file) { FATAL("Multiple -i options not supported"); } if (in_file) { FATAL("Multiple -i options not supported"); }
in_file = optarg; in_file = optarg;
break; break;
case 'f': case 'f':
// 检查是否重复指定
if (fsrv.out_file) { FATAL("Multiple -f options not supported"); } if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
// 不使用标准输入
fsrv.use_stdin = 0; fsrv.use_stdin = 0;
fsrv.out_file = ck_strdup(optarg); fsrv.out_file = ck_strdup(optarg);
break; break;
// 仅边缘分析
case 'e': case 'e':
if (edges_only) { FATAL("Multiple -e options not supported"); } if (edges_only) { FATAL("Multiple -e options not supported"); }
// 启用仅边缘分析
edges_only = 1; edges_only = 1;
break; break;
@ -857,25 +861,26 @@ int main(int argc, char **argv_orig, char **envp) {
u8 suffix = 'M'; u8 suffix = 'M';
if (mem_limit_given) { FATAL("Multiple -m options not supported"); } if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
// 设置标志表示已给定内存限制
mem_limit_given = 1; mem_limit_given = 1;
// 检查参数有效性
if (!optarg) { FATAL("Wrong usage of -m"); } if (!optarg) { FATAL("Wrong usage of -m"); }
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
// 如果指定为 none设定内存限制为 0
mem_limit = 0; mem_limit = 0;
fsrv.mem_limit = 0; fsrv.mem_limit = 0;
break; break;
} }
// 读取内存限制值
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') { optarg[0] == '-') {
FATAL("Bad syntax used for -m"); FATAL("Bad syntax used for -m");
} }
// 判定单位并转换为字节
switch (suffix) { switch (suffix) {
case 'T': case 'T':
@ -894,15 +899,15 @@ int main(int argc, char **argv_orig, char **envp) {
FATAL("Unsupported suffix or bad syntax for -m"); FATAL("Unsupported suffix or bad syntax for -m");
} }
// 防止设置过低的限制
if (mem_limit < 5) { FATAL("Dangerously low value of -m"); } if (mem_limit < 5) { FATAL("Dangerously low value of -m"); }
if (sizeof(rlim_t) == 4 && mem_limit > 2000) { if (sizeof(rlim_t) == 4 && mem_limit > 2000) {
// 针对 32 位系统的范围检查
FATAL("Value of -m out of range on 32-bit systems"); FATAL("Value of -m out of range on 32-bit systems");
} }
// 设置文件服务的内存限制
fsrv.mem_limit = mem_limit; fsrv.mem_limit = mem_limit;
} }
@ -1009,27 +1014,30 @@ int main(int argc, char **argv_orig, char **envp) {
} }
} }
// 检查是否提供了有效的输入文件
if (optind == argc || !in_file) { usage(argv[0]); } if (optind == argc || !in_file) { usage(argv[0]); }
// 获取映射大小并更新文件服务结构
map_size = get_map_size(); map_size = get_map_size();
fsrv.map_size = map_size; fsrv.map_size = map_size;
use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX"); use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
// 检查环境变量
check_environment_vars(envp); check_environment_vars(envp);
// 初始化共享内存结构
sharedmem_t shm = {0}; sharedmem_t shm = {0};
/* initialize cmplog_mode */ /* initialize cmplog_mode */
// 初始化 cmplog_mode
shm.cmplog_mode = 0; shm.cmplog_mode = 0;
// 注册退出处理函数
atexit(at_exit_handler); atexit(at_exit_handler);
// 设置信号处理函数
setup_signal_handlers(); setup_signal_handlers();
// 设置环境
set_up_environment(argv); set_up_environment(argv);
#ifdef __linux__ #ifdef __linux__
// 根据模式查找目标路径
if (!fsrv.nyx_mode) { if (!fsrv.nyx_mode) {
fsrv.target_path = find_binary(argv[optind]); fsrv.target_path = find_binary(argv[optind]);
@ -1043,11 +1051,13 @@ int main(int argc, char **argv_orig, char **envp) {
#else #else
fsrv.target_path = find_binary(argv[optind]); fsrv.target_path = find_binary(argv[optind]);
#endif #endif
// 初始化共享内存和跟踪位图
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
// 检测后续文件参数
detect_file_args(argv + optind, fsrv.out_file, &use_stdin); detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
// 设置超时信号的处理
signal(SIGALRM, kill_child); signal(SIGALRM, kill_child);
// 根据所选模式准备命令行参数
if (qemu_mode) { if (qemu_mode) {
if (use_wine) { if (use_wine) {
@ -1073,14 +1083,16 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv.nyx_id = 0; fsrv.nyx_id = 0;
u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
// 加载插件
fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
if (fsrv.nyx_handlers == NULL) { if (fsrv.nyx_handlers == NULL) {
FATAL("failed to initialize libnyx.so..."); FATAL("failed to initialize libnyx.so...");
} }
// 使用临时工作目录
fsrv.nyx_use_tmp_workdir = true; fsrv.nyx_use_tmp_workdir = true;
// 绑定 CPU ID
fsrv.nyx_bind_cpu_id = 0; fsrv.nyx_bind_cpu_id = 0;
use_argv = argv + optind; use_argv = argv + optind;
@ -1091,27 +1103,28 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv = argv + optind; use_argv = argv + optind;
} }
// 输出干运行的相关信息
SAYF("\n"); SAYF("\n");
if (getenv("AFL_FORKSRV_INIT_TMOUT")) { if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
if (forksrv_init_tmout < 1) { if (forksrv_init_tmout < 1) {
// 检查初始化超时配置
FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
} }
// 设置初始化超时
fsrv.init_tmout = (u32)forksrv_init_tmout; fsrv.init_tmout = (u32)forksrv_init_tmout;
} }
// 配置终止信号
configure_afl_kill_signals( configure_afl_kill_signals(
&fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM); &fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
// 读取初始文件
read_initial_file(); read_initial_file();
#ifdef __linux__ #ifdef __linux__
// 检查二进制签名
if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); } if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
#else #else
(void)check_binary_signatures(fsrv.target_path); (void)check_binary_signatures(fsrv.target_path);
@ -1119,29 +1132,33 @@ int main(int argc, char **argv_orig, char **envp) {
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
mem_limit, exec_tmout, edges_only ? ", edges only" : ""); mem_limit, exec_tmout, edges_only ? ", edges only" : "");
// 启动文件服务
afl_fsrv_start(&fsrv, use_argv, &stop_soon, false); afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
// 分析目标
analyze_run_target(in_data, in_len, 1); analyze_run_target(in_data, in_len, 1);
if (fsrv.last_run_timed_out) { if (fsrv.last_run_timed_out) {
// 检查执行超时
FATAL("Target binary times out (adjusting -t may help)."); FATAL("Target binary times out (adjusting -t may help).");
} }
// 检查是否进行过检测
if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) { if (get_afl_env("AFL_SKIP_BIN_CHECK") == NULL && !anything_set()) {
FATAL("No instrumentation detected."); FATAL("No instrumentation detected.");
} }
// 调用分析函数(主要功能接口
analyze(); analyze();
OKF("We're done here. Have a nice day!\n"); OKF("We're done here. Have a nice day!\n");
// 释放共享内存
afl_shm_deinit(&shm); afl_shm_deinit(&shm);
// 释放文件服务
afl_fsrv_deinit(&fsrv); afl_fsrv_deinit(&fsrv);
// 释放目标路径
if (fsrv.target_path) { ck_free(fsrv.target_path); } if (fsrv.target_path) { ck_free(fsrv.target_path); }
// 释放输入数据
if (in_data) { ck_free(in_data); } if (in_data) { ck_free(in_data); }
exit(0); exit(0);

@ -91,116 +91,170 @@ static u8 use_64bit = 0;
to keep the code simple. */ to keep the code simple. */
static void edit_params(int argc, char **argv) { static void edit_params(int argc, char **argv) {
// 获取临时目录路径和AFL_AS环境变量
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS"); u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
u32 i, input_index; u32 i, input_index;
#ifdef __APPLE__ #ifdef __APPLE__
u8 use_clang_as = 0; u8 use_clang_as = 0;
// 在MacOS下若使用clang且没有设置AFL_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: https://goo.gl/HBWDtn.
To work around this, when using clang and running without AFL_AS
specified, we will actually call 'clang -c' instead of 'as -q' to
compile the assembly file.
The tools aren't cmdline-compatible, but at least for now, we can
seemingly get away with this by making only very minor tweaks. Thanks
to Nico Weber for the idea. */
if (clang_mode && !afl_as) { if (clang_mode && !afl_as) {
use_clang_as = 1; use_clang_as = 1;
afl_as = getenv("AFL_CC"); // 获取AFL_CC环境变量
if (!afl_as) afl_as = getenv("AFL_CXX"); // 获取AFL_CXX环境变量 afl_as = getenv("AFL_CC");
if (!afl_as) afl_as = "clang"; // 默认使用clang if (!afl_as) afl_as = getenv("AFL_CXX");
if (!afl_as) afl_as = "clang";
} }
#endif
// 如果TMPDIR环境变量为空尝试从TEMP和TMP获取临时目录 #endif /* __APPLE__ */
/* 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. */
if (!tmp_dir) { tmp_dir = getenv("TEMP"); } if (!tmp_dir) { tmp_dir = getenv("TEMP"); }
if (!tmp_dir) { tmp_dir = getenv("TMP"); } if (!tmp_dir) { tmp_dir = getenv("TMP"); }
if (!tmp_dir) { tmp_dir = "/tmp"; } // 默认临时目录为"/tmp" if (!tmp_dir) { tmp_dir = "/tmp"; }
// 为汇编参数分配内存,确保不会超过最大参数个数
as_params = ck_alloc((argc + 32) * sizeof(u8 *)); as_params = ck_alloc((argc + 32) * sizeof(u8 *));
if (unlikely((INT_MAX - 32) < argc || !as_params)) { if (unlikely((INT_MAX - 32) < argc || !as_params)) {
FATAL("Too many parameters passed to as"); // 参数过多,终止
FATAL("Too many parameters passed to as");
} }
// 设置汇编器命令
as_params[0] = afl_as ? afl_as : (u8 *)"as"; as_params[0] = afl_as ? afl_as : (u8 *)"as";
as_params[argc] = 0; as_params[argc] = 0;
// 查找输入文件,通常位于命令行参数的最后 /* Find the input file. It's usually located near the end.
Assume there won't be any arguments referring to files after the input
file, e.g. as input.s -o output.o */
for (input_index = argc - 1; input_index > 0; input_index--) { for (input_index = argc - 1; input_index > 0; input_index--) {
input_file = argv[input_index]; input_file = argv[input_index];
// 如果遇到调试选项,跳过 /* Clang may add debug arguments after the input file. */
if (strncmp(input_file, "-g", 2)) break; if (strncmp(input_file, "-g", 2)) break;
} }
// 如果没有找到输入文件,输出错误信息
if (input_index == 0) if (input_index == 0)
FATAL("Could not find input file (not called through afl-gcc?)"); FATAL("Could not find input file (not called through afl-gcc?)");
// 遍历参数,处理与汇编相关的选项
for (i = 1; (s32)i < argc; i++) { for (i = 1; (s32)i < argc; i++) {
if (i == input_index) continue; // 跳过输入文件
// 处理64位和32位选项 if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) { if (!strcmp(argv[i], "--64")) {
use_64bit = 1; use_64bit = 1;
} else if (!strcmp(argv[i], "--32")) { } else if (!strcmp(argv[i], "--32")) {
use_64bit = 0; use_64bit = 0;
} }
#ifdef __APPLE__ #ifdef __APPLE__
// 在MacOS下处理架构选项
/* The Apple case is a bit different... */
if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) { if (!strcmp(argv[i], "-arch") && i + 1 < (u32)argc) {
if (!strcmp(argv[i + 1], "x86_64")) if (!strcmp(argv[i + 1], "x86_64"))
use_64bit = 1; use_64bit = 1;
else if (!strcmp(argv[i + 1], "i386")) else if (!strcmp(argv[i + 1], "i386"))
FATAL("Sorry, 32-bit Apple platforms are not supported."); FATAL("Sorry, 32-bit Apple platforms are not supported.");
} }
#endif
// 跳过不相关的选项 /* Strip options that set the preference for a particular upstream
assembler in Xcode. */
if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q"))) if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
continue; continue;
// 将参数添加到汇编器参数列表 #endif /* __APPLE__ */
as_params[as_par_cnt++] = argv[i]; as_params[as_par_cnt++] = argv[i];
} }
#ifdef __APPLE__ #ifdef __APPLE__
// 如果使用clang作为汇编器追加相关选项
/* When calling clang as the upstream assembler, append -c -x assembler
and hope for the best. */
if (use_clang_as) { if (use_clang_as) {
as_params[as_par_cnt++] = "-c"; as_params[as_par_cnt++] = "-c";
as_params[as_par_cnt++] = "-x"; as_params[as_par_cnt++] = "-x";
as_params[as_par_cnt++] = "assembler"; as_params[as_par_cnt++] = "assembler";
} }
#endif
// 如果输入文件是"-"参数,检查是否为版本信息 #endif /* __APPLE__ */
if (input_file[0] == '-') { if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) { if (!strcmp(input_file + 1, "-version")) {
just_version = 1; just_version = 1;
modified_file = input_file; modified_file = input_file;
goto wrap_things_up; // 跳到结束处理 goto wrap_things_up;
} }
if (input_file[1]) { if (input_file[1]) {
FATAL("Incorrect use (not called through afl-gcc?)"); FATAL("Incorrect use (not called through afl-gcc?)");
} else { } else {
input_file = NULL; // 没有文件参数
input_file = NULL;
} }
} else { } 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. */
if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) && if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
strncmp(input_file, "/var/tmp/", 9) && strncmp(input_file, "/var/tmp/", 9) &&
strncmp(input_file, "/tmp/", 5) && strncmp(input_file, "/tmp/", 5) &&
getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) { getenv("AFL_AS_FORCE_INSTRUMENT") == NULL) {
pass_thru = 1; pass_thru = 1;
} else if (getenv("AFL_AS_FORCE_INSTRUMENT")) { } else if (getenv("AFL_AS_FORCE_INSTRUMENT")) {
unsetenv("AFL_AS_FORCE_INSTRUMENT"); // 强制插桩的环境变量取消
unsetenv("AFL_AS_FORCE_INSTRUMENT");
} }
} }
// 为汇编文件生成一个唯一的临时文件名
modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(), modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
(u32)time(NULL), (u32)random()); (u32)time(NULL), (u32)random());
}
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
wrap_things_up: wrap_things_up:
as_params[as_par_cnt++] = modified_file; as_params[as_par_cnt++] = modified_file;
@ -224,13 +278,9 @@ static void add_instrumentation(void) {
skip_app = 0, instrument_next = 0; skip_app = 0, instrument_next = 0;
#ifdef __APPLE__ #ifdef __APPLE__
<<<<<<< HEAD
u8 *colon_pos;
=======
u8 *colon_pos; u8 *colon_pos;
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
#endif /* __APPLE__ */ #endif /* __APPLE__ */
if (input_file) { if (input_file) {
@ -253,6 +303,12 @@ static void add_instrumentation(void) {
if (!outf) { PFATAL("fdopen() failed"); } if (!outf) { PFATAL("fdopen() failed"); }
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 && if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok &&
instrument_next && line[0] == '\t' && isalpha(line[1])) { instrument_next && line[0] == '\t' && isalpha(line[1])) {

@ -1895,132 +1895,125 @@ param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
these have_*, otherwise they may not work as expected. these have_*, otherwise they may not work as expected.
*/ */
void add_sanitizers(aflcc_state_t *aflcc, char **envp) { void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
// 如果启用了 ASAN (地址消毒器),则进行相关配置
if (getenv("AFL_USE_ASAN") || aflcc->have_asan) { if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
// 如果同时启用了 MSAN (内存消毒器),则报错,因为 ASAN 和 MSAN 不能同时使用
if (getenv("AFL_USE_MSAN") || aflcc->have_msan) if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN and MSAN are mutually exclusive");
// 如果启用了 AFL_HARDEN则报错因为 ASAN 和 AFL_HARDEN 不能同时使用
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive"); FATAL("ASAN and AFL_HARDEN are mutually exclusive");
// 如果是 GCC 插件模式,并且没有启用静态 ASAN 库,则添加静态 ASAN 库的选项
if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) { if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
insert_param(aflcc, "-static-libasan"); insert_param(aflcc, "-static-libasan");
} }
// 添加 fortify 配置0表示没有额外的强化
add_defs_fortify(aflcc, 0); add_defs_fortify(aflcc, 0);
// 如果没有启用 ASAN则添加相应的编译选项来启用地址消毒
if (!aflcc->have_asan) { if (!aflcc->have_asan) {
insert_param(aflcc, "-fsanitize=address"); insert_param(aflcc, "-fsanitize=address");
insert_param(aflcc, "-fno-common"); insert_param(aflcc, "-fno-common");
} }
aflcc->have_asan = 1; // 标记已经启用了 ASAN aflcc->have_asan = 1;
}
// 如果启用了 MSAN (内存消毒器),则进行相关配置 } else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
// 如果同时启用了 ASAN则报错因为 ASAN 和 MSAN 不能同时使用
if (getenv("AFL_USE_ASAN") || aflcc->have_asan) if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
FATAL("ASAN and MSAN are mutually exclusive"); FATAL("ASAN and MSAN are mutually exclusive");
// 如果启用了 AFL_HARDEN则报错因为 MSAN 和 AFL_HARDEN 不能同时使用
if (getenv("AFL_HARDEN")) if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive"); FATAL("MSAN and AFL_HARDEN are mutually exclusive");
// 添加 fortify 配置0表示没有额外的强化
add_defs_fortify(aflcc, 0); add_defs_fortify(aflcc, 0);
// 如果没有启用 MSAN则添加相应的编译选项来启用内存消毒
if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); } if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
aflcc->have_msan = 1;
aflcc->have_msan = 1; // 标记已经启用了 MSAN
} }
// 如果启用了 UBSAN (未定义行为消毒器),则进行相关配置
if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) { if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
// 如果没有启用 UBSAN则添加相应的编译选项来启用未定义行为消毒
if (!aflcc->have_ubsan) { if (!aflcc->have_ubsan) {
insert_param(aflcc, "-fsanitize=undefined"); insert_param(aflcc, "-fsanitize=undefined");
insert_param(aflcc, "-fsanitize-undefined-trap-on-error"); insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
insert_param(aflcc, "-fno-sanitize-recover=all"); insert_param(aflcc, "-fno-sanitize-recover=all");
} }
// 如果没有启用帧指针,则添加相应的选项来启用帧指针
if (!aflcc->have_fp) { if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer"); insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1; aflcc->have_fp = 1;
} }
aflcc->have_ubsan = 1; // 标记已经启用了 UBSAN aflcc->have_ubsan = 1;
} }
// 如果启用了 TSAN (线程消毒器),则进行相关配置
if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) { if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
// 如果没有启用帧指针,则添加相应的选项来启用帧指针
if (!aflcc->have_fp) { if (!aflcc->have_fp) {
insert_param(aflcc, "-fno-omit-frame-pointer"); insert_param(aflcc, "-fno-omit-frame-pointer");
aflcc->have_fp = 1; aflcc->have_fp = 1;
} }
// 如果没有启用 TSAN则添加相应的编译选项来启用线程消毒
if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); } if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
aflcc->have_tsan = 1;
aflcc->have_tsan = 1; // 标记已经启用了 TSAN
} }
// 如果启用了 LSAN (泄漏消毒器),则进行相关配置
if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) { if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
// 添加编译选项来启用泄漏消毒
insert_param(aflcc, "-fsanitize=leak"); insert_param(aflcc, "-fsanitize=leak");
// 添加 LSAN 控制的定义
add_defs_lsan_ctrl(aflcc); add_defs_lsan_ctrl(aflcc);
aflcc->have_lsan = 1;
aflcc->have_lsan = 1; // 标记已经启用了 LSAN
} }
// 如果启用了 CFISAN (控制流完整性消毒器),则进行相关配置
if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) { if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
// 如果是 GCC 插件模式或 GCC 模式,则启用完整的控制流保护
if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) { if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
// 如果没有启用控制流保护,则添加相应选项
if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); } if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
} else { } else {
// 如果没有启用 LTO (链接时优化),则添加 LTO 选项
if (!aflcc->lto_mode && !aflcc->have_flto) { if (!aflcc->lto_mode && !aflcc->have_flto) {
uint32_t i = 0, found = 0; uint32_t i = 0, found = 0;
while (envp[i] != NULL && !found) { while (envp[i] != NULL && !found) {
if (strncmp("-flto", envp[i++], 5) == 0) found = 1; if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
} }
if (!found) { insert_param(aflcc, "-flto"); } if (!found) { insert_param(aflcc, "-flto"); }
aflcc->have_flto = 1; // 标记已经启用了 LTO aflcc->have_flto = 1;
} }
// 如果没有启用 CFISAN则添加相应选项来启用控制流完整性消毒
if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); } if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
// 如果没有启用隐藏符号,则启用隐藏符号选项
if (!aflcc->have_hidden) { if (!aflcc->have_hidden) {
insert_param(aflcc, "-fvisibility=hidden"); insert_param(aflcc, "-fvisibility=hidden");
aflcc->have_hidden = 1; aflcc->have_hidden = 1;
} }
aflcc->have_cfisan = 1; // 标记已经启用了 CFISAN aflcc->have_cfisan = 1;
} }
} }
} }
/* Add params to enable LLVM SanCov, the native PCGUARD */ /* Add params to enable LLVM SanCov, the native PCGUARD */
@ -2571,13 +2564,10 @@ void add_gcc_plugin(aflcc_state_t *aflcc) {
/* Add some miscellaneous params required by our instrumentation. */ /* Add some miscellaneous params required by our instrumentation. */
void add_misc_params(aflcc_state_t *aflcc) { void add_misc_params(aflcc_state_t *aflcc) {
// 如果环境变量 AFl_NO_BUILTIN 或其他相关环境变量被设置,或者启用了 LTO 模式
// 则禁用内置的字符串和内存比较函数
if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") || if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") || getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
aflcc->lto_mode) { aflcc->lto_mode) {
// 禁用常见的字符串和内存比较函数的内置实现,防止与模糊测试产生冲突
insert_param(aflcc, "-fno-builtin-strcmp"); insert_param(aflcc, "-fno-builtin-strcmp");
insert_param(aflcc, "-fno-builtin-strncmp"); insert_param(aflcc, "-fno-builtin-strncmp");
insert_param(aflcc, "-fno-builtin-strcasecmp"); insert_param(aflcc, "-fno-builtin-strcasecmp");
@ -2589,46 +2579,31 @@ void add_misc_params(aflcc_state_t *aflcc) {
} }
// 如果没有启用位置无关代码PIC则添加 -fPIC 参数 if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
if (!aflcc->have_pic) {
insert_param(aflcc, "-fPIC");
}
// 如果环境变量 AFL_HARDEN 被设置,启用栈保护等安全选项
if (getenv("AFL_HARDEN")) { if (getenv("AFL_HARDEN")) {
// 启用所有函数的栈保护
insert_param(aflcc, "-fstack-protector-all"); insert_param(aflcc, "-fstack-protector-all");
// 如果未设置 Fortify设置 Fortify 防护等级 if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
if (!aflcc->fortify_set)
add_defs_fortify(aflcc, 2);
} }
// 如果环境变量 AFL_DONT_OPTIMIZE 未设置,启用优化选项
if (!getenv("AFL_DONT_OPTIMIZE")) { if (!getenv("AFL_DONT_OPTIMIZE")) {
// 启用调试符号生成
insert_param(aflcc, "-g"); insert_param(aflcc, "-g");
if (!aflcc->have_o) insert_param(aflcc, "-O3");
// 如果没有设置 -O 优化级别,设置为 -O3最高优化 if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
if (!aflcc->have_o)
insert_param(aflcc, "-O3");
// 如果没有设置循环展开,启用循环展开优化
if (!aflcc->have_unroll)
insert_param(aflcc, "-funroll-loops");
// 以下代码被注释掉了,但如果有指定架构优化选项(如 -march也可以启用
// if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-') // if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
// insert_param(aflcc, aflcc->march_opt); // insert_param(aflcc, aflcc->march_opt);
} }
// 如果设置了 x_set 标志,插入 -x none 参数
if (aflcc->x_set) { if (aflcc->x_set) {
insert_param(aflcc, "-x"); insert_param(aflcc, "-x");
insert_param(aflcc, "none"); insert_param(aflcc, "none");
} }
} }
@ -3107,44 +3082,6 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc, static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
char **argv) { char **argv) {
<<<<<<< HEAD
u8 skip_next = 0;
while (--argc) {
u8 *cur = *(++argv);
if (skip_next > 0) {
skip_next--;
continue;
}
if (PARAM_MISS != parse_misc_params(aflcc, cur, scan)) continue;
if (PARAM_MISS != parse_fsanitize(aflcc, cur, scan)) continue;
if (PARAM_MISS != parse_linking_params(aflcc, cur, scan, &skip_next, argv))
continue;
if (*cur == '@') {
u8 *filename = cur + 1;
if (aflcc->debug) { DEBUGF("response file=%s\n", filename); }
FILE *f = fopen(filename, "r");
if (!f) {
if (!scan) insert_param(aflcc, cur);
continue;
}
struct stat st;
if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode) || st.st_size < 1) {
fclose(f);
if (!scan) insert_param(aflcc, cur);
continue;
}
static u32 rsp_count = 2000;
if (scan) {
if (rsp_count == 0) FATAL("Too many response files provided!");
--rsp_count;
}
u32 argc_read = 1;
char **argv_read = ck_alloc(sizeof(char *));
argv_read[0] = "";
char *arg_buf = NULL;
u64 arg_len = 0;
enum fsm_state {
=======
// for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]); // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
/* Process the argument list. */ /* Process the argument list. */
@ -3230,20 +3167,15 @@ static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
enum fsm_state { enum fsm_state {
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
fsm_whitespace, // whitespace seen so far fsm_whitespace, // whitespace seen so far
fsm_double_quote, // have unpaired double quote fsm_double_quote, // have unpaired double quote
fsm_single_quote, // have unpaired single quote fsm_single_quote, // have unpaired single quote
fsm_backslash, // a backslash is seen with no unpaired quote fsm_backslash, // a backslash is seen with no unpaired quote
fsm_normal // a normal char is seen fsm_normal // a normal char is seen
<<<<<<< HEAD
};
=======
}; };
// Workaround to append c to arg buffer, and append the buffer to argv // Workaround to append c to arg buffer, and append the buffer to argv
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
#define ARG_ALLOC(c) \ #define ARG_ALLOC(c) \
do { \ do { \
\ \
@ -3426,54 +3358,6 @@ static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
/* Process each of the existing argv, also add a few new args. */ /* Process each of the existing argv, also add a few new args. */
static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv, static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
char **envp) { char **envp) {
<<<<<<< HEAD
add_real_argv0(aflcc);
if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC) {
insert_param(aflcc, "-Wno-unused-command-line-argument");
}
if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) {
add_assembler(aflcc);
}
if (aflcc->compiler_mode == GCC_PLUGIN) { add_gcc_plugin(aflcc); }
if (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == LTO) {
if (aflcc->lto_mode && aflcc->have_instr_env) {
load_llvm_pass(aflcc, "afl-llvm-lto-instrumentlist.so");
}
if (getenv("AFL_LLVM_DICT2FILE")) {
load_llvm_pass(aflcc, "afl-llvm-dict2file.so");
}
if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
load_llvm_pass(aflcc, "split-switches-pass.so");
}
if (getenv("LAF_TRANSFORM_COMPARES") ||
getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
load_llvm_pass(aflcc, "compare-transform-pass.so");
}
if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
load_llvm_pass(aflcc, "split-compares-pass.so");
}
if (aflcc->cmplog_mode) {
insert_param(aflcc, "-fno-inline");
load_llvm_pass(aflcc, "cmplog-switches-pass.so");
load_llvm_pass(aflcc, "split-switches-pass.so");
}
if (aflcc->lto_mode) {
insert_param(aflcc, aflcc->lto_flag);
if (!aflcc->have_c) {
add_lto_linker(aflcc);
add_lto_passes(aflcc);
}
} else {
if (aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
add_optimized_pcguard(aflcc);
} else if (aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
add_native_pcguard(aflcc);
} else {
load_llvm_pass(aflcc, "afl-llvm-pass.so");
}
}
=======
add_real_argv0(aflcc); add_real_argv0(aflcc);
@ -3573,7 +3457,6 @@ static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
} }
>>>>>>> e12b99bad19de97a02e9fe14b9b2c048338b2ab7
if (aflcc->cmplog_mode) { if (aflcc->cmplog_mode) {
load_llvm_pass(aflcc, "cmplog-instructions-pass.so"); load_llvm_pass(aflcc, "cmplog-instructions-pass.so");
@ -3613,86 +3496,50 @@ static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
} }
/* Main entry point */ /* Main entry point */
classDiagram int main(int argc, char **argv, char **envp) {
class AFLCCMain {
+main(argc, argv, envp)
+initializeState()
+checkEnvironmentVariables()
+findDependencies()
+determineCompilerMode()
+determineInstrumentationMode()
+finalizeMode()
+processParameters()
+maybeShowUsage()
+notifyMode()
+debugArguments()
+editParameters()
+executeCompiler()
}
class AFLCCState { aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
-cc_params: char** aflcc_state_init(aflcc, (u8 *)argv[0]);
-cc_par_cnt: u32
-passthrough: u8
-debug: u8
+aflcc_state_init(state, prog_name)
}
class EnvironmentChecker { check_environment_vars(envp);
+check_environment_vars(envp)
}
class DependencyFinder { find_built_deps(aflcc);
+find_built_deps(aflcc)
}
class CompilerModeHandler { compiler_mode_by_callname(aflcc);
+compiler_mode_by_callname(aflcc) compiler_mode_by_environ(aflcc);
+compiler_mode_by_environ(aflcc) compiler_mode_by_cmdline(aflcc, argc, argv);
+compiler_mode_by_cmdline(aflcc, argc, argv)
}
class InstrumentationModeHandler { instrument_mode_by_environ(aflcc);
+instrument_mode_by_environ(aflcc)
}
class ModeFinalizer { mode_final_checkout(aflcc, argc, argv);
+mode_final_checkout(aflcc, argc, argv)
}
class ParameterProcessor { process_params(aflcc, 1, argc, argv);
+process_params(aflcc, start_idx, argc, argv)
}
class UsageNotifier { maybe_usage(aflcc, argc, argv);
+maybe_usage(aflcc, argc, argv)
}
class ModeNotifier { mode_notification(aflcc);
+mode_notification(aflcc)
}
class Debugger { if (aflcc->debug) debugf_args(argc, argv);
+debugf_args(argc, argv)
}
class ParameterEditor { edit_params(aflcc, argc, argv, envp);
+edit_params(aflcc, argc, argv, envp)
}
class Executor { if (aflcc->debug)
+execute_compiler(aflcc, argv) debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
}
if (aflcc->passthrough) {
argv[0] = aflcc->cc_params[0];
execvp(aflcc->cc_params[0], (char **)argv);
} else {
execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
}
FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
return 0;
}
AFLCCMain --> AFLCCState : 使
AFLCCMain --> EnvironmentChecker : 使
AFLCCMain --> DependencyFinder : 使
AFLCCMain --> CompilerModeHandler : 使
AFLCCMain --> InstrumentationModeHandler : 使
AFLCCMain --> ModeFinalizer : 使
AFLCCMain --> ParameterProcessor : 使
AFLCCMain --> UsageNotifier : 使
AFLCCMain --> ModeNotifier : 使
AFLCCMain --> Debugger : 使
AFLCCMain --> ParameterEditor : 使
AFLCCMain --> Executor : 使

File diff suppressed because it is too large Load Diff

@ -23,8 +23,6 @@
how they affect the execution path. how they affect the execution path.
*/ */
//引入了 AFL++ 的核心头文件、CMPLog 相关头文件、通用函数头文件等。
//根据编译选项,可能还会包含其他系统头文件,如内存映射、文件操作等。
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "cmplog.h" #include "cmplog.h"
@ -84,9 +82,7 @@
\ \
\ \
} while (0) } while (0)
//定义了与 zlib 相关的宏,用于处理压缩文件的读写操作。
//对于苹果系统,引入了特定的头文件以支持线程优先级设置。
//如果启用了性能分析,则声明了一个外部变量 time_spent_working 用于记录工作时间
#include <zlib.h> #include <zlib.h>
#define ZLIBOPEN gzopen #define ZLIBOPEN gzopen
#define ZLIBREAD ck_gzread #define ZLIBREAD ck_gzread
@ -110,14 +106,13 @@
#ifdef PROFILING #ifdef PROFILING
extern u64 time_spent_working; extern u64 time_spent_working;
#endif #endif
//程序退出时的清理函数
static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用于清理资源和终止子进程 static void at_exit() {
//首先尝试获取环境变量 __AFL_TARGET_PID2 和 __AFL_TARGET_PID1这些变量存储了目标进程的 PID
s32 i, pid1 = 0, pid2 = 0, pgrp = -1; s32 i, pid1 = 0, pid2 = 0, pgrp = -1;
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL}; char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
char *ptr; char *ptr;
//如果找到有效的 PID则获取其进程组 ID 并向进程组发送 SIGTERM 信号以终止整个进程组,
//然后单独向目标进程发送 SIGTERM 信号。
ptr = getenv("__AFL_TARGET_PID2"); ptr = getenv("__AFL_TARGET_PID2");
if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) { if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {
@ -135,11 +130,10 @@ static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用
kill(pid1, SIGTERM); kill(pid1, SIGTERM);
} }
//尝试获取环境变量 CPU_AFFINITY_ENV_VAR如果存在且非空则删除该文件以解除 CPU 亲和性设置
ptr = getenv(CPU_AFFINITY_ENV_VAR); ptr = getenv(CPU_AFFINITY_ENV_VAR);
if (ptr && *ptr) unlink(ptr); if (ptr && *ptr) unlink(ptr);
//遍历 list 数组,获取每个环境变量的值,如果存在且非空,
//则根据编译选项使用不同的共享内存删除函数shm_unlink 或 shmctl来删除共享内存
i = 0; i = 0;
while (list[i] != NULL) { while (list[i] != NULL) {
@ -179,14 +173,13 @@ static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用,用
pgrp = getpgid(pid1); pgrp = getpgid(pid1);
if (pgrp > 0) { killpg(pgrp, kill_signal); } if (pgrp > 0) { killpg(pgrp, kill_signal); }
kill(pid2, kill_signal); kill(pid2, kill_signal);
//最后,获取环境变量 AFL_KILL_SIGNAL 的值作为要发送的信号类型(默认为 SIGKILL
//然后再次检查 PID1 和 PID2获取其进程组 ID 并向进程组发送相应的信号,单独向目标进程发送信号以确保其被终止
} }
} }
/* Display usage hints. */ /* Display usage hints. */
//主要为显示说明
static void usage(u8 *argv0, int more_help) { static void usage(u8 *argv0, int more_help) {
SAYF( SAYF(
@ -197,8 +190,7 @@ static void usage(u8 *argv0, int more_help) {
"also see \n" "also see \n"
" AFL_AUTORESUME)\n" " AFL_AUTORESUME)\n"
" -o dir - output directory for fuzzer findings\n\n" " -o dir - output directory for fuzzer findings\n\n"
//-i dir指定输入目录该目录包含用于模糊测试的测试用例。如果输入为 -,则表示恢复之前的模糊测试会话。
//-o dir指定输出目录用于存储模糊测试过程中发现的结果。
"Execution control settings:\n" "Execution control settings:\n"
" -P strategy - set fix mutation strategy: explore (focus on new " " -P strategy - set fix mutation strategy: explore (focus on new "
"coverage),\n" "coverage),\n"
@ -219,11 +211,6 @@ static void usage(u8 *argv0, int more_help) {
"maximum.\n" "maximum.\n"
" -m megs - memory limit for child process (%u MB, 0 = no limit " " -m megs - memory limit for child process (%u MB, 0 = no limit "
"[default])\n" "[default])\n"
//-P strategy设置固定的变异策略。可以选择 explore专注于发现新覆盖率或 exploit专注于触发崩溃。还可以设置在没有发现新结果时自动切换到 exploit 模式的时间(以秒为单位),并在发现新覆盖率时切换回 explore 模式。
//-p schedule设置功率调度策略用于计算种子的性能得分。可选的策略包括 explore默认、fast、exploit、seek、rare、mmopt、coe、lin 和 quad。具体的策略选择和效果可以参考 AFL++ 的文档。
//-f file指定被模糊测试程序读取的文件位置默认为标准输入或 @@。
//-t msec设置每次运行的超时时间自动缩放默认为指定的毫秒数。可以在超时值后加上 +,表示自动计算超时时间,指定的值为最大值。
//-m megs设置子进程的内存限制以兆字节为单位默认为 0表示不限制
#if defined(__linux__) && defined(__aarch64__) #if defined(__linux__) && defined(__aarch64__)
" -A - use binary-only instrumentation (ARM CoreSight mode)\n" " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
#endif #endif
@ -236,12 +223,6 @@ static void usage(u8 *argv0, int more_help) {
#if defined(__linux__) #if defined(__linux__)
" -X - use VM fuzzing (NYX mode - standalone mode)\n" " -X - use VM fuzzing (NYX mode - standalone mode)\n"
" -Y - use VM fuzzing (NYX mode - multiple instances mode)\n" " -Y - use VM fuzzing (NYX mode - multiple instances mode)\n"
//-A在 ARM 架构的 Linux 系统上使用二进制插桩ARM CoreSight 模式)。
//-O使用 FRIDA 模式进行二进制插桩。
//-Q在 Linux 系统上,使用 QEMU 模式进行二进制插桩。
//-U在 Linux 系统上,使用基于 Unicorn 的插桩Unicorn 模式)。
//-W在 Linux 系统上,使用基于 QEMU 和 Wine 的插桩Wine 模式)。
//-X 和 -Y在 Linux 系统上,使用 VM 模糊测试NYX 模式),分别支持独立模式和多实例模式。
#endif #endif
"\n" "\n"
@ -315,11 +296,10 @@ static void usage(u8 *argv0, int more_help) {
#if defined USE_COLOR && !defined ALWAYS_COLORED #if defined USE_COLOR && !defined ALWAYS_COLORED
#define DYN_COLOR \ #define DYN_COLOR \
"AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n" "AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
//定义了 USE_COLOR 但未定义 ALWAYS_COLORED则定义 DYN_COLOR 宏,用于提示用户如何关闭控制台的颜色输出
#else #else
#define DYN_COLOR #define DYN_COLOR
#endif #endif
//如果定义了 AFL_PERSISTENT_RECORD则定义 PERSISTENT_MSG 宏,用于提示用户 AFL_PERSISTENT_RECORD 环境变量的作用
#ifdef AFL_PERSISTENT_RECORD #ifdef AFL_PERSISTENT_RECORD
#define PERSISTENT_MSG \ #define PERSISTENT_MSG \
"AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \ "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
@ -328,7 +308,7 @@ static void usage(u8 *argv0, int more_help) {
#define PERSISTENT_MSG #define PERSISTENT_MSG
#endif #endif
SAYF(//用于输出详细的帮助信息,包括 AFL++ 使用的各种环境变量及其作用。 SAYF(
"Environment variables used:\n" "Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"ASAN_OPTIONS: custom settings for ASAN\n" "ASAN_OPTIONS: custom settings for ASAN\n"
@ -431,59 +411,7 @@ static void usage(u8 *argv0, int more_help) {
" seconds (default: 60, minimum: 1)\n" " seconds (default: 60, minimum: 1)\n"
"\n" "\n"
); );
/*
LD_BIND_LAZY AFL++ LD_BIND_NOW
ASAN_OPTIONS MSAN_OPTIONS ASAN MSAN AFL++
AFL_AUTORESUME
AFL_BENCH_JUST_ONE AFL_BENCH_UNTIL_CRASH退
AFL_CMPLOG_ONLY_NEW CMPLog
AFL_CRASH_EXITCODE AFL++ 退
AFL_CUSTOM_MUTATOR_LIBRARY AFL_CUSTOM_MUTATOR_ONLY使
AFL_CYCLE_SCHEDULES
AFL_DEBUG AFL_DEBUG_CHILD stdout/stderr
AFL_DISABLE_REDUNDANT AFL_DISABLE_TRIM
AFL_DUMB_FORKSRV使 fork
AFL_EXIT_WHEN_DONE AFL_EXIT_ON_TIME退退
AFL_EXIT_ON_SEED_ISSUES退
AFL_EXPAND_HAVOC_NOW Havoc
AFL_FAST_CAL
AFL_FORCE_UI
AFL_FORKSRV_INIT_TMOUT fork
AFL_HANG_TMOUT
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES
AFL_IGNORE_PROBLEMS AFL_IGNORE_PROBLEMS_COVERAGE
AFL_IGNORE_SEED_PROBLEMS AFL_IGNORE_TIMEOUTS退
AFL_IGNORE_UNKNOWN_ENVS
AFL_IMPORT_FIRST
AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX AFL++
AFL_PIZZA_MODE AFL++ 4 1
AFL_KILL_SIGNAL AFL_FORK_SERVER_KILL_SIGNAL fork ID
AFL_MAP_SIZE
AFL_MAX_DET_EXTRAS使
AFL_NO_AFFINITY AFL_TRY_AFFINITY使 CPU 使 CPU
AFL_NO_ARITH AFL_NO_AUTODICT
AFL_NO_CPU_RED AFL_NO_FORKSRV CPU 使 execve 使 fork
AFL_NO_SNAPSHOT AFL_NO_STARTUP_CALIBRATION使
AFL_NO_WARN_INSTABILITY AFL_NO_UI
AFL_NYX_AUX_SIZENyx 4096
AFL_NYX_DISABLE_SNAPSHOT_MODE AFL_NYX_LOG NYX hprintf
AFL_NYX_REUSE_SNAPSHOT Nyx
AFL_PATHAFL
AFL_PYTHON_MODULE使 Python
AFL_QUIET fork
AFL_POST_PROCESS_KEEP_ORIGINAL
AFL_PRELOAD LD_PRELOAD/DYLD_INSERT_LIBRARIES
AFL_TARGET_ENV
AFL_SHUFFLE_QUEUE
AFL_SKIP_BIN_CHECK AFL_SKIP_CPUFREQ AFL CPU
AFL_STATSD StatsD
AFL_NO_FASTRESUME AFL_NO_SYNC
AFL_SYNC_TIME AFL_FINAL_SYNC退
AFL_NO_CRASH_README README
AFL_TESTCACHE_SIZE AFL_TMPDIR
AFL_EARLY_FORKSERVER AFL_PERSISTENT AFL-clang-fast/AFL-clang-lto/AFL-gcc-fast fork
AFL_DEFER_FORKSRV fork __AFL_INIT
AFL_FUZZER_STATS_UPDATE_INTERVAL fuzzer_stats */
} else { } else {
SAYF( SAYF(
@ -495,56 +423,50 @@ AFL_FUZZER_STATS_UPDATE_INTERVAL更新 fuzzer_stats 文件的间隔(以秒
#ifdef USE_PYTHON #ifdef USE_PYTHON
SAYF("Compiled with %s module support, see docs/custom_mutators.md\n", SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION); (char *)PYTHON_VERSION);
/*
USE_PYTHON AFL++ 使 Python 使
AFL++ Python */
#else #else
SAYF("Compiled without Python module support.\n"); SAYF("Compiled without Python module support.\n");
#endif #endif
/*如果定义了 AFL_PERSISTENT_RECORD则输出 AFL++ 是使用持久记录支持编译的。
AFL++ */
#ifdef AFL_PERSISTENT_RECORD #ifdef AFL_PERSISTENT_RECORD
SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n"); SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
#else #else
SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n"); SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
#endif #endif
/*如果定义了 USEMMAP则输出 AFL++ 是使用 shm_open 支持编译的。
AFL++ 使 shmat */
#ifdef USEMMAP #ifdef USEMMAP
SAYF("Compiled with shm_open support.\n"); SAYF("Compiled with shm_open support.\n");
#else #else
SAYF("Compiled with shmat support.\n"); SAYF("Compiled with shmat support.\n");
#endif #endif
/*如果定义了 ASAN_BUILD则输出 AFL++ 是使用 ASAN 构建编译的。*/
#ifdef ASAN_BUILD #ifdef ASAN_BUILD
SAYF("Compiled with ASAN_BUILD.\n"); SAYF("Compiled with ASAN_BUILD.\n");
#endif #endif
/*如果定义了 NO_SPLICING则输出 AFL++ 是使用禁止拼接选项编译的*/
#ifdef NO_SPLICING #ifdef NO_SPLICING
SAYF("Compiled with NO_SPLICING.\n"); SAYF("Compiled with NO_SPLICING.\n");
#endif #endif
/*如果定义了 FANCY_BOXES_NO_UTF则输出 AFL++ 是没有 UTF-8 支持编译的,这会影响状态屏幕中的线条渲染。*/
#ifdef FANCY_BOXES_NO_UTF #ifdef FANCY_BOXES_NO_UTF
SAYF("Compiled without UTF-8 support for line rendering in status screen.\n"); SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
#endif #endif
/*如果定义了 PROFILING则输出 AFL++ 是使用性能分析编译的。*/
#ifdef PROFILING #ifdef PROFILING
SAYF("Compiled with PROFILING.\n"); SAYF("Compiled with PROFILING.\n");
#endif #endif
/*如果定义了 INTROSPECTION则输出 AFL++ 是使用自省编译的。*/
#ifdef INTROSPECTION #ifdef INTROSPECTION
SAYF("Compiled with INTROSPECTION.\n"); SAYF("Compiled with INTROSPECTION.\n");
#endif #endif
/*如果定义了 _DEBUG则输出 AFL++ 是使用调试模式编译的*/
#ifdef _DEBUG #ifdef _DEBUG
SAYF("Compiled with _DEBUG.\n"); SAYF("Compiled with _DEBUG.\n");
#endif #endif
/*如果定义了 _AFL_DOCUMENT_MUTATIONS则输出 AFL++ 是使用记录变异编译的。*/
#ifdef _AFL_DOCUMENT_MUTATIONS #ifdef _AFL_DOCUMENT_MUTATIONS
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n"); SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
#endif #endif
/*如果定义了 _AFL_SPECIAL_PERFORMANCE则输出 AFL++ 是使用特定系统的特殊性能选项编译的,并提醒用户这可能不适用于其他平台。*/
#ifdef _AFL_SPECIAL_PERFORMANCE #ifdef _AFL_SPECIAL_PERFORMANCE
SAYF( SAYF(
"Compiled with special performance options for this specific system, it " "Compiled with special performance options for this specific system, it "
@ -555,9 +477,7 @@ AFL_FUZZER_STATS_UPDATE_INTERVAL更新 fuzzer_stats 文件的间隔(以秒
exit(1); exit(1);
#undef PHYTON_SUPPORT #undef PHYTON_SUPPORT
/*额外帮助:输出提示信息,建议用户查阅 README.md 文件以获取更多帮助。
退 exit(1) 退 1 退
使 #undef PHYTON_SUPPORT PHYTON_SUPPORT PYTHON_SUPPORT*/
} }
#ifndef AFL_LIB #ifndef AFL_LIB
@ -624,10 +544,9 @@ static void fasan_check_afl_preload(char *afl_preload) {
int main(int argc, char **argv_orig, char **envp) { int main(int argc, char **argv_orig, char **envp) {
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;//用于存储 getopt 函数返回的选项字符 s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
u64 prev_queued = 0;//自动同步标志,初始值为 0。 u64 prev_queued = 0;
//用于记录上一次排队的项目数量。 u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, default_output = 1,
u32 sync_interval_cnt /*同步间隔计数器*/= 0, seek_to = 0, show_help = 0, default_output = 1,
map_size = get_map_size(); map_size = get_map_size();
u8 *extras_dir[4]; u8 *extras_dir[4];
u8 mem_limit_given = 0, exit_1 = 0, debug = 0, u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
@ -638,20 +557,9 @@ int main(int argc, char **argv_orig, char **envp) {
struct timeval tv; struct timeval tv;
struct timezone tz; struct timezone tz;
/*eek_to用于指定从哪个位置开始处理队列。
show_help
default_output 1
map_size get_map_size
extras_dir[4]
mem_limit_given
exit_1
debug
extras_dir_cnt
afl_preload frida_afl_preload AFL
use_argv
struct timeval tv struct timezone tz*/
doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH; doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
//根据 DOC_PATH 环境变量或默认路径 "docs" 初始化文档路径
if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) { if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {
printf("afl-fuzz" VERSION "\n"); printf("afl-fuzz" VERSION "\n");
@ -665,8 +573,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
exit(0); exit(0);
} }
/*版本信息:如果命令行参数包含 --version则输出 AFL++ 的版本信息并退出程序。
--help usage 退*/
#if defined USE_COLOR && defined ALWAYS_COLORED #if defined USE_COLOR && defined ALWAYS_COLORED
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) { if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
@ -675,11 +582,11 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
"compile time)"); "compile time)");
} }
/*颜色输出:如果定义了 USE_COLOR 和 ALWAYS_COLORED并且环境变量 AFL_NO_COLOR 或 AFL_NO_COLOUR 被设置,则输出警告信息,提示用户颜色设置在编译时已配置。*/
#endif #endif
char **argv = argv_cpy_dup(argc, argv_orig); char **argv = argv_cpy_dup(argc, argv_orig);
//argv_cpy_dup复制命令行参数数组以便在后续处理中使用
afl_state_t *afl = calloc(1, sizeof(afl_state_t)); afl_state_t *afl = calloc(1, sizeof(afl_state_t));
if (!afl) { FATAL("Could not create afl state"); } if (!afl) { FATAL("Could not create afl state"); }
@ -692,22 +599,15 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
read_afl_environment(afl, envp); read_afl_environment(afl, envp);
if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; } if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
exit_1 = !!afl->afl_env.afl_bench_just_one; exit_1 = !!afl->afl_env.afl_bench_just_one;
//SAYF输出 AFL++ 的版本信息和基于的原始 AFL 作者信息。
SAYF(cCYA "afl-fuzz" VERSION cRST SAYF(cCYA "afl-fuzz" VERSION cRST
" based on afl by Michal Zalewski and a large online community\n"); " based on afl by Michal Zalewski and a large online community\n");
//gettimeofday获取当前时间。
//rand_set_seed根据当前时间设置随机种子用于后续的随机数生成
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz);
rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid()); rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
//afl->shmem_testcase_mode设置为 1表示始终尝试使用共享内存进行模糊测试。
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
/*分配内存:为 afl_state_t 结构体分配内存,用于存储 AFL++ 的状态信息。
AFL_DEBUG
afl_state_init AFL
afl_fsrv_init
read_afl_environment AFL++
*/
// still available: HjJkKqruvwz // still available: HjJkKqruvwz
while ((opt = getopt(argc, argv, while ((opt = getopt(argc, argv,
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:" "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
@ -794,25 +694,12 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
FATAL("Bad syntax used for -b"); FATAL("Bad syntax used for -b");
} }
/*getopt 循环:使用 getopt 函数解析命令行选项。
-a "text""binary" "default"
-P "explore""exploit" "exploit"
-g
-G
-Z
-I
-b AFL++ CPU */
break; break;
} }
case 'c': { case 'c': {
/*-c 选项
CMPLog
"-" CMPLog CMPLog cmplog_binary NULL
"-" CMPLog cmplog_binary */
if (strcmp(optarg, "-") == 0) { if (strcmp(optarg, "-") == 0) {
@ -836,11 +723,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} }
case 's': { case 's': {
/*-s 选项
NULL
使 fixed_seed 1使*/
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); } if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
rand_set_seed(afl, strtoul(optarg, 0L, 10)); rand_set_seed(afl, strtoul(optarg, 0L, 10));
afl->fixed_seed = 1; afl->fixed_seed = 1;
@ -849,12 +732,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} }
case 'p': /* Power schedule */ case 'p': /* Power schedule */
/*-p 选项
afl->schedule FASTCOEEXPLOITLINQUADMMOPTRAREEXPLORE SEEK
*/
if (!stricmp(optarg, "fast")) { if (!stricmp(optarg, "fast")) {
afl->schedule = FAST; afl->schedule = FAST;
@ -906,11 +784,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'e': case 'e':
/*-e 选项
afl->file_extension -e
afl->file_extension */
if (afl->file_extension) { FATAL("Multiple -e options not supported"); } if (afl->file_extension) { FATAL("Multiple -e options not supported"); }
afl->file_extension = optarg; afl->file_extension = optarg;
@ -918,13 +792,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'i': /* input dir */ case 'i': /* input dir */
/*-i 选项
afl->in_dir -i
NULL -i
afl->in_dir
"-" afl->in_place_resume 1*/
if (afl->in_dir) { FATAL("Multiple -i options not supported"); } if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); } if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
afl->in_dir = optarg; afl->in_dir = optarg;
@ -934,28 +802,13 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'o': /* output dir */ case 'o': /* output dir */
/*-o 选项
afl->out_dir -o
afl->out_dir */
if (afl->out_dir) { FATAL("Multiple -o options not supported"); } if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
afl->out_dir = optarg; afl->out_dir = optarg;
break; break;
case 'M': { /* main sync ID */ case 'M': { /* main sync ID */
/*-M 选项
ID
ARM CoreSight -M
ID -S -M
- -
ID
old_seed_selection 1使
disable_trim 1
ID : ID
is_main_node 1
*/
u8 *c; u8 *c;
if (afl->non_instrumented_mode) { if (afl->non_instrumented_mode) {
@ -1009,14 +862,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'S': /* secondary sync id */ case 'S': /* secondary sync id */
/*-S 选项
ID
ARM CoreSight -S
ID -S -M
- -
ID
is_secondary_node 1*/
if (afl->non_instrumented_mode) { if (afl->non_instrumented_mode) {
FATAL("-S is not supported in non-instrumented mode"); FATAL("-S is not supported in non-instrumented mode");
@ -1046,13 +892,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'F': /* foreign sync dir */ case 'F': /* foreign sync dir */
/*-F 选项
-F
foreign_syncs */
if (!optarg) { FATAL("Missing path for -F"); } if (!optarg) { FATAL("Missing path for -F"); }
if (!afl->is_main_node) { if (!afl->is_main_node) {
@ -1084,13 +924,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'f': /* target file */ case 'f': /* target file */
/*-f 选项
-f
use_stdin 0使
default_output 0使*/
if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); } if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
afl->fsrv.out_file = ck_strdup(optarg); afl->fsrv.out_file = ck_strdup(optarg);
@ -1099,11 +933,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'x': /* dictionary */ case 'x': /* dictionary */
/*-x 选项
-x
extras_dir extras_dir_cnt */
if (extras_dir_cnt >= 4) { if (extras_dir_cnt >= 4) {
FATAL("More than four -x options are not supported"); FATAL("More than four -x options are not supported");
@ -1114,13 +944,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 't': { /* timeout */ case 't': { /* timeout */
/*-t 选项
-t
+
5
timeout_given + */
u8 suffix = 0; u8 suffix = 0;
if (afl->timeout_given) { FATAL("Multiple -t options not supported"); } if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }
@ -1150,14 +974,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} }
case 'm': { /* mem limit */ case 'm': { /* mem limit */
/*-m 选项
-m
TGkM
5
32 2000 MB*/
u8 suffix = 'M'; u8 suffix = 'M';
if (mem_limit_given) { if (mem_limit_given) {
@ -1223,30 +1040,19 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
case 'd': case 'd':
case 'D': /* old deterministic */ case 'D': /* old deterministic */
/*-d 和 -D 选项
使 -z */
WARNF( WARNF(
"Parameters -d and -D are deprecated, a new enhanced deterministic " "Parameters -d and -D are deprecated, a new enhanced deterministic "
"fuzzing is active by default, to disable it use -z"); "fuzzing is active by default, to disable it use -z");
break; break;
case 'z': /* no deterministic */ case 'z': /* no deterministic */
/*-z 选项
skip_deterministic 1*/
afl->skip_deterministic = 1; afl->skip_deterministic = 1;
break; break;
case 'B': /* load bitmap */ case 'B': /* load bitmap */
/*-B 选项
in_bitmap -B
in_bitmap
*/
/* This is a secret undocumented option! It is useful if you find /* This is a secret undocumented option! It is useful if you find
an interesting test case during a normal fuzzing process, and want an interesting test case during a normal fuzzing process, and want
to mutate it without rediscovering any of the test cases already to mutate it without rediscovering any of the test cases already
@ -1264,22 +1070,13 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'C': /* crash mode */ case 'C': /* crash mode */
/*-C 选项
crash_mode -C
crash_mode FSRV_RUN_CRASH*/
if (afl->crash_mode) { FATAL("Multiple -C options not supported"); } if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
afl->crash_mode = FSRV_RUN_CRASH; afl->crash_mode = FSRV_RUN_CRASH;
break; break;
case 'n': /* dumb mode */ case 'n': /* dumb mode */
/*-n 选项
-M -S 使
non_instrumented_mode -n
AFL_DUMB_FORKSRV non_instrumented_mode 1 2*/
if (afl->is_main_node || afl->is_secondary_node) { if (afl->is_main_node || afl->is_secondary_node) {
FATAL("Non instrumented mode is not supported with -M / -S"); FATAL("Non instrumented mode is not supported with -M / -S");
@ -1305,26 +1102,14 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'T': /* banner */ case 'T': /* banner */
/*-T 选项
use_banner -T
use_banner */
if (afl->use_banner) { FATAL("Multiple -T options not supported"); } if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
afl->use_banner = optarg; afl->use_banner = optarg;
break; break;
#ifdef __linux__ #ifdef __linux__
case 'X': /* NYX mode */ case 'X': /* NYX mode */
/*-X 和 -Y 选项(仅限 Linux
Nyx
-X Nyx
nyx_mode -X
nyx_parentnyx_standalone nyx_mode Nyx
-Y Nyx
nyx_mode -Y
nyx_mode Nyx */
if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); } if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
afl->fsrv.nyx_parent = true; afl->fsrv.nyx_parent = true;
@ -1347,12 +1132,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
#endif #endif
case 'A': /* CoreSight mode */ case 'A': /* CoreSight mode */
/*-A 选项(仅限 ARM64 和 Linux
ARM CoreSight
ARM CoreSight -M -S 使
cs_mode -A
cs_mode ARM CoreSight */
#if !defined(__aarch64__) || !defined(__linux__) #if !defined(__aarch64__) || !defined(__linux__)
FATAL("-A option is not supported on this platform"); FATAL("-A option is not supported on this platform");
#endif #endif
@ -1370,12 +1150,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'O': /* FRIDA mode */ case 'O': /* FRIDA mode */
/*-O 选项
FRIDA
frida_mode -O
frida_mode FRIDA
AFL_USE_FASAN frida_asan 1使 FRIDA */
if (afl->fsrv.frida_mode) { if (afl->fsrv.frida_mode) {
FATAL("Multiple -O options not supported"); FATAL("Multiple -O options not supported");
@ -1388,12 +1163,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'Q': /* QEMU mode */ case 'Q': /* QEMU mode */
/*-Q 选项
QEMU
qemu_mode -Q
qemu_mode 1 QEMU
mem_limit MEM_LIMIT_QEMU QEMU */
if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); } if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
afl->fsrv.qemu_mode = 1; afl->fsrv.qemu_mode = 1;
@ -1403,24 +1173,14 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'N': /* Unicorn mode */ case 'N': /* Unicorn mode */
/*-N 选项
no_unlink -N
no_unlink true*/
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); } if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
afl->fsrv.no_unlink = (afl->no_unlink = true); afl->fsrv.no_unlink = (afl->no_unlink = true);
break; break;
case 'U': /* Unicorn mode */ case 'U': /* Unicorn mode */
/*-U 选项
Unicorn
unicorn_mode -U
unicorn_mode 1 Unicorn
mem_limit MEM_LIMIT_UNICORN Unicorn
*/
if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); } if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
afl->unicorn_mode = 1; afl->unicorn_mode = 1;
@ -1429,13 +1189,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'W': /* Wine+QEMU mode */ case 'W': /* Wine+QEMU mode */
/*-W 选项
Wine+QEMU
use_wine -W
qemu_mode 1 QEMU
use_wine 1 Wine
mem_limit 0*/
if (afl->use_wine) { FATAL("Multiple -W options not supported"); } if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
afl->fsrv.qemu_mode = 1; afl->fsrv.qemu_mode = 1;
afl->use_wine = 1; afl->use_wine = 1;
@ -1445,12 +1199,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
break; break;
case 'V': { case 'V': {
/*-V 选项
AFL++
most_time_key 1
*/
afl->most_time_key = 1; afl->most_time_key = 1;
if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 || if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
optarg[0] == '-') { optarg[0] == '-') {
@ -1462,12 +1211,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} break; } break;
case 'E': { case 'E': {
/*-E 选项
AFL++
most_execs_key 1
*/
afl->most_execs_key = 1; afl->most_execs_key = 1;
if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 || if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
optarg[0] == '-') { optarg[0] == '-') {
@ -1479,20 +1223,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} break; } break;
case 'l': { case 'l': {
/*-l 选项
CMPLog
CMPLog
'0''1' CMPLog 1
'2' CMPLog 2
'3' CMPLog 3
'a''A'
's''S'
't''T'
'x''X'
'r''R'
CMPLog CMPLOG_LVL_MAX cmplog_max_filesize MAX_FILE*/
if (!optarg) { FATAL("missing parameter for 'l'"); } if (!optarg) { FATAL("missing parameter for 'l'"); }
char *c = optarg; char *c = optarg;
while (*c) { while (*c) {
@ -1555,23 +1286,7 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
} break; } break;
case 'L': { /* MOpt mode */ case 'L': { /* MOpt mode */
/*-L 选项
MOpt
limit_time_sig -L
havoc_max_mult HAVOC_MAX_MULT_MOPT MOpt Havoc
-1 limit_time_sig -1 MOpt limit_time_puppet 0
0 -1 0 2000000 -1
limit_time_sig 1
old_seed_selection 1使
60 * 1000
MOpt swarm_nowkey_puppetg_noww_now
swarm swarm_fitnessstage_finds_puppetprobability_nowx_nowv_nowL_bestG_besteff_best
MOpt Havoc */
if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); } if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }
afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT; afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
@ -1720,55 +1435,35 @@ struct timeval tv 和 struct timezone tz用于获取当前时间*/
case 'h': case 'h':
show_help++; show_help++;
break; // not needed break; // not needed
/*-h 选项
show_help
break switch case
*/
case 'R': case 'R':
/*-R 选项
Radamsa
Radamsa 使custom_mutators/radamsa/使*/
FATAL( FATAL(
"Radamsa is now a custom mutator, please use that " "Radamsa is now a custom mutator, please use that "
"(custom_mutators/radamsa/)."); "(custom_mutators/radamsa/).");
break; break;
/*默认情况
show_help 1*/
default: default:
if (!show_help) { show_help = 1; } if (!show_help) { show_help = 1; }
} }
} }
/*同步 ID 检查
ID
sync_id "addseeds" "addseeds" ID*/
if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) { if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {
FATAL("-M/-S name 'addseeds' is a reserved name, choose something else"); FATAL("-M/-S name 'addseeds' is a reserved name, choose something else");
} }
/*主节点和功率调度检查
is_main_node 1 FAST EXPLORE -M FAST EXPLORE */
if (afl->is_main_node == 1 && afl->schedule != FAST && if (afl->is_main_node == 1 && afl->schedule != FAST &&
afl->schedule != EXPLORE) { afl->schedule != EXPLORE) {
FATAL("-M is compatible only with fast and explore -p power schedules"); FATAL("-M is compatible only with fast and explore -p power schedules");
} }
/*参数检查和帮助信息显示
optind argc show_help usage 退*/
if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) { if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
usage(argv[0], show_help); usage(argv[0], show_help);
@ -1778,14 +1473,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
if (unlikely(afl->afl_env.afl_persistent_record)) { if (unlikely(afl->afl_env.afl_persistent_record)) {
#ifdef AFL_PERSISTENT_RECORD #ifdef AFL_PERSISTENT_RECORD
/*持久记录配置检查
AFL_PERSISTENT_RECORD
afl_env.afl_persistent_record
AFL++ 使 AFL_PERSISTENT_RECORD
fsrv.persistent_record
2 AFL_PERSISTENT_RECORD 2 100 1000
AFL++ 使 AFL_PERSISTENT_RECORD AFL++ AFL_PERSISTENT_RECORD */
afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record); afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);
if (afl->fsrv.persistent_record < 2) { if (afl->fsrv.persistent_record < 2) {
@ -1807,19 +1495,13 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
} }
if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
/*内存限制调整
CMPLog 260 CMPLog */
OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea " OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
"Fioraldi and Heiko \"hexcoder\" Eißfeldt"); "Fioraldi and Heiko \"hexcoder\" Eißfeldt");
OKF("AFL++ is open source, get it at " OKF("AFL++ is open source, get it at "
"https://github.com/AFLplusplus/AFLplusplus"); "https://github.com/AFLplusplus/AFLplusplus");
OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md"); OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
/*版本信息显示
AFL++ Marc "van Hauser" HeuseDominik MaierAndrea Fioraldi Heiko "hexcoder" Eißfeldt
AFL++ GitHub
AFL++ 3 README.md */
#ifdef __linux__ #ifdef __linux__
if (afl->fsrv.nyx_mode) { if (afl->fsrv.nyx_mode) {
@ -1828,24 +1510,18 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz"); OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");
} }
/*Nyx 模式信息显示(仅限 Linux
Nyx Nyx Sergej Schumilo Nyx GitHub */
#endif #endif
// silently disable deterministic mutation if custom mutators are used // silently disable deterministic mutation if custom mutators are used
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) { if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
/*确定性变异禁用
*/
afl->skip_deterministic = 1; afl->skip_deterministic = 1;
} }
if (afl->fixed_seed) { if (afl->fixed_seed) {
/*固定种子信息显示
使*/
OKF("Running with fixed seed: %u", (u32)afl->init_seed); OKF("Running with fixed seed: %u", (u32)afl->init_seed);
} }
@ -1859,9 +1535,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
} }
#endif #endif
/*信号配置
configure_afl_kill_signals AFL++ fork QEMUUnicornfauxsrv Nyx 使 SIGKILL 使 SIGTERM */
configure_afl_kill_signals( configure_afl_kill_signals(
&afl->fsrv, afl->afl_env.afl_child_kill_signal, &afl->fsrv, afl->afl_env.afl_child_kill_signal,
afl->afl_env.afl_fsrv_kill_signal, afl->afl_env.afl_fsrv_kill_signal,
@ -1872,21 +1546,12 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
) )
? SIGKILL ? SIGKILL
: SIGTERM); : SIGTERM);
/*信号处理设置
setup_signal_handlers AFL++ 便*/
setup_signal_handlers(); setup_signal_handlers();
check_asan_opts(afl); check_asan_opts(afl);
/*ASAN 构建内存限制禁用(仅限 ASAN 构建)
AFL++ 使 ASAN ASAN */
afl->power_name = power_names[afl->schedule]; afl->power_name = power_names[afl->schedule];
/*ASAN 选项检查
check_asan_opts ASAN AFL++ ASAN 使*/
/*功率调度名称设置
power_names afl->power_name */
if (!afl->non_instrumented_mode && !afl->sync_id) { if (!afl->non_instrumented_mode && !afl->sync_id) {
auto_sync = 1; auto_sync = 1;
@ -1895,13 +1560,7 @@ break 语句实际上在这里是多余的,因为 switch 语句的每个 case
OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id); OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id);
} }
/*Nyx 模式同步配置(仅限 Linux
Nyx
Nyx ID "default"
Nyx
ID "0" ID "0"
ID ID 1*/
#ifdef __linux__ #ifdef __linux__
if (afl->fsrv.nyx_mode) { if (afl->fsrv.nyx_mode) {

@ -27,9 +27,6 @@
*/ */
//林睿健阅读部分
#define AFL_MAIN #define AFL_MAIN
#include "config.h" #include "config.h"
@ -100,10 +97,6 @@ static sharedmem_t *shm_fuzz;
/* Classify tuple counts. This is a slow & naive version, but good enough here. /* Classify tuple counts. This is a slow & naive version, but good enough here.
*/ */
/*
count_class_lookup
*/
static const u8 count_class_lookup[256] = { static const u8 count_class_lookup[256] = {
[0] = 0, [0] = 0,
@ -118,10 +111,6 @@ static const u8 count_class_lookup[256] = {
}; };
/*
kill_child
PID0
*/
static void kill_child() { static void kill_child() {
if (fsrv->child_pid > 0) { if (fsrv->child_pid > 0) {
@ -133,11 +122,6 @@ static void kill_child() {
} }
/*
deinit_shmem
fsrvforkservershm_fuzz
NULL
*/
static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv, static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
sharedmem_t *shm_fuzz) { sharedmem_t *shm_fuzz) {
@ -151,11 +135,7 @@ static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
} }
/* Apply mask to classified bitmap (if set). */ /* Apply mask to classified bitmap (if set). */
/*
apply_mask
memmask
NULL
*/
static void apply_mask(u32 *mem, u32 *mask) { static void apply_mask(u32 *mem, u32 *mask) {
u32 i = (map_size >> 2); u32 i = (map_size >> 2);
@ -172,12 +152,6 @@ static void apply_mask(u32 *mem, u32 *mask) {
} }
/*
classify_counts
fsrvforkserver
edges_only
使count_class_lookup
*/
static void classify_counts(afl_forkserver_t *fsrv) { static void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits; u8 *mem = fsrv->trace_bits;
@ -206,11 +180,7 @@ static void classify_counts(afl_forkserver_t *fsrv) {
} }
/* See if any bytes are set in the bitmap. */ /* See if any bytes are set in the bitmap. */
/*
anything_set
fsrvforkserver
1
*/
static inline u8 anything_set(afl_forkserver_t *fsrv) { static inline u8 anything_set(afl_forkserver_t *fsrv) {
u32 *ptr = (u32 *)fsrv->trace_bits; u32 *ptr = (u32 *)fsrv->trace_bits;
@ -226,11 +196,6 @@ static inline u8 anything_set(afl_forkserver_t *fsrv) {
} }
/*
at_exit_handler退
remove_shm
remove_out_file
*/
static void at_exit_handler(void) { static void at_exit_handler(void) {
if (remove_shm) { if (remove_shm) {
@ -246,11 +211,7 @@ static void at_exit_handler(void) {
} }
/* Read initial file. */ /* Read initial file. */
/*
read_initial_file
in_file
*/
static void read_initial_file(void) { static void read_initial_file(void) {
struct stat st; struct stat st;
@ -278,11 +239,7 @@ static void read_initial_file(void) {
} }
/* Write output file. */ /* Write output file. */
/*
write_to_file
pathmemlen
*/
static s32 write_to_file(u8 *path, u8 *mem, u32 len) { static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
s32 ret; s32 ret;
@ -303,11 +260,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
/* Execute target application. Returns 0 if the changes are a dud, or /* Execute target application. Returns 0 if the changes are a dud, or
1 if they should be kept. */ 1 if they should be kept. */
/*
tmin_run_target
fsrvforkservermemlenfirst_run
*/
static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len, static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
u8 first_run) { u8 first_run) {
@ -327,7 +280,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
} }
/* Always discard inputs that time out, unless we are in hang mode */ /* Always discard inputs that time out, unless we are in hang mode */
/* 如果处于挂起模式,总是丢弃超时的输入 */
if (hang_mode) { if (hang_mode) {
switch (ret) { switch (ret) {
@ -347,7 +300,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
classify_counts(fsrv); classify_counts(fsrv);
apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap); apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
/* 根据当前模式处理崩溃输入 */
if (ret == FSRV_RUN_TMOUT) { if (ret == FSRV_RUN_TMOUT) {
missed_hangs++; missed_hangs++;
@ -373,7 +326,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
} }
} else { } else {
/* 适当处理非崩溃输入 */
/* Handle non-crashing inputs appropriately. */ /* Handle non-crashing inputs appropriately. */
if (crash_mode) { if (crash_mode) {
@ -399,11 +352,7 @@ static u8 tmin_run_target(afl_forkserver_t *fsrv, u8 *mem, u32 len,
} }
/* Actually minimize! */ /* Actually minimize! */
/*
minimize
fsrvforkserver
*/
static void minimize(afl_forkserver_t *fsrv) { static void minimize(afl_forkserver_t *fsrv) {
static u32 alpha_map[256]; static u32 alpha_map[256];
@ -682,11 +631,7 @@ finalize_all:
} }
/* Handle Ctrl-C and the like. */ /* Handle Ctrl-C and the like. */
/*
handle_stop_sig
sig
*/
static void handle_stop_sig(int sig) { static void handle_stop_sig(int sig) {
(void)sig; (void)sig;
@ -696,11 +641,7 @@ static void handle_stop_sig(int sig) {
} }
/* Do basic preparations - persistent fds, filenames, etc. */ /* Do basic preparations - persistent fds, filenames, etc. */
/*
set_up_environment
fsrvforkserverargv
*/
static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
u8 *x; u8 *x;
@ -798,10 +739,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
} }
/* Setup signal handlers, duh. */ /* Setup signal handlers, duh. */
/*
setup_signal_handlers
便Ctrl-C
*/
static void setup_signal_handlers(void) { static void setup_signal_handlers(void) {
struct sigaction sa; struct sigaction sa;
@ -826,11 +764,7 @@ static void setup_signal_handlers(void) {
} }
/* Display usage hints. */ /* Display usage hints. */
/*
usage使
argv0
使
*/
static void usage(u8 *argv0) { static void usage(u8 *argv0) {
SAYF( SAYF(
@ -895,272 +829,188 @@ static void usage(u8 *argv0) {
} }
/* Main entry point */ /* Main entry point */
/*
argcargvenvp
退
*/
int main(int argc, char **argv_orig, char **envp) { int main(int argc, char **argv_orig, char **envp) {
//程序的主入口点,接收命令行参数和环境变量
s32 opt; s32 opt;
//用于存储getopt函数返回的当前选项字符。
u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0, u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0,
del_limit_given = 0; del_limit_given = 0;
//定义了一些标志变量用于记录是否已经设置了内存限制、超时时间、unicorn模式、wine模式和删除长度限制。
char **use_argv; char **use_argv;
//用于存储处理后的参数列表,可能会根据模式不同而进行修改。
char **argv = argv_cpy_dup(argc, argv_orig); char **argv = argv_cpy_dup(argc, argv_orig);
//复制命令行参数,以便在解析选项时修改参数列表。
afl_forkserver_t fsrv_var = {0}; afl_forkserver_t fsrv_var = {0};
//初始化一个afl_forkserver_t类型的变量用于管理forkserver。
if (getenv("AFL_DEBUG")) { debug = 1; } if (getenv("AFL_DEBUG")) { debug = 1; }
fsrv = &fsrv_var; fsrv = &fsrv_var;
afl_fsrv_init(fsrv); afl_fsrv_init(fsrv);
map_size = get_map_size(); map_size = get_map_size();
fsrv->map_size = map_size; fsrv->map_size = map_size;
//设置forkserver的共享内存区域大小。
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
//尝试访问文档路径如果不存在则使用默认的“docs”路径。
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
//打印程序的欢迎信息和版本号。
while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) { while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) {
//循环处理命令行参数getopt会解析短选项和长选项。
switch (opt) { switch (opt) {
//根据getopt返回的选项字符执行相应的操作。
case 'i': case 'i':
//如果选项是'i',表示输入文件。
if (in_file) { FATAL("Multiple -i options not supported"); } if (in_file) { FATAL("Multiple -i options not supported"); }
//检查是否已经设置了输入文件,如果设置了多次,则报错。
in_file = optarg; in_file = optarg;
//将输入文件的路径设置到in_file变量。
break; break;
case 'o': case 'o':
//如果选项是'o',表示输出文件。
if (output_file) { FATAL("Multiple -o options not supported"); } if (output_file) { FATAL("Multiple -o options not supported"); }
//检查是否已经设置了输出文件,如果设置了多次,则报错。
output_file = optarg; output_file = optarg;
//将输出文件的路径设置到output_file变量。
break; break;
case 'f': case 'f':
//如果选项是'f',表示被测试程序读取的输入文件(标准输入)。
if (out_file) { FATAL("Multiple -f options not supported"); } if (out_file) { FATAL("Multiple -f options not supported"); }
//检查是否已经设置了输入文件,如果设置了多次,则报错。
fsrv->use_stdin = 0; fsrv->use_stdin = 0;
//设置标志,表示不使用标准输入。
out_file = ck_strdup(optarg); out_file = ck_strdup(optarg);
//复制输入文件的路径到out_file变量。
break; break;
case 'e': case 'e':
//如果选项是'e',表示仅考虑边缘覆盖,忽略命中次数。
if (edges_only) { FATAL("Multiple -e options not supported"); } if (edges_only) { FATAL("Multiple -e options not supported"); }
//检查是否已经设置了仅考虑边缘覆盖,如果设置了多次,则报错。
if (hang_mode) { if (hang_mode) {
//检查是否已经设置了挂起模式,如果同时设置了仅考虑边缘覆盖和挂起模式,则报错。
FATAL("Edges only and hang mode are mutually exclusive."); FATAL("Edges only and hang mode are mutually exclusive.");
//报错,因为仅考虑边缘覆盖和挂起模式不能同时设置。
} }
edges_only = 1; edges_only = 1;
//设置标志,表示仅考虑边缘覆盖。
break; break;
case 'x': case 'x':
//如果选项是'x',表示将非零退出代码视为崩溃。
if (exit_crash) { FATAL("Multiple -x options not supported"); } if (exit_crash) { FATAL("Multiple -x options not supported"); }
//检查是否已经设置了将非零退出代码视为崩溃,如果设置了多次,则报错。
exit_crash = 1; exit_crash = 1;
//设置标志,表示将非零退出代码视为崩溃。
break; break;
case 'm': { case 'm': {
//如果选项是'm',表示设置子进程的内存限制。
//使用花括号创建一个新的作用域,用于存储局部变量。
u8 suffix = 'M'; u8 suffix = 'M';
//定义一个变量suffix默认值为'M',表示内存单位是兆字节。
if (mem_limit_given) { FATAL("Multiple -m options not supported"); } if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
//检查是否已经设置了内存限制,如果设置了多次,则报错。
mem_limit_given = 1; mem_limit_given = 1;
//设置标志,表示已经设置了内存限制。
if (!optarg) { FATAL("Wrong usage of -m"); } if (!optarg) { FATAL("Wrong usage of -m"); }
//检查是否提供了内存限制的参数,如果没有提供,则报错。
if (!strcmp(optarg, "none")) { if (!strcmp(optarg, "none")) {
//检查参数是否是“none”表示不设置内存限制。
fsrv->mem_limit = 0; fsrv->mem_limit = 0;
//设置内存限制为0。
break; break;
//跳出内存限制设置。
} }
//结束内存限制设置的条件判断。
if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 || if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
optarg[0] == '-') { optarg[0] == '-') {
//尝试解析内存限制的参数,如果解析失败或参数以负号开头,则报错。
FATAL("Bad syntax used for -m"); FATAL("Bad syntax used for -m");
//报错,因为内存限制的参数语法不正确。
} }
//结束内存限制设置的条件判断。
switch (suffix) { switch (suffix) {
//根据解析出的后缀,转换内存限制的单位。
case 'T': case 'T':
fsrv->mem_limit *= 1024 * 1024; fsrv->mem_limit *= 1024 * 1024;
break; break;
//如果后缀是'T',表示内存限制的单位是太字节,转换为兆字节。
case 'G': case 'G':
fsrv->mem_limit *= 1024; fsrv->mem_limit *= 1024;
break; break;
//如果后缀是'G',表示内存限制的单位是吉字节,转换为兆字节。
case 'k': case 'k':
fsrv->mem_limit /= 1024; fsrv->mem_limit /= 1024;
break; break;
//如果后缀是'k',表示内存限制的单位是千字节,转换为兆字节。
case 'M': case 'M':
break; break;
//如果后缀是'M',表示内存限制的单位是兆字节,不需要转换。
default: default:
FATAL("Unsupported suffix or bad syntax for -m"); FATAL("Unsupported suffix or bad syntax for -m");
//如果后缀不支持或语法错误,则报错。
} }
//结束单位转换的switch语句。
if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); } if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
//检查内存限制是否过低如果低于5兆字节则报错。
if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) { if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
//检查在32位系统上内存限制是否过高如果超过2000兆字节则报错。
FATAL("Value of -m out of range on 32-bit systems"); FATAL("Value of -m out of range on 32-bit systems");
//报错因为32位系统上内存限制过高。
} }
//结束内存限制设置。
} }
//结束内存限制设置的局部作用域。
break; break;
//结束'm'选项的处理。
case 't': case 't':
//如果选项是't',表示设置每次运行的超时时间。
if (timeout_given) { FATAL("Multiple -t options not supported"); } if (timeout_given) { FATAL("Multiple -t options not supported"); }
//检查是否已经设置了超时时间,如果设置了多次,则报错。
timeout_given = 1; timeout_given = 1;
//设置标志,表示已经设置了超时时间。
if (!optarg) { FATAL("Wrong usage of -t"); } if (!optarg) { FATAL("Wrong usage of -t"); }
//检查是否提供了超时时间的参数,如果没有提供,则报错。
fsrv->exec_tmout = atoi(optarg); fsrv->exec_tmout = atoi(optarg);
//将超时时间的参数转换为整数并设置到fsrv->exec_tmout。
if (fsrv->exec_tmout < 10 || optarg[0] == '-') { if (fsrv->exec_tmout < 10 || optarg[0] == '-') {
//检查超时时间是否过低或参数以负号开头,如果是,则报错。
FATAL("Dangerously low value of -t"); FATAL("Dangerously low value of -t");
//报错,因为超时时间过低。
} }
//结束超时时间设置的条件判断。
break; break;
//结束't'选项的处理。
case 'A': /* CoreSight mode */ case 'A': /* CoreSight mode */
//如果选项是'A'表示使用ARM CoreSight模式。
#if !defined(__aarch64__) || !defined(__linux__) #if !defined(__aarch64__) || !defined(__linux__)
FATAL("-A option is not supported on this platform"); FATAL("-A option is not supported on this platform");
#endif #endif
//检查是否在支持的平台上,如果不是,则报错。
if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); } if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
//检查是否已经设置了CoreSight模式如果设置了多次则报错。
fsrv->cs_mode = 1; fsrv->cs_mode = 1;
//设置标志表示使用CoreSight模式。
break; break;
//结束'A'选项的处理。
case 'O': /* FRIDA mode */ case 'O': /* FRIDA mode */
//如果选项是'O'表示使用FRIDA模式。
if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
//检查是否已经设置了FRIDA模式如果设置了多次则报错。
fsrv->frida_mode = 1; fsrv->frida_mode = 1;
//设置标志表示使用FRIDA模式。
setenv("AFL_FRIDA_INST_SEED", "1", 1); setenv("AFL_FRIDA_INST_SEED", "1", 1);
//设置环境变量用于FRIDA模式。
break; break;
//结束'O'选项的处理。
case 'Q': case 'Q':
//如果选项是'Q'表示使用QEMU模式。
if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
//检查是否已经设置了QEMU模式如果设置了多次则报错。
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; } if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
//如果未设置内存限制则使用QEMU模式的默认内存限制。
fsrv->qemu_mode = 1; fsrv->qemu_mode = 1;
//设置标志表示使用QEMU模式。
break; break;
//结束'Q'选项的处理。
case 'U': case 'U':
//如果选项是'U'表示使用Unicorn模式。
if (unicorn_mode) { FATAL("Multiple -Q options not supported"); } if (unicorn_mode) { FATAL("Multiple -Q options not supported"); }
//检查是否已经设置了Unicorn模式如果设置了多次则报错。
if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; } if (!mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
//如果未设置内存限制则使用Unicorn模式的默认内存限制。
unicorn_mode = 1; unicorn_mode = 1;
//设置标志表示使用Unicorn模式。
break; break;
//结束'U'选项的处理。
case 'W': /* Wine+QEMU mode */ case 'W': /* Wine+QEMU mode */
//如果选项是'W'表示使用Wine+QEMU模式。
if (use_wine) { FATAL("Multiple -W options not supported"); } if (use_wine) { FATAL("Multiple -W options not supported"); }
//检查是否已经设置了Wine+QEMU模式如果设置了多次则报错。
fsrv->qemu_mode = 1; fsrv->qemu_mode = 1;
//设置标志表示使用QEMU模式。
use_wine = 1; use_wine = 1;
//设置标志表示使用Wine。
if (!mem_limit_given) { fsrv->mem_limit = 0; } if (!mem_limit_given) { fsrv->mem_limit = 0; }
//如果未设置内存限制则设置为0。
break; break;
//结束'W'选项的处理。
case 'Y': // fallthough case 'Y': // fallthough
#ifdef __linux__ #ifdef __linux__
case 'X': /* NYX mode */ case 'X': /* NYX mode */
//
if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
@ -1171,7 +1021,6 @@ int main(int argc, char **argv_orig, char **envp) {
break; break;
#else #else
case 'X': case 'X':
//如果选项是'X'表示使用Nyx模式。
FATAL("Nyx mode is only availabe on linux..."); FATAL("Nyx mode is only availabe on linux...");
break; break;
#endif #endif

File diff suppressed because it is too large Load Diff

Binary file not shown.
Loading…
Cancel
Save