原文

  1. 引言 本目录下的代码可以利用QEMU 的“user emulation”模式帮助建立独立特征,并允许调用者获得黑盒、闭源的二进制程序的插桩输出。这一机制能支持afl-fuzz用于无法使用afl-gcc编译的目标程序的压力测试(stress-test)。

通常情况下,使用这种方式对程序性能开销会有2-5x的性能下降,即使是这样,仍然比DynamoRIO和PIN等工具要好。

思路和大部分代码实现都来源于Andres Griffiths。

2.如何使用 这一特性是在实现QEMU 2.3.0上实现的一个相当简单的path的基础上完成的。最简单的方式是运行./build_qumu_support.sh脚本建造(build)环境。这一脚本会自动下载、配置(configure)以及编译好QEMU二进制。

QEMU是一个非常大的项目,所以这一个过程会比较耗费时间,另外可能还需要解决依赖项问题,典型的如lib和glib2-devel等。

一旦二进制编译完成,就可以通过在命令行中添加-Q参数的方式调用afl-fuzz和所有相关工具使用QEMU工具。

需要注意的是,QEMU需要设置充足的内存限制(memory limit)才能运行;200MB是个比较好的初始设置,但对复杂程序,需要把这一值设置成更大才行。当指定-Q参数时,默认-m限制将会自动增加到200 MB。

原则上来说,如果在调用./build_qemu_support.sh之前设置CPU_TARGET,则应该建立运行非本地二进制(可以尝试 CPU_TARGET=arm)的环境。如果想要对在64bit系统下运行32bit二进制,这同样是必须的设置。

如果想要为系统中所有的用户安装QEMU helper,则需要在上一级目录(parent directory)上make install之前build。

3.链接注意事项(notes on linking) 特性只适用于Linux。要支持BSD,可能相当于移植改变到linux-user/elfload.c,应用到bsd-user/elfload.c。

只在链接阶段插桩ELF二进制,.text节区,并不跟踪(trace)共享Lib。实际上:

任意想要分析的程序,对其lib文件必须是静态链接到可执行的ELF文件中。 对标准的C lib库和其他标准库,一般情况下不需要对其进行插桩,所以应该动态链接,否则AFL不会自动规避对其插桩分析,这会带来不必要的开销。 4.测试集(benchmarking) 如果想要对比对相同目标代码的QEMU插桩和afl-gcc编译时插桩的性能,我们需要使用相同的编译优化参数build非插桩二进制程序。并确保相关链接库被静态链接到二进制中。通常的命令如下:

$ CFLAGS="-O3 -funroll-loops" ./configure --disable-shared $ make clean all 1 2 如果优化层面或者插桩范围(视野)不一样的话,对执行速度或插桩覆盖率方面的比较衡量会显得没有意义。

5.Gotchas,feedback,bugs 如果需要对被变异后的测试用例进行fix up校验和或者其他cleanup,查看experimental/post_library/目录,里面有可行的解决方案。

主要不要把QEMU模式和ASAN、MSAN等混淆。QEMU并没有得益于sanitizers使用的“shadow VM” 技巧,并很可能会把内存用完。

和fully-fledged 虚拟化相比,用户模拟模式并不是一个安全范围内。二进制能自由与主机(host OS)进行交互。如果确实需要对不可信的二进制进行fuzz,可以先把二进制和AFL同时放到沙盒中。

QEMU并不需要支持目标程序可能使用的所有的CPU或硬件特性。特别地,并没有完全支持AVX2 / FMA3。所以在旧的CPU下使用二进制,或者使用-march=core2参数重新编译将会有所帮助。

6.替代方案:静态重写(static rewriting) 对二进制进行一次静态重写,而不是尝试在运行时进行翻译,能后获得比后者更快的速度。但静态重写是充满危险的(fraught with peril),因为依赖于能否在没有实际执行程序的情况下对程序控制流进行正确和完全的模拟。

如果想要使用这种模式,Aleksandar Nikolich已经给出相应的模块: https://github.com/vrtadmin/moflow/tree/master/afl-dyninsthttps://groups.google.com/forum/#!topic/afl-users/HlSQdbOTlpg