AFL++如何进行插桩
之前没好好看过代码,最近刚好有机会,就稍微细细看了一下,网上相关的资料很少。在这总结一下
- 汇编级别插桩 afl-as
- afl-gcc、afl-clang
这两个,通过x86汇编直接插入,无法对其他架构arm、mips进行插桩。
至于为什么会自动掉用afl-as来做汇编器,是因为在调用afl-gcc或afl-clang时,传递了-B afl-fuzz目录。这样编译工具链会优先在-B指定的目录下寻找相应的编译工具。
- 编译器级别插桩 afl-cc
- afl-clang-fast、afl-gcc-fast
两种好处,一是不受CPU架构的影响,二是编译器会对桩代码进行优化,在速度上比纯汇编层面的插桩要快。
先介绍afl-gcc-fast。这部分的插桩在afl-compiler-rt.o.c文件里面使用C语言实现的。然后在插桩的位置进行调用。afl-compiler-rt.o.c会被编译为afl-compiler-rt.64.o、afl-compiler-rt.32.o、afl-compiler-rt.o。在编译的过程中,编译器会对代码进行优化。
之后gcc通过afl-gcc-pass.so编译出来的pass,进行插桩。在对应的的基本块后面创建__afl_trace(const u32 x)
的声明和调用(猜测是在语法树上面进进行修改的)。最终会在链接的阶段,将afl-compiler-rt.o也就是包含了各种桩代码函数实现的.o链接到目标文件,产生目标程序。
再说afl-clang-fast,这个借助llvm pass修改程序的IR进行插桩。桩代码是通过IR实现的,然后再进行汇编和链接,产生插桩文件。