AFL-fuzz工具分析

网上afl-fuzz的资料比较少,大多是解释afl带的技术白皮书,介绍afl的原理和使用到的技术,但对于想要了解afl内部实现并加以利用和改进还是远远不够的。所以本人在学习afl过程中,把一些重要的东西记录下来,方便阅读和理解afl的代码。如果有写的不对的地方,欢迎指证。

1. afl的fuzz工作流程

1. main函数先进行初始化和选项处理;
2. 执行input文件夹下的预先准备的所有testcase(perform_dry_run),生成初始化的queue和bitmap;
3. 通过cull_queue对queue进行精选,减小input的量;
4. 然后进行while(1)循环不断进行fuzz。

其中while(1)循环包括以下流程,每fuzz一个queue,就会重新进入while(1),并重新cull_queue()精选队列。

1. cull_queue()对queue进行精选,选出favored。
2. 判断queue_cur是否为NULL,如果是,则表示已经完成对队列的遍历,queue_cycle++,初始化相关参数,重新开始遍历队列;
3. fuzz queue_cur对应的input文件,**fuzz_one()**;
4. 判断是否结束,并更新queue_cur和current_entry

注:当队列中的所有文件都经过变异测试了,则完成一次"cycle done";
整个队列又会从第一个文件开始,再次进行变异,不过与第一次变异不同的是,这一次就不需要再进行deterministic fuzzing了。

1.1 预料删选 cull_queue()

为了优化模糊工作,AFL使用快速算法定期重新评估队列,该算法选择一个较小的测试用例子集,该子集仍覆盖到目前为止所看到的每个元组,并且其特征使它们对Fuzzing特别有利。该算法通过为每个队列条目分配与其执行延迟和文件大小成正比的分数来工作;然后为每个tuples选择最低得分候选者。

cull_queue()遍历top_rated[]中的queue,然后提取出发现新的edge的entry,并标记为favored,使得在下次遍历queue时,这些entry能获得更多执行fuzz的机会。

这里本质上采用了贪婪算法,如果top_rated[i]存在,且对应temp_v[]中对应bit位还没抹去,即这一轮选出的queue还没覆盖bit_map[i]对应的边,则取出这个top_rated[i]。抹去temp_v中top_rated[i]能访问到的位。最后将这个top_rated[i]标记为favored,如果这个queue还没fuzzed,pending_favored++.
cull_queue()函数核心代码如下:

    /* line 1309 - 1328*/

注:需要结合下面2节进行理解。

1.1.1 trace_bits[]与top_rated[]

一个queue经过run之后,会生成新的trace_bits来记录这个queue的trace情况,也就是这个queue访问了那些edge。
通过遍历trace_bits[],可以访问到每个edge。

top_rate[]数组维护的是所有边的访问情况。其对应关系为,top_rated[i]选取出所有访问到bit_map[i]所代表边的queue中代价(执行时间*文件长度)最小的一个queue。

1.1.2 bitmap更新 update_bitmap_score()

update_bitmap_socre()函数在每次run_target()之后调用,根据上述规则更新top_rate[].如果一个queue入选top_rate[],被替换掉queue的tc_ref–, 新queue的tc_ref++,并生成简化的trace_mini。

如果有发生新的queue入选top_rate[],score_changed置一,在cull_queue()时,会先判断score_changed是否为1,如果不为1,就不用进行cull_queue()了。

trace_mini的组织方式:trace_mini的大小为MAP_SIZE / 8,即每个bit对应了bit_map中的一个byte;如果这个queue访问了bit_map中的一个byte(即访问了一个edge),trace_mini中对应的bit位就置一。

1.2 变异测试用例 fuzz_one()

对当前选出的queue_cur执行fuzz操作,fuzz_one()的具体步骤为:

1. 按照是否有pending_favored和queue_cur的情况(was_fuzzed, favored)选择是否跳过分析,具体跳过的规则见1.2.1;
2. 加载test case
3. CALIBRATION
4. 输入文件修剪,减小input文件大小 trim_case()
5. case打分performance score(),如果该queue已经完成deterministic阶段,则直接跳到havoc阶段
6. bitfilp: 位翻转,同时自动检测token(识别IHDR),生成effector map中
7. arithmetic: 算术变异,加上或者减去一个整数
8. interest:对比特位进行替换,替换为interest的数据(提前定义好的,通常为数据类型的边界)
9. dictionary:字典替换或插入,来源用户提供的token、自动检测生成的token。
10. havoc:大破坏!多种变异方式的组合
11. splice:拼接,2个seed进行拼接,并进行havoc

注:havoc之前的变异为deterministic fuzzing,即每次执行,变异过程和结果都一样。

1.2.1 queue跳过规则

1. 如果有pending_favored, 则99%跳过fuzzed或者不是favored的queue;
2. 如果没有如果有pending_favored,则95%跳过已经fuzzed的不是favored的queue,75%跳过没有fuzzed的不是favored的queue,不跳过favored的queue。

1.2.2 calilbrate_case()

多次执行这个case,并通过update_bitmap_score()更新bitmap。
在save_if_interesting()/perform_dry_run()/fuzz_one()中被调用。

不是很懂这个函数的意义???

1.2.3 输入文件修剪 trim_case()

文件大小对模糊性能有很大影响,这是因为大文件使目标二进制文件变得更慢,并且因为它们减少了突变将触及重要的格式控制结构而不是冗余数据块的可能性。这在perf_tips.txt中有更详细的讨论。
用户可能会提供低质量的起始语料库,某些类型的突变可能会产生迭代地增加生成文件的大小的效果,因此应对这一趋势是很重要的。

幸运的是,插装反馈提供了一种简单的方法来自动删除输入文件,同时确保对文件的更改不会对执行路径产生影响。
在afl-fuzz中内置的修边器试图按可变长度和stepover顺序删除

  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值