本文档提供了American Fuzzy Lop的简单的概述,原文。
想了解一般的使用说明,请参见README 。
想了解AFL背后的动机和设计目标,请参见historical_notes.txt。
American Fuzzy Lop 不关注任何单一的操作规则(singular principle of operation),也不是一个针对任何特定理论的概念验证(proof of concept)。这个工具可以被认为是一系列在实践中测试过的hacks行为,我们发现这个工具惊人的有效。我们用目前最simple且最robust的方法实现了这个工具。
..
在编译程序中注入的插桩(instrumentation)能够捕获分支(边缘)覆盖率,并且还能检测到粗略的分支执行命中次数(branch-taken hit counts)。在分支点注入的代码大致如下:
cur_location = <COMPILE_TIME_RANDOM>; shared_mem[cur_location ^ prev_location]++; prev_location = cur_location >> 1;
cur_location的值是随机产生的,为的是简化连接复杂对象的过程和保持XOR输出分布是均匀的。
shared_mem[] 数组是一个调用者 (caller) 传给被插桩的二进制程序的64kb的共享空间。其中的每一位可以理解成对于特别的(branch_src, branch_dst)式的tuple的一次命中(hit)。
选择这个数组大小的原因是让冲突(collisions)尽可能减少。这样通常能处理2k到10k的分支点。同时,它的大小也足以达到毫秒级的分析。
这种形式的覆盖率,相对于简单的基本块覆盖率来说,对程序运行路径提供了一个更好的描述(insight)。特别地,它能很好地区分以下两个执行路径:
A -> B -> C -> D -> E (tuples: AB, BC, CD, DE) A -> B -> D -> C -> E (tuples: AB, BD, DC, CE)
这有助于发现底层代码的微小错误条件。因为安全漏洞通常是一些非预期(或不正确)的语句转移(一个tuple就是一个语句转移),而不是没覆盖到某块代码。
上边伪代码的最后一行移位操作是为了让tuple具有定向性(没有这一行的话,AB和BA就没区别了,同样,AA和BB也没区别了)。采用左移的原因跟Intel CPU的一些特性有关。