一、前言:

本次需求分析针对工程实践,我的工程实践是对afl进行源码级学习,掌握其运行原理,之后针对部分分布式数据库,改进afl的测试算法,以达到分析数据库漏洞的目标。

所以此篇文章就是针对afl的需求分析,afl与大多数软件不同,不存在用户管理员,是一个发现目标程序漏洞的软件。

二、需求分析:

1.对待测试目标程序进行插桩,以便获得测试用例的程序覆盖率;

2.对用户过大的测试用例进行裁剪,因为过大的测试用例会导致测试速度下降,但不能保证覆盖率提高,在性能权衡后,选择裁剪。

3.对测试用例进行足够的变异,以达到扩大程序覆盖率的目标。

三、工作流程:

 

①从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);

 

②选择一些输入文件,作为初始测试集加入输入队列(queue);

 

③将队列中的文件按一定的策略进行“突变”;

 

④如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;

 

⑤上述过程会一直循环进行,期间触发了crash的文件会被记录下来。

 

  

 

 

 四、插桩实现:

 

代码覆盖率是模糊测试中一个极其重要的概念,使用代码覆盖率可以评估和改进测试过程,执行到的代码越多,找到bug的可能性就越大,毕竟,在覆盖的代码中并不能100%发现bug,在未覆盖的代码中却是100%找不到任何bug的,所以本节中就将详细介绍代码覆盖率的相关概念。

 

1. 代码覆盖率(Code Coverage)

 

代码覆盖率是一种度量代码的覆盖程度的方式,也就是指源代码中的某行代码是否已执行;对二进制程序,还可将此概念理解为汇编代码中的某条指令是否已执行。其计量方式很多,但无论是GCC的GCOV还是LLVM的SanitizerCoverage,都提供函数(function)、基本块(basic-block)、边界(edge)三种级别的覆盖率检测,更具体的细节可以参考LLVM的官方文档

 

2. 基本块(Basic Block)

 

缩写为BB,指一组顺序执行的指令,BB中第一条指令被执行后,后续的指令也会被全部执行,每个BB中所有指令的执行次数是相同的,也就是说一个BB必须满足以下特征:

 

只有一个入口点,BB中的指令不是任何跳转指令的目标。

只有一个退出点,只有最后一条指令使执行流程转移到另一个BB

 

 

 将上面的程序拖进IDA,可以看到同样被划分出了4个基本块:

 

 

3. 元组(tuple)

具体到AFL的实现中,使用二元组(branch_src, branch_dst)来记录当前基本块 + 前一基本块 的信息,从而获取目标的执行流程和代码覆盖情况,伪代码如下:

cur_location = <COMPILE_TIME_RANDOM>;//用一个随机数标记当前基本块
shared_mem[cur_location ^ prev_location]++;//将当前块和前一块异或保存到shared_mem[]
prev_location = cur_location >> 1;//cur_location右移1位区分从当前块到当前块的转跳

利用cur_location来标记当前块,prev_location来标记前块,cur_location ^ prev_location来标记程序从前块运行到当前块。

 

 五、变异实现:

 

六、总结:

AFL是个很大的程序,目前为止的代码阅读没能让我画出他的庞大的类图,只能尽量做一些记录。

posted on 2020-12-15 11:20  太阳不绕地球转  阅读(321)  评论(0编辑  收藏  举报