diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ff147b5..5b849a9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -4514,291 +4514,278 @@ static u32 next_p2(u32 val) { static u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) { - static u8 tmp[64]; - static u8 clean_trace[MAP_SIZE]; + static u8 tmp[64]; // 用于存储临时字符串 + static u8 clean_trace[MAP_SIZE]; // 用于存储干净的trace数据 - u8 needs_write = 0, fault = 0; - u32 trim_exec = 0; - u32 remove_len; - u32 len_p2; + u8 needs_write = 0, fault = 0; // needs_write标记是否需要写入文件,fault标记是否发生错误 + u32 trim_exec = 0; // 记录trim操作的执行次数 + u32 remove_len; // 每次删除的字节长度 + u32 len_p2; // 输入长度的下一个2的幂次方 - /* Although the trimmer will be less useful when variable behavior is - detected, it will still work to some extent, so we don't check for - this. */ + /* 虽然当检测到可变行为时,trimmer的用处会减少,但它仍然会在一定程度上起作用,因此我们不检查这一点。 */ - if (q->len < 5) return 0; + if (q->len < 5) return 0; // 如果输入长度小于5,直接返回,不进行trim操作 - stage_name = tmp; - bytes_trim_in += q->len; + stage_name = tmp; // 设置当前阶段名称为trim + bytes_trim_in += q->len; // 累加输入的总字节数 - /* Select initial chunk len, starting with large steps. */ + /* 选择初始的删除长度,从较大的步长开始。 */ - len_p2 = next_p2(q->len); + len_p2 = next_p2(q->len); // 计算输入长度的下一个2的幂次方 - remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); + remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); // 计算初始删除长度 - /* Continue until the number of steps gets too high or the stepover - gets too small. */ + /* 继续直到步数过高或步长过小。 */ while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, TRIM_MIN_BYTES)) { - u32 remove_pos = remove_len; + u32 remove_pos = remove_len; // 删除的起始位置 - sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); + sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); // 格式化阶段名称 - stage_cur = 0; - stage_max = q->len / remove_len; + stage_cur = 0; // 当前阶段执行的次数 + stage_max = q->len / remove_len; // 当前阶段的最大执行次数 - while (remove_pos < q->len) { + while (remove_pos < q->len) { // 遍历输入数据 - u32 trim_avail = MIN(remove_len, q->len - remove_pos); - u32 cksum; + u32 trim_avail = MIN(remove_len, q->len - remove_pos); // 计算实际可删除的字节数 + u32 cksum; // 用于存储trace的校验和 - write_with_gap(in_buf, q->len, remove_pos, trim_avail); + write_with_gap(in_buf, q->len, remove_pos, trim_avail); // 写入带有删除部分的数据 - fault = run_target(argv, exec_tmout); - trim_execs++; + fault = run_target(argv, exec_tmout); // 运行目标程序 + trim_execs++; // 增加trim操作的执行次数 - if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; + if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; // 如果发生错误或停止信号,跳转到abort_trimming - /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + /* 注意,我们这里不跟踪崩溃或挂起;也许TODO? */ - cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); // 计算trace的校验和 - /* If the deletion had no impact on the trace, make it permanent. This - isn't perfect for variable-path inputs, but we're just making a - best-effort pass, so it's not a big deal if we end up with false - negatives every now and then. */ + /* 如果删除操作对trace没有影响,则将其永久化。对于可变路径输入,这并不完美,但我们只是尽力而为, + 所以偶尔出现假阴性也没关系。 */ - if (cksum == q->exec_cksum) { + if (cksum == q->exec_cksum) { // 如果校验和与之前的相同 - u32 move_tail = q->len - remove_pos - trim_avail; + u32 move_tail = q->len - remove_pos - trim_avail; // 计算需要移动的尾部字节数 - q->len -= trim_avail; - len_p2 = next_p2(q->len); + q->len -= trim_avail; // 更新输入长度 + len_p2 = next_p2(q->len); // 重新计算下一个2的幂次方 memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, - move_tail); + move_tail); // 移动数据,覆盖删除的部分 - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + /* 保存一个干净的trace,以便在trim操作完成后更新bitmap_score。 */ - if (!needs_write) { + if (!needs_write) { // 如果还没有保存过干净的trace - needs_write = 1; - memcpy(clean_trace, trace_bits, MAP_SIZE); + needs_write = 1; // 标记需要写入文件 + memcpy(clean_trace, trace_bits, MAP_SIZE); // 保存当前的trace } - } else remove_pos += remove_len; + } else remove_pos += remove_len; // 如果校验和不同,继续下一个删除位置 - /* Since this can be slow, update the screen every now and then. */ + /* 由于这个过程可能很慢,所以每隔一段时间更新屏幕显示。 */ - if (!(trim_exec++ % stats_update_freq)) show_stats(); - stage_cur++; + if (!(trim_exec++ % stats_update_freq)) show_stats(); // 更新统计信息 + stage_cur++; // 增加当前阶段的执行次数 } - remove_len >>= 1; + remove_len >>= 1; // 将删除长度减半 } - /* If we have made changes to in_buf, we also need to update the on-disk - version of the test case. */ + /* 如果对in_buf进行了修改,还需要更新磁盘上的测试用例文件。 */ - if (needs_write) { + if (needs_write) { // 如果需要写入文件 s32 fd; - unlink(q->fname); /* ignore errors */ + unlink(q->fname); /* 忽略错误 */ // 删除旧文件 - fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); + fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); // 创建新文件 - if (fd < 0) PFATAL("Unable to create '%s'", q->fname); + if (fd < 0) PFATAL("Unable to create '%s'", q->fname); // 如果创建失败,报错 - ck_write(fd, in_buf, q->len, q->fname); - close(fd); + ck_write(fd, in_buf, q->len, q->fname); // 写入数据 + close(fd); // 关闭文件 - memcpy(trace_bits, clean_trace, MAP_SIZE); - update_bitmap_score(q); + memcpy(trace_bits, clean_trace, MAP_SIZE); // 恢复干净的trace + update_bitmap_score(q); // 更新bitmap_score } abort_trimming: - bytes_trim_out += q->len; - return fault; + bytes_trim_out += q->len; // 累加输出的总字节数 + return fault; // 返回错误状态 } -/* Write a modified test case, run program, process results. Handle - error conditions, returning 1 if it's time to bail out. This is - a helper function for fuzz_one(). */ +/* 写入修改后的测试用例,运行程序,处理结果。处理错误条件,如果应该退出则返回1。 + 这是fuzz_one()的辅助函数。 */ EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) { u8 fault; - if (post_handler) { + if (post_handler) { // 如果有后处理函数 - out_buf = post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + out_buf = post_handler(out_buf, &len); // 调用后处理函数 + if (!out_buf || !len) return 0; // 如果处理后数据为空,返回0 } - write_to_testcase(out_buf, len); + write_to_testcase(out_buf, len); // 写入测试用例 - fault = run_target(argv, exec_tmout); + fault = run_target(argv, exec_tmout); // 运行目标程序 - if (stop_soon) return 1; + if (stop_soon) return 1; // 如果收到停止信号,返回1 - if (fault == FAULT_TMOUT) { + if (fault == FAULT_TMOUT) { // 如果发生超时 - if (subseq_tmouts++ > TMOUT_LIMIT) { - cur_skipped_paths++; - return 1; + if (subseq_tmouts++ > TMOUT_LIMIT) { // 如果连续超时次数超过限制 + cur_skipped_paths++; // 增加跳过的路径数 + return 1; // 返回1 } - } else subseq_tmouts = 0; + } else subseq_tmouts = 0; // 否则重置连续超时次数 - /* Users can hit us with SIGUSR1 to request the current input - to be abandoned. */ + /* 用户可以通过SIGUSR1信号请求放弃当前输入。 */ - if (skip_requested) { + if (skip_requested) { // 如果收到跳过请求 - skip_requested = 0; - cur_skipped_paths++; - return 1; + skip_requested = 0; // 重置跳过请求 + cur_skipped_paths++; // 增加跳过的路径数 + return 1; // 返回1 } - /* This handles FAULT_ERROR for us: */ + /* 这为我们处理FAULT_ERROR: */ - queued_discovered += save_if_interesting(argv, out_buf, len, fault); + queued_discovered += save_if_interesting(argv, out_buf, len, fault); // 保存有趣的测试用例 - if (!(stage_cur % stats_update_freq) || stage_cur + 1 == stage_max) + if (!(stage_cur % stats_update_freq) || stage_cur + 1 == stage_max) // 更新统计信息 show_stats(); - return 0; + return 0; // 返回0 } + /* Helper to choose random block len for block operations in fuzz_one(). Doesn't return zero, provided that max_len is > 0. */ static u32 choose_block_len(u32 limit) { u32 min_value, max_value; - u32 rlim = MIN(queue_cycle, 3); + u32 rlim = MIN(queue_cycle, 3); // 限制随机选择的范围,最大为3 - if (!run_over10m) rlim = 1; + if (!run_over10m) rlim = 1; // 如果运行时间未超过10分钟,限制随机选择的范围为1 - switch (UR(rlim)) { + switch (UR(rlim)) { // 根据随机数选择块长度的范围 - case 0: min_value = 1; - max_value = HAVOC_BLK_SMALL; + case 0: min_value = 1; // 最小值为1 + max_value = HAVOC_BLK_SMALL; // 最大值为HAVOC_BLK_SMALL break; - case 1: min_value = HAVOC_BLK_SMALL; - max_value = HAVOC_BLK_MEDIUM; + case 1: min_value = HAVOC_BLK_SMALL; // 最小值为HAVOC_BLK_SMALL + max_value = HAVOC_BLK_MEDIUM; // 最大值为HAVOC_BLK_MEDIUM break; default: - if (UR(10)) { + if (UR(10)) { // 90%的概率选择中等大小的块 - min_value = HAVOC_BLK_MEDIUM; - max_value = HAVOC_BLK_LARGE; + min_value = HAVOC_BLK_MEDIUM; // 最小值为HAVOC_BLK_MEDIUM + max_value = HAVOC_BLK_LARGE; // 最大值为HAVOC_BLK_LARGE - } else { + } else { // 10%的概率选择大块 - min_value = HAVOC_BLK_LARGE; - max_value = HAVOC_BLK_XL; + min_value = HAVOC_BLK_LARGE; // 最小值为HAVOC_BLK_LARGE + max_value = HAVOC_BLK_XL; // 最大值为HAVOC_BLK_XL } } - if (min_value >= limit) min_value = 1; + if (min_value >= limit) min_value = 1; // 如果最小值超过限制,则重置为1 - return min_value + UR(MIN(max_value, limit) - min_value + 1); + return min_value + UR(MIN(max_value, limit) - min_value + 1); // 返回在[min_value, max_value]范围内的随机长度 } -/* Calculate case desirability score to adjust the length of havoc fuzzing. - A helper function for fuzz_one(). Maybe some of these constants should - go into config.h. */ +/* 计算案例的期望得分,以调整havoc fuzzing的长度。 + 这是fuzz_one()的辅助函数。也许其中一些常量应该放在config.h中。 */ static u32 calculate_score(struct queue_entry* q) { - u32 avg_exec_us = total_cal_us / total_cal_cycles; - u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; - u32 perf_score = 100; + u32 avg_exec_us = total_cal_us / total_cal_cycles; // 计算平均执行时间 + u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; // 计算平均位图大小 + u32 perf_score = 100; // 初始得分为100 - /* Adjust score based on execution speed of this path, compared to the - global average. Multiplier ranges from 0.1x to 3x. Fast inputs are - less expensive to fuzz, so we're giving them more air time. */ + /* 根据路径的执行速度调整得分,与全局平均速度相比。乘数范围从0.1x到3x。 + 执行速度快的输入fuzz成本较低,因此我们给予它们更多的执行时间。 */ - if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; + if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; // 如果执行时间远高于平均,得分降低 else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25; else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50; else if (q->exec_us * 0.75 > avg_exec_us) perf_score = 75; - else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; + else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; // 如果执行时间远低于平均,得分增加 else if (q->exec_us * 3 < avg_exec_us) perf_score = 200; else if (q->exec_us * 2 < avg_exec_us) perf_score = 150; - /* Adjust score based on bitmap size. The working theory is that better - coverage translates to better targets. Multiplier from 0.25x to 3x. */ + /* 根据位图大小调整得分。理论是更好的覆盖率意味着更好的目标。乘数从0.25x到3x。 */ - if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; + if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; // 如果位图大小远高于平均,得分增加 else if (q->bitmap_size * 0.5 > avg_bitmap_size) perf_score *= 2; else if (q->bitmap_size * 0.75 > avg_bitmap_size) perf_score *= 1.5; - else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; + else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; // 如果位图大小远低于平均,得分降低 else if (q->bitmap_size * 2 < avg_bitmap_size) perf_score *= 0.5; else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75; - /* Adjust score based on handicap. Handicap is proportional to how late - in the game we learned about this path. Latecomers are allowed to run - for a bit longer until they catch up with the rest. */ + /* 根据handicap调整得分。handicap与我们在游戏中了解到此路径的时间成正比。 + 后来者被允许运行更长时间,直到他们赶上其他人。 */ - if (q->handicap >= 4) { + if (q->handicap >= 4) { // 如果handicap大于等于4,得分增加4倍 perf_score *= 4; q->handicap -= 4; - } else if (q->handicap) { + } else if (q->handicap) { // 如果handicap大于0,得分增加2倍 perf_score *= 2; q->handicap--; } - /* Final adjustment based on input depth, under the assumption that fuzzing - deeper test cases is more likely to reveal stuff that can't be - discovered with traditional fuzzers. */ + /* 根据输入深度进行最终调整,假设fuzzing更深的测试用例更有可能揭示传统fuzzer无法发现的内容。 */ switch (q->depth) { - case 0 ... 3: break; - case 4 ... 7: perf_score *= 2; break; - case 8 ... 13: perf_score *= 3; break; - case 14 ... 25: perf_score *= 4; break; - default: perf_score *= 5; + case 0 ... 3: break; // 深度为0到3时不调整得分 + case 4 ... 7: perf_score *= 2; break; // 深度为4到7时得分增加2倍 + case 8 ... 13: perf_score *= 3; break; // 深度为8到13时得分增加3倍 + case 14 ... 25: perf_score *= 4; break; // 深度为14到25时得分增加4倍 + default: perf_score *= 5; // 深度大于25时得分增加5倍 } - /* Make sure that we don't go over limit. */ + /* 确保得分不超过限制。 */ - if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100; + if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100; // 如果得分超过最大限制,则设置为最大限制 - return perf_score; + return perf_score; // 返回最终得分 } + /* Helper function to see if a particular change (xor_val = old ^ new) could be a product of deterministic bit flips with the lengths and stepovers attempted by afl-fuzz. This is used to avoid dupes in some of the