前言
本次主要解决上次的问题三。为了引入更好的测试用例进行模糊测试,afl提供了两个工具afl-cmin、afl-tmin
来进行语料库蒸馏。本文将对这两个工具进行介绍。
一、构建语料库
我们需要先构建一个该项目测试所需的语料库
第一个testcase里面放的是我自己瞎写的一个字符串, 把它多复制几份,每份都对里面进行一些修改,这7个测试样例就构成了我们本次实验的“语料库”了。
AFL功能纵使强大,也需要一个高效的执行速度。如果是普通的语料库作为测试用例,会出现很多无意义的测试,例如多个测试用例执行了同样的代码路径,再比如语料库的文件过大,测试和处理的时间太长等。
构建一个质量更高的语料库就成了必须完成的工作。像我们刚刚制作的几个testcase,随意删删改改的,7个文件都大同小异,显然不是一个合格的语料库,因此afl提供了afl-cmin
、afl-tmin
两种语料库蒸馏的工具。
二、语料库蒸馏
1.afl-cmin(移除执行相同代码的测试用例)
afl-cmin
的核心思想是:尝试找到与语料库全集具有相同覆盖范围的最小子集。 举个例子,假设有多个文件,都覆盖了相同的代码,那么就丢掉多余的文件。
//afl-cmin -i 测试用例文件夹 -o 筛选后的测试用例文件夹 [可能会用到其他操作] 测试程序文件
//这里的用法如下
afl-cmin -i fuzz_in -o fuzz_in_cmin ./afl_test
afl-cmin操作进行时,每次用一个文件跟之前的比较,如果能达到上一个的效果,就替换掉上一个文件。完成后的输出如下所示
此时,之前的整个语料库都被缩减为现在的一个
效果就很明显了。
2.afl-tmin(减小单个输入文件的大小)
整体的大小得到了改善,接下来还要对每个文件进行更细化的处理。
afl-tmin
有两种工作模式,instrumented mode
和crash mode
。默认的工作方式是instrumented mode
,如下所示。
//afl-tmin -i 需要精简的文件 -o 精简后的文件 [其他操作] 测试程序
//这里用到的用例
afl-tmin -i testcase -o fuzz_in_tmin/testcase_tmin ./afl_test
如果指定了参数-x
,就会调用crash mode
模式,会把导致程序非正常退出的文件直接剔除。
afl-tmin -x -i testcase -o fuzz_in_tmin/testcase_tmin ./afl_test
使用普通模式执行时,执行的结果如下图所示。
从执行结果可以看出,文件直接被缩减了68%,生成了新的输入文件
但有个问题,打开afl-tmin
操作之后生成的文件,文件内容永远都是由0构成的字符串,尝试了很多次也是这样。如下图,是两次尝试结果的对比。
PS:本次实验采用的语料库很简单,所以cmin后生成包含所有测试用例执行路径的子集只有一个文件,当语料库比较庞大且比较复杂时,cmin操作常常会生成多个文件作为子集,对子集中的每一个文件进行tmin操作缩减文件的大小,当所有文件都tmin后,还可以继续cmin缩减一次,从而达到最精简。
三、问题
为什么每次tmin缩减后生成的文件内容全是0,这样不会造成测试样例过于单一吗?还能很好的实现路径覆盖吗?