从main函数开始
1 | u8* inst_ratio_str = getenv("AFL_INST_RATIO"); |
先是从环境变量中拿了AFL_INST_RATIO
,这是插入指令的密度
1 | gettimeofday(&tv, &tz); |
这里是根据时间和pid来随机化seed
1 | if (inst_ratio_str) { |
把inst_ratio_str
转为数字
1 | if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) { |
如果使用ASAN或者MSAN的话,就会把插入指令的密度降低为1/3以加快速度。什么是ASAN呢
)
1 | if (!(pid = fork())) { |
如果插入完指令后,会fork子进程,用来执行as,将汇编变成二进制
再来看关键的函数add_instrumentation
add_instrumentation
1 | if (input_file) { |
首先打开汇编代码文件
1 | outfd = open(modified_file, O_WRONLY | O_EXCL | O_CREAT, 0600); |
再打开一个新的文件
1 | while (fgets(line, MAX_LINE, inf)) { |
循环读第一行,进行判断
1 | if (!pass_thru && !skip_intel && !skip_app && !skip_csect && instr_ok && |
进行一系列的判断,如果满足这些条件的话,就插入指令
1 | fputs(line, outf); |
输出原来那一行
1 | if (line[0] == '\t' && line[1] == '.') { |
寻找.text段
1 | if (strstr(line, ".code")) { |
判断32位还是64位
1 | // 这段注释大概意思是,在main函数,GCC aranch label,clang branch label,conditional branches处插入指令 |
1 | if (line[0] == '\t') { |
找到j
开头,但是每二个字母不是m
的指令,比如jne
,jbe
,后面的R(100)<instr_ration
是根据概率来选择插入或者不插入。
1 | if (ins_lines) |
再往后看到这里,会插入main_payload
(main_payload在头文件afl-as.h中)