[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.