[toc]
文件处理过程

源码分析
afl-gcc
afl-gcc是gcc/g++的wrapper,调用gcc/g++afl-gcc设置-B direcotry- gcc/g++调用afl对应的cpp、cc1/cc1/plus、as、ld。
/* |
afl-as
AFL的代码插桩,是在将源文件编译为汇编代码后,通过
afl-as完成的afl-as是as的封装
afl-as会在汇编代码的代码相应位置插入统计代码,然后调用真正的as进行汇编。统计代码是在afl-as.h文件中,afl-as负责找到每个 basic block 插入afl-as.h中的统计代码。afl-as.c:main()主要调用了两个函数:
/* |
add_instrumentation()
Process input file, generate modified_file. Insert instrumentation in all the appropriate places.
查找代码部分
只对代码部分插桩
利用代码文件的符号排列格式进行判断
如果是代码部分则会将instr_ok置1
查找基本块
- 方法
- 标识符:以 “点号”(
.)开始,以“冒号”(:)结束,中间是字母数字组合 - 跳转指令:
- 一般是进行比较根据比较结果来决定是否跳转(如 jnz xxx),条件跳转指令的下一条也是一个 basic block 的开始处。
- 如果是跳转指令则在指令后插入统计代码
- instrument_next置1
- 标识符:以 “点号”(
插桩
fprintf(outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, R(MAP_SIZE)); |
这里通过fprintf()将格式化字符串添加到汇编文件的相应位置
R(MAP_SIZE)即为0到MAP_SIZE之间的一个随机数。
eg.trampoline_fmt_32
static const u8* trampoline_fmt_32 = |
这一段汇编代码,主要的操作是:
- 保存
edi等寄存器 - 将
ecx的值设置为fprintf()所要打印的变量内容 - 调用方法
__afl_maybe_log() - 恢复寄存器
__afl_maybe_log是插桩代码所执行的实际内容
fork server
确定性 -fork- 子进程随机性
插桩
补充知识:
gcc/cc1
The g++ is a compiler driver. It knows how to invoke the actual compiler (cc1plus), assembler and linker. It does not know how to parse or compile the sources.
fork()
fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
参考网页
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.


