1、config.h
属于配置类的头文件,包含大量的宏定义,用来规定。
宏定义大概分三个部分,刚开始是一些通用的参数,如输入输出文件的大小,用户的颜色配置;第二部分是跟变异有关的,比如在文件变异时候的interest过程,所用到的预设特殊值,就是在这个头文件中定义的,还有bitflip阶段的 token 长度定义也是在这个头文件中;第三部分是特殊用途的宏定义,比如 HASH_CONST 定义了哈希函数里的一个长度常量,等等2、types.h
其是对一些数据类型的重命名或者是定义,以及对DMA通用地址的定义以及其64为的特性。
3、debug.h
调试,宏定义各种参数及函数
4、alloc-inl.h
内存相关,提供错误检查、内存清零、内存分配等常规操作,“内存器的设计初衷不是为了抵抗恶意攻击,但是它确实提供了便携健壮的内存处理方式,可以检查 use-after-free 等”
afl-clang-fast.c 文件本质上是 clang 的 wrapper,最终调用的还是 clang 。但是与 afl-gcc 一样,会进行一些参数处理。
#define AFL_MAIN
#include "../config.h"
#include "../types.h"
#include "../debug.h"
#include "../alloc-inl.h"
#include
#include
#include
#include
static u8* obj_path; /* Path to runtime libraries 运行库的路径 */
static u8** cc_params; /* Parameters passed to the real CC 传递给实际CC的运行时库参数的路径*/
static u32 cc_par_cnt = 1; /* Param count, including argv0 参数计数,包括argv0 */
/* Try to find the runtime libraries. If that fails, abort. 尝试查找运行库。如果失败,中止。*/
static void find_obj(u8* argv0) {
u8 *afl_path = getenv("AFL_PATH"); //获取环境变量AFL_PATH的值
u8 *slash, *tmp;
if (afl_path) { //如果存在环境变量AFL_PATH的值
tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path);//alloc_printf函数动态分配一段空间存储路径
if (!access(tmp, R_OK)) { //读取AFL_PATH/afl-llvm-rt.o是否可以访问
obj_path = afl_path; //如果可以就设置这个目录为obj_path,然后直接返回
ck_free(tmp);//释放掉alloc_printf分配的内存
return;
}
ck_free(tmp);//释放掉alloc_printf分配的内存
}
//如果不存在环境变量AFL_PATH的值
slash = strrchr(argv0, '/');//检查argv0里有没有’/‘,如果没有就赋值’argv0’到slash,如果有就找到最后一个’/‘所在的位置,然后跳过这个’/‘,将后面的字符串赋值给slash
if (slash) {
u8 *dir;
*slash = 0;
dir = ck_strdup(argv0);//取其前面的字符串作为dir
*slash = '/';
tmp = alloc_printf("%s/afl-llvm-rt.o", dir);
if (!access(tmp, R_OK)) { //如果可以就设置这个目录为obj_path,然后直接返回
obj_path = dir;
ck_free(tmp);
return;
}
ck_free(tmp);
ck_free(dir);
}
if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { //如果上面两种都找不到,因为默认的AFL的MakeFile在编译的时候,会定义一个名为AFL_PATH的宏,其指向/usr/local/lib/afl,会到这里找是否存在afl-llvm-rt.o,如果存在设置obj_path并直接返回
obj_path = AFL_PATH;
return;
}
FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH");//如果上述三种方式都找不到,那么就会抛出异常
}
/* Copy argv to cc_params, making the necessary edits. 将argv复制到cc_参数,进行必要的编辑 */
static void edit_params(u32 argc, char** argv) {
u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
u8 *name;
cc_params = ck_alloc((argc + 128) * sizeof(u8*));//通过ck_alloc来为cc_params分配内存,分配的长度为(argc+128)*8
name = strrchr(argv[0], '/');//检查argv[0]里有没有’/‘,如果没有就赋值’argv[0]’到name,如果有就找到最后一个’/‘所在的位置,然后跳过这个’/‘,将后面的字符串赋值给name
if (!name) name = argv[0]; else name++;
if (!strcmp(name, "afl-clang-fast++")) {//如果name变量中的字符是afl-clang++
u8* alt_cxx = getenv("AFL_CXX");//读取环境变量AFL_CXX
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";//如果存在,就将其值设置为cc_params[0],如果不存在,就直接设置成clang++
} else {
u8* alt_cc = getenv("AFL_CC");//读取环境变量AFL_CC
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";//如果存在,就将其值设置为cc_params[0],如果不存在,就直接设置成clang
}
/* There are two ways to compile afl-clang-fast. In the traditional mode, we
use afl-llvm-pass.so to inject instrumentation. In the experimental
'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
instead. The latter is a very recent addition - see:
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */
/*有两种方法可以编译afl-clang-fast。在传统模式中,我们使用afl-llvm-pass。所以要注入仪器。在实验中“trace pc guard”模式下,我们使用本机LLVM检测回调相反后者是最近添加的一项功能,请参见:
http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */
#ifdef USE_TRACE_PC //如果定义了USE_TRACE_PC宏
//就将-fsanitize-coverage=trace-pc-guard -mllvm -sanitizer-coverage-block-threshold=0添加到参数里
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
#ifndef __ANDROID__
cc_params[cc_par_cnt++] = "-mllvm";
cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
#endif
#else
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = "-load";
cc_params[cc_par_cnt++] = "-Xclang";
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
#endif /* ^USE_TRACE_PC */
//依次读取我们传给afl-clang-fast的参数,并添加到cc_params里,不过这里会做一些检查和设置
cc_params[cc_par_cnt++] = "-Qunused-arguments";
while (--argc) {
u8* cur = *(++argv);
if (!strcmp(cur, "-m32")) bit_mode = 32;
if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;//如果传入参数里有-m32或者armv7a-linux-androideabi,就设置bit_mode为32
if (!strcmp(cur, "-m64")) bit_mode = 64;//如果传入参数里有-m32或者armv7a-linux-androideabi,就设置bit_mode为32
if (!strcmp(cur, "-x")) x_set = 1;//如果传入参数里有-x,就设置x_set为1
if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1; //如果传入参数里有-fsanitize=address或者-fsanitize=memory,就设置asan_set为1
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; //如果传入参数里有FORTIFY_SOURCE就设置fortify_set = 1
if (!strcmp(cur, "-Wl,-z,defs") ||
!strcmp(cur, "-Wl,--no-undefined")) continue; //如果传入参数里有-Wl,-z,defs或者-Wl,--no-undefined,就直接pass掉,不传给clang。
cc_params[cc_par_cnt++] = cur;
}
if (getenv("AFL_HARDEN")) {//读取环境变量AFL_HARDEN
cc_params[cc_par_cnt++] = "-fstack-protector-all";//如果存在,就在cc_params里添加-fstack-protector-all
if (!fortify_set)
cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";//如果不存在fortify_set,就在cc_params里添加-D_FORTIFY_SOURCE=2
}
if (!asan_set) {//如果不存在asan_set
if (getenv("AFL_USE_ASAN")) {//获取环境变量AFL_USE_ASAN
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive");//如果环境变量AFL_USE_MSAN不存在,报错
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");//如果环境变量AFL_HARDEN不存在,报错
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";//在cc_params里添加-U_FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=address";//在cc_params里添加-fsanitize=address
} else if (getenv("AFL_USE_MSAN")) {//获取环境变量AFL_USE_MSAN
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive");//如果环境变量AFL_USE_ASAN不存在,报错
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");//如果环境变量AFL_HARDEN不存在,报错
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";//在cc_params里添加-U_FORTIFY_SOURCE
cc_params[cc_par_cnt++] = "-fsanitize=memory";//在cc_params里添加-fsanitize=memory
}
}
#ifdef USE_TRACE_PC //如果定义了USE_TRACE_PC宏
if (getenv("AFL_INST_RATIO"))
FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");//检查是否存在环境变量AFL_INST_RATIO,如果存在就抛出异常AFL_INST_RATIO not available at compile time with 'trace-pc'.
#endif /* USE_TRACE_PC */
if (!getenv("AFL_DONT_OPTIMIZE")) { //读取环境变量AFL_DONT_OPTIMIZE,如果不存在就添加-g -O3 -funroll-loops到参数里
cc_params[cc_par_cnt++] = "-g";
cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops";
}
if (getenv("AFL_NO_BUILTIN")) {//读取环境变量AFL_NO_BUILTIN,如果存在就添加-fno-builtin-strcmp等。
cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
}
//添加参数
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
/* When the user tries to use persistent or deferred forkserver modes by
appending a single line to the program, we want to reliably inject a
signature into the binary (to be picked up by afl-fuzz) and we want
to call a function from the runtime .o file. This is unnecessarily
painful for three reasons:
1) We need to convince the compiler not to optimize out the signature.
This is done with __attribute__((used)).
2) We need to convince the linker, when called with -Wl,--gc-sections,
not to do the same. This is done by forcing an assignment to a
'volatile' pointer.
3) We need to declare __afl_persistent_loop() in the global namespace,
but doing this within a method in a class is hard - :: and extern "C"
are forbidden and __attribute__((alias(...))) doesn't work. Hence the
__asm__ aliasing trick.
*/
cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
"({ static volatile char *_B __attribute__((used)); "
" _B = (char*)\"" PERSIST_SIG "\"; "
#ifdef __APPLE__
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
"__attribute__((visibility(\"default\"))) "
"int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */
"_L(_A); })";
cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
"do { static volatile char *_A __attribute__((used)); "
" _A = (char*)\"" DEFER_SIG "\"; "
#ifdef __APPLE__
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"___afl_manual_init\"); "
#else
"__attribute__((visibility(\"default\"))) "
"void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
"_I(); } while (0)";
if (x_set) {
cc_params[cc_par_cnt++] = "-x";//如果x_set为1,则添加参数-x none
cc_params[cc_par_cnt++] = "none";
}
#ifndef __ANDROID__
switch (bit_mode) {//根据bit_mode的值选择afl-llvm-rt
case 0://如果为0,即没有-m32和-m64选项,就向参数里添加obj_path/afl-llvm-rt.o
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
break;
case 32://如果为32,添加obj_path/afl-llvm-rt-32.o
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m32 is not supported by your compiler");
break;
case 64://如果为64,添加obj_path/afl-llvm-rt-64.o
cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);
if (access(cc_params[cc_par_cnt - 1], R_OK))
FATAL("-m64 is not supported by your compiler");
break;
}
#endif
cc_params[cc_par_cnt] = NULL;
}
/* Main entry point */
int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) {
#ifdef USE_TRACE_PC
SAYF(cCYA "afl-clang-fast [tpcg] " cBRI VERSION cRST " by \n" );
#else
SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by \n" );
#endif /* ^USE_TRACE_PC */
}
if (argc < 2) {
SAYF("\n"
"This is a helper application for afl-fuzz. It serves as a drop-in replacement\n"
"for clang, letting you recompile third-party code with the required runtime\n"
"instrumentation. A common use pattern would be one of the following:\n\n"
" CC=%s/afl-clang-fast ./configure\n"
" CXX=%s/afl-clang-fast++ ./configure\n\n"
"In contrast to the traditional afl-clang tool, this version is implemented as\n"
"an LLVM pass and tends to offer improved performance with slow programs.\n\n"
"You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. Setting\n"
"AFL_HARDEN enables hardening optimizations in the compiled code.\n\n",
BIN_PATH, BIN_PATH);
exit(1);
}
#ifndef __ANDROID__
find_obj(argv[0]);
#endif
edit_params(argc, argv);
execvp(cc_params[0], (char**)cc_params);//替换进程空间,执行要调用的clang和为其传递参数
FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
return 0;
}