afl-fuzz.c 4500

dev-suhongye-2
Satori5ama 8 months ago
parent ad899967e3
commit 3d0d161d4e

@ -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 trim_case(char** argv, struct queue_entry* q, u8* in_buf) {
static u8 tmp[64]; static u8 tmp[64]; // 用于存储临时字符串
static u8 clean_trace[MAP_SIZE]; static u8 clean_trace[MAP_SIZE]; // 用于存储干净的trace数据
u8 needs_write = 0, fault = 0; u8 needs_write = 0, fault = 0; // needs_write标记是否需要写入文件fault标记是否发生错误
u32 trim_exec = 0; u32 trim_exec = 0; // 记录trim操作的执行次数
u32 remove_len; u32 remove_len; // 每次删除的字节长度
u32 len_p2; u32 len_p2; // 输入长度的下一个2的幂次方
/* Although the trimmer will be less useful when variable behavior is /* 虽然当检测到可变行为时trimmer的用处会减少但它仍然会在一定程度上起作用因此我们不检查这一点。 */
detected, it will still work to some extent, so we don't check for
this. */
if (q->len < 5) return 0; if (q->len < 5) return 0; // 如果输入长度小于5直接返回不进行trim操作
stage_name = tmp; stage_name = tmp; // 设置当前阶段名称为trim
bytes_trim_in += q->len; 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)) { 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_cur = 0; // 当前阶段执行的次数
stage_max = q->len / remove_len; 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 trim_avail = MIN(remove_len, q->len - remove_pos); // 计算实际可删除的字节数
u32 cksum; 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); fault = run_target(argv, exec_tmout); // 运行目标程序
trim_execs++; 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 /* 如果删除操作对trace没有影响则将其永久化。对于可变路径输入这并不完美但我们只是尽力而为
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. */
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; q->len -= trim_avail; // 更新输入长度
len_p2 = next_p2(q->len); len_p2 = next_p2(q->len); // 重新计算下一个2的幂次方
memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, 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 /* 保存一个干净的trace以便在trim操作完成后更新bitmap_score。 */
update_bitmap_score once we're done with the trimming stuff. */
if (!needs_write) { if (!needs_write) { // 如果还没有保存过干净的trace
needs_write = 1; needs_write = 1; // 标记需要写入文件
memcpy(clean_trace, trace_bits, MAP_SIZE); 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(); if (!(trim_exec++ % stats_update_freq)) show_stats(); // 更新统计信息
stage_cur++; stage_cur++; // 增加当前阶段的执行次数
} }
remove_len >>= 1; remove_len >>= 1; // 将删除长度减半
} }
/* If we have made changes to in_buf, we also need to update the on-disk /* 如果对in_buf进行了修改还需要更新磁盘上的测试用例文件。 */
version of the test case. */
if (needs_write) { if (needs_write) { // 如果需要写入文件
s32 fd; 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); ck_write(fd, in_buf, q->len, q->fname); // 写入数据
close(fd); close(fd); // 关闭文件
memcpy(trace_bits, clean_trace, MAP_SIZE); memcpy(trace_bits, clean_trace, MAP_SIZE); // 恢复干净的trace
update_bitmap_score(q); update_bitmap_score(q); // 更新bitmap_score
} }
abort_trimming: abort_trimming:
bytes_trim_out += q->len; bytes_trim_out += q->len; // 累加输出的总字节数
return fault; return fault; // 返回错误状态
} }
/* Write a modified test case, run program, process results. Handle /* 写入修改后的测试用例运行程序处理结果。处理错误条件如果应该退出则返回1。
error conditions, returning 1 if it's time to bail out. This is fuzz_one() */
a helper function for fuzz_one(). */
EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) { EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) {
u8 fault; u8 fault;
if (post_handler) { if (post_handler) { // 如果有后处理函数
out_buf = post_handler(out_buf, &len); out_buf = post_handler(out_buf, &len); // 调用后处理函数
if (!out_buf || !len) return 0; 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) { if (subseq_tmouts++ > TMOUT_LIMIT) { // 如果连续超时次数超过限制
cur_skipped_paths++; cur_skipped_paths++; // 增加跳过的路径数
return 1; return 1; // 返回1
} }
} else subseq_tmouts = 0; } else subseq_tmouts = 0; // 否则重置连续超时次数
/* Users can hit us with SIGUSR1 to request the current input /* 用户可以通过SIGUSR1信号请求放弃当前输入。 */
to be abandoned. */
if (skip_requested) { if (skip_requested) { // 如果收到跳过请求
skip_requested = 0; skip_requested = 0; // 重置跳过请求
cur_skipped_paths++; cur_skipped_paths++; // 增加跳过的路径数
return 1; 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(); show_stats();
return 0; return 0; // 返回0
} }
/* Helper to choose random block len for block operations in fuzz_one(). /* Helper to choose random block len for block operations in fuzz_one().
Doesn't return zero, provided that max_len is > 0. */ Doesn't return zero, provided that max_len is > 0. */
static u32 choose_block_len(u32 limit) { static u32 choose_block_len(u32 limit) {
u32 min_value, max_value; 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; case 0: min_value = 1; // 最小值为1
max_value = HAVOC_BLK_SMALL; max_value = HAVOC_BLK_SMALL; // 最大值为HAVOC_BLK_SMALL
break; break;
case 1: min_value = HAVOC_BLK_SMALL; case 1: min_value = HAVOC_BLK_SMALL; // 最小值为HAVOC_BLK_SMALL
max_value = HAVOC_BLK_MEDIUM; max_value = HAVOC_BLK_MEDIUM; // 最大值为HAVOC_BLK_MEDIUM
break; break;
default: default:
if (UR(10)) { if (UR(10)) { // 90%的概率选择中等大小的块
min_value = HAVOC_BLK_MEDIUM; min_value = HAVOC_BLK_MEDIUM; // 最小值为HAVOC_BLK_MEDIUM
max_value = HAVOC_BLK_LARGE; max_value = HAVOC_BLK_LARGE; // 最大值为HAVOC_BLK_LARGE
} else { } else { // 10%的概率选择大块
min_value = HAVOC_BLK_LARGE; min_value = HAVOC_BLK_LARGE; // 最小值为HAVOC_BLK_LARGE
max_value = HAVOC_BLK_XL; 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. /* 计算案例的期望得分以调整havoc fuzzing的长度。
A helper function for fuzz_one(). Maybe some of these constants should fuzz_one()config.h */
go into config.h. */
static u32 calculate_score(struct queue_entry* q) { static u32 calculate_score(struct queue_entry* q) {
u32 avg_exec_us = total_cal_us / total_cal_cycles; u32 avg_exec_us = total_cal_us / total_cal_cycles; // 计算平均执行时间
u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; // 计算平均位图大小
u32 perf_score = 100; u32 perf_score = 100; // 初始得分为100
/* Adjust score based on execution speed of this path, compared to the /* 根据路径的执行速度调整得分与全局平均速度相比。乘数范围从0.1x到3x。
global average. Multiplier ranges from 0.1x to 3x. Fast inputs are fuzz */
less expensive to fuzz, so we're giving them more air time. */
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.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.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 * 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 * 3 < avg_exec_us) perf_score = 200;
else if (q->exec_us * 2 < avg_exec_us) perf_score = 150; else if (q->exec_us * 2 < avg_exec_us) perf_score = 150;
/* Adjust score based on bitmap size. The working theory is that better /* 根据位图大小调整得分。理论是更好的覆盖率意味着更好的目标。乘数从0.25x到3x。 */
coverage translates to better targets. Multiplier from 0.25x to 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.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 * 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 * 2 < avg_bitmap_size) perf_score *= 0.5;
else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75; 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 /* 根据handicap调整得分。handicap与我们在游戏中了解到此路径的时间成正比。
in the game we learned about this path. Latecomers are allowed to run */
for a bit longer until they catch up with the rest. */
if (q->handicap >= 4) { if (q->handicap >= 4) { // 如果handicap大于等于4得分增加4倍
perf_score *= 4; perf_score *= 4;
q->handicap -= 4; q->handicap -= 4;
} else if (q->handicap) { } else if (q->handicap) { // 如果handicap大于0得分增加2倍
perf_score *= 2; perf_score *= 2;
q->handicap--; q->handicap--;
} }
/* Final adjustment based on input depth, under the assumption that fuzzing /* 根据输入深度进行最终调整假设fuzzing更深的测试用例更有可能揭示传统fuzzer无法发现的内容。 */
deeper test cases is more likely to reveal stuff that can't be
discovered with traditional fuzzers. */
switch (q->depth) { switch (q->depth) {
case 0 ... 3: break; case 0 ... 3: break; // 深度为0到3时不调整得分
case 4 ... 7: perf_score *= 2; break; case 4 ... 7: perf_score *= 2; break; // 深度为4到7时得分增加2倍
case 8 ... 13: perf_score *= 3; break; case 8 ... 13: perf_score *= 3; break; // 深度为8到13时得分增加3倍
case 14 ... 25: perf_score *= 4; break; case 14 ... 25: perf_score *= 4; break; // 深度为14到25时得分增加4倍
default: perf_score *= 5; 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 /* 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 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 attempted by afl-fuzz. This is used to avoid dupes in some of the

Loading…
Cancel
Save