前言 本篇是(普通)插桩的最后一部分,主要是分析afl-as.h中关于桩代码的实现过程,文中涉及到大量汇编,需要一定的汇编语言基础才能看懂。此外,由于本人不喜AT&T格式的汇编,因此在分析时,选择用gdb查看经过afl-gcc编译后的程序,并以Intel汇编格式的桩代码进行分析。
前置知识 系统调用/库函数 本篇的内容以汇编为主,同时也用到了一些系统调用或者库函数调用,这里对它们做简要介绍,完整的内容信息可以通过man 2 ***(系统调用)
或man 3 ***(库函数)
进行查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 int atoi (const char *nptr) ;void *shmat (int shmid, const void *shmaddr, int shmflg) ;ssize_t write (int fd, const void *buf, size_t count) ;ssize_t read (int fd, void *buf, size_t count) ;pid_t fork (void ) ;pid_t waitpid (pid_t pid, int *wstatus, int options) ;void _exit(int status);int close (int fd) ;
afl-as.h源码分析 关键变量 1 2 3 4 5 6 7 8 9 10 11 (gdb) x/20sw 0x4018 0x4018 <__afl_area_ptr>: U"" 0x401c <__afl_area_ptr+4>: U"" 0x4020 <__afl_prev_loc>: U"" 0x4024 <__afl_prev_loc+4>: U"" 0x4028 <__afl_fork_pid>: U"" 0x402c <__afl_temp>: U"" 0x4030 <__afl_setup_failure>: U"" 0x4034 <__afl_setup_failure>: U"" 0x4038 <__afl_global_area_ptr>: U"" 0x403c <__afl_global_area_ptr+4>:U""
__afl_area_ptr:用于存储共享内存地址
__afl_prev_loc:上一个插桩的位置,由R(MAP_SIZE)生成的一个随机数
__afl_fork_pid:存储fork出来的子进程的pid
__afl_temp:临时缓冲区
__afl_setup_failure:标志位,若该值不为0,则退出程序
__afl_global_area_ptr:用于存储共享内存地址(全局变量 )
trampoline trampoline的含义是“蹦床”,在插桩时,这就是需要被插入的桩代码,不过它本身并没有实现什么功能,主要作用是调用__afl_maybe_log
函数,所以在这里可以把它理解为跳板,类似构造ROP链时用到的gadget。在afl-as.h文件中共定义了两种形式的trampoline,用于适配64/32位的运行环境,总体相差不大,这里我们介绍64位的trampoline_fmt_64:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 static const u8* trampoline_fmt_64 = "\n" "/* --- AFL TRAMPOLINE (64-BIT) --- */\n" "\n" ".align 4\n" "\n" "leaq -(128+24)(%%rsp), %%rsp\n" "movq %%rdx, 0(%%rsp)\n" "movq %%rcx, 8(%%rsp)\n" "movq %%rax, 16(%%rsp)\n" "movq $0x%08x, %%rcx\n" "call __afl_maybe_log\n" "movq 16(%%rsp), %%rax\n" "movq 8(%%rsp), %%rcx\n" "movq 0(%%rsp), %%rdx\n" "leaq (128+24)(%%rsp), %%rsp\n" "\n" "/* --- END --- */\n" "\n" ;
以上是afl-as.h文件中,以AT&T格式存在的源码;我们可以用gdb打开经过afl-gcc编译后的文件,执行如下指令,就可以看到Intel格式的汇编了,这里在主函数开头,刚好有一段trampoline,我们可以据此分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 (gdb) set disassembly-flavor intel (gdb) disassemble main Dump of assembler code for function main: 0x0000000000001220 <+0>: lea rsp,[rsp-0x98] 0x0000000000001228 <+8>: mov QWORD PTR [rsp],rdx 0x000000000000122c <+12>: mov QWORD PTR [rsp+0x8],rcx 0x0000000000001231 <+17>: mov QWORD PTR [rsp+0x10],rax 0x0000000000001236 <+22>: mov rcx,0x89ef 0x000000000000123d <+29>: call 0x15b8 <__afl_maybe_log> 0x0000000000001242 <+34>: mov rax,QWORD PTR [rsp+0x10] 0x0000000000001247 <+39>: mov rcx,QWORD PTR [rsp+0x8] 0x000000000000124c <+44>: mov rdx,QWORD PTR [rsp] 0x0000000000001250 <+48>: lea rsp,[rsp+0x98] 0x0000000000001258 <+56>: endbr64
由于这部分汇编很简单,就不在代码中注释了,首尾是保存和恢复现场的操作。核心就只有两条指令:
mov rcx, 0x89ef
:这里的 0x89af 实际上是一个随机数,用于定位执行到的代码块。参考上一篇add_instrumentation函数中的插桩语句
1 2 3 4 5 #define R(x) (random() % (x)) --> types.h fprintf (outf, use_64bit ? trampoline_fmt_64 : trampoline_fmt_32, R(MAP_SIZE));
call 0x15b8 <__afl_maybe_log>
:调用__afl_maybe_log函数
如下图所示,在经过 afl-gcc 插桩编译后,可以看到汇编中增加了表明代码块的 mov
语句和对 __afl_maybe_log()
调用,当执行到这段代码,fuzzer 知道这段代码被触发,从而统计每次输入样本的边缘覆盖率
__afl_maybe_log 该函数处理流程大致如下(图片来自初号机ScUpax0s )
1 2 3 4 5 6 7 8 (gdb) disassemble __afl_maybe_log Dump of assembler code for function __afl_maybe_log: 0x00000000000015b8 <+0>: lahf 0x00000000000015b9 <+1>: seto al 0x00000000000015bc <+4>: mov rdx,QWORD PTR [rip+0x2a55] # 0x4018 <__afl_area_ptr> 0x00000000000015c3 <+11>: test rdx,rdx 0x00000000000015c6 <+14>: je 0x15e8 <__afl_setup> End of assembler dump.
lahf
:将EFLAGS的低八位送入AH,即将标志寄存器EFLAGS中的SF、ZF、AF、PF、CF五个标志位分别传送到累加器AH的对应位。完整的EFLAGS可以参考这里 (注意:x64与x86Eflags寄存器的低32位相同,高32位保留,因此这里可直接拿来用)
seto
:溢出位置位
判断 __afl_area_ptr 是否为NULL:
如果为NULL,则跳转到__afl_setup
函数对__afl_area_ptr进行初始化;
如果不为NULL,继续执行
__afl_setup 1 2 3 4 5 6 7 8 9 10 11 (gdb) disassemble __afl_setup Dump of assembler code for function __afl_setup: 0x00000000000015e8 <+0>: cmp BYTE PTR [rip+0x2a41],0x0 # 0x4030 <__afl_setup_failure> 0x00000000000015ef <+7>: jne 0x15e0 <__afl_return> 0x00000000000015f1 <+9>: lea rdx,[rip+0x2a40] # 0x4038 <__afl_global_area_ptr> 0x00000000000015f8 <+16>: mov rdx,QWORD PTR [rdx] 0x00000000000015fb <+19>: test rdx,rdx 0x00000000000015fe <+22>: je 0x1609 <__afl_setup_first> 0x0000000000001600 <+24>: mov QWORD PTR [rip+0x2a11],rdx # 0x4018 <__afl_area_ptr> 0x0000000000001607 <+31>: jmp 0x15c8 <__afl_store> End of assembler dump.
判断__afl_setup_failure的值是否为0:
如果为0,继续执行
如果不为0,则跳转到__afl_return
返回
检查__afl_global_area_ptr文件指针是否为NULL:
__afl_setup_first 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 (gdb) disassemble __afl_setup_first Dump of assembler code for function __afl_setup_first: 0x0000000000001609 <+0>: lea rsp,[rsp-0x160] 0x0000000000001611 <+8>: mov QWORD PTR [rsp],rax 0x0000000000001615 <+12>: mov QWORD PTR [rsp+0x8],rcx 0x000000000000161a <+17>: mov QWORD PTR [rsp+0x10],rdi 0x000000000000161f <+22>: mov QWORD PTR [rsp+0x20],rsi 0x0000000000001624 <+27>: mov QWORD PTR [rsp+0x28],r8 0x0000000000001629 <+32>: mov QWORD PTR [rsp+0x30],r9 0x000000000000162e <+37>: mov QWORD PTR [rsp+0x38],r10 0x0000000000001633 <+42>: mov QWORD PTR [rsp+0x40],r11 0x0000000000001638 <+47>: movq QWORD PTR [rsp+0x60],xmm0 0x000000000000163e <+53>: movq QWORD PTR [rsp+0x70],xmm1 0x0000000000001644 <+59>: movq QWORD PTR [rsp+0x80],xmm2 0x000000000000164d <+68>: movq QWORD PTR [rsp+0x90],xmm3 0x0000000000001656 <+77>: movq QWORD PTR [rsp+0xa0],xmm4 0x000000000000165f <+86>: movq QWORD PTR [rsp+0xb0],xmm5 0x0000000000001668 <+95>: movq QWORD PTR [rsp+0xc0],xmm6 0x0000000000001671 <+104>: movq QWORD PTR [rsp+0xd0],xmm7 0x000000000000167a <+113>: movq QWORD PTR [rsp+0xe0],xmm8 0x0000000000001684 <+123>: movq QWORD PTR [rsp+0xf0],xmm9 0x000000000000168e <+133>: movq QWORD PTR [rsp+0x100],xmm10 0x0000000000001698 <+143>: movq QWORD PTR [rsp+0x110],xmm11 0x00000000000016a2 <+153>: movq QWORD PTR [rsp+0x120],xmm12 0x00000000000016ac <+163>: movq QWORD PTR [rsp+0x130],xmm13 0x00000000000016b6 <+173>: movq QWORD PTR [rsp+0x140],xmm14 0x00000000000016c0 <+183>: movq QWORD PTR [rsp+0x150],xmm15 0x00000000000016ca <+193>: push r12 0x00000000000016cc <+195>: mov r12,rsp 0x00000000000016cf <+198>: sub rsp,0x10 0x00000000000016d3 <+202>: and rsp,0xfffffffffffffff0 0x00000000000016d7 <+206>: lea rdi,[rip+0x2c1] # 0x199f <.AFL_SHM_ENV> 0x00000000000016de <+213>: call 0x1130 0x00000000000016e3 <+218>: test rax,rax 0x00000000000016e6 <+221>: je 0x18ce <__afl_setup_abort> 0x00000000000016ec <+227>: mov rdi,rax 0x00000000000016ef <+230>: call 0x1200 0x00000000000016f4 <+235>: xor rdx,rdx 0x00000000000016f7 <+238>: xor rsi,rsi 0x00000000000016fa <+241>: mov rdi,rax 0x00000000000016fd <+244>: call 0x11f0 0x0000000000001702 <+249>: cmp rax,0xffffffffffffffff 0x0000000000001706 <+253>: je 0x18ce <__afl_setup_abort> 0x000000000000170c <+259>: mov rdx,rax 0x000000000000170f <+262>: mov QWORD PTR [rip+0x2902],rax # 0x4018 <__afl_area_ptr> 0x0000000000001716 <+269>: lea rdx,[rip+0x291b] # 0x4038 <__afl_global_area_ptr> 0x000000000000171d <+276>: mov QWORD PTR [rdx],rax 0x0000000000001720 <+279>: mov rdx,rax End of assembler dump.
在栈中保存部分64位通用寄存器以及128位xmm寄存器组
读取环境变量_AFL_SHM_ENV的值,来获取共享内存 的shm_id:
如果获取失败,就跳转到__afl_setup_abort
如果获取成功:
先调用atoi
转换一下获取shm_id的值
再调用shmat
启用对共享内存的访问,并把共享内存连接到当前进程的地址空间。这里如果启用失败的话,也会跳转到__afl_setup_abort
最后,将shmat
返回的共享内存地址保存在变量 afl_area_ptr 和 afl_global_area_ptr 中
后面,将开始运行__afl_forkserver
__afl_forkserver 1 2 3 4 5 6 7 8 9 10 11 (gdb) disassemble __afl_forkserver Dump of assembler code for function __afl_forkserver: 0x0000000000001723 <+0>: push rdx 0x0000000000001724 <+1>: push rdx 0x0000000000001725 <+2>: mov rdx,0x4 # length 0x000000000000172c <+9>: lea rsi,[rip+0x28f9] # 0x402c <__afl_temp> 0x0000000000001733 <+16>: mov rdi,0xc7 # file desc 0x000000000000173a <+23>: call 0x1170 0x000000000000173f <+28>: cmp rax,0x4 0x0000000000001743 <+32>: jne 0x17e1 <__afl_fork_resume> End of assembler dump.
通过代码中的注释,我们可以理解这部分汇编的含义就是,将缓冲区__afl_temp中的4个字节,写入到0xc7号描述符所指定的文件中。由于这是在gdb中显示的,所以我们看到的是已经编译后的汇编,这里的0xc7,在实际源码中表现为 FORKSRV_FD+1(198+1 -> 0xc7),它代表着一个状态管道。
因此,这里真正的含义是,向状态管道中写入__afl_temp中的4个字节,告诉afl-fuzz (后面会分析到),forkserver已经成功启动,等待下一步指示 。
__afl_fork_wait_loop 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 (gdb) disassemble __afl_fork_wait_loop Dump of assembler code for function __afl_fork_wait_loop: 0x0000000000001749 <+0>: mov rdx,0x4 0x0000000000001750 <+7>: lea rsi,[rip+0x28d5] # 0x402c <__afl_temp> 0x0000000000001757 <+14>: mov rdi,0xc6 0x000000000000175e <+21>: call 0x11b0 0x0000000000001763 <+26>: cmp rax,0x4 0x0000000000001767 <+30>: jne 0x18c6 <__afl_die> 0x000000000000176d <+36>: call 0x1210 0x0000000000001772 <+41>: cmp rax,0x0 0x0000000000001776 <+45>: jl 0x18c6 <__afl_die> 0x000000000000177c <+51>: je 0x17e1 <__afl_fork_resume> 0x000000000000177e <+53>: mov DWORD PTR [rip+0x28a4],eax # 0x4028 <__afl_fork_pid> 0x0000000000001784 <+59>: mov rdx,0x4 0x000000000000178b <+66>: lea rsi,[rip+0x2896] # 0x4028 <__afl_fork_pid> 0x0000000000001792 <+73>: mov rdi,0xc7 0x0000000000001799 <+80>: call 0x1170 0x000000000000179e <+85>: mov rdx,0x0 0x00000000000017a5 <+92>: lea rsi,[rip+0x2880] # 0x402c <__afl_temp> 0x00000000000017ac <+99>: mov rdi,QWORD PTR [rip+0x2875] # 0x4028 <__afl_fork_pid> 0x00000000000017b3 <+106>: call 0x11e0 0x00000000000017b8 <+111>: cmp rax,0x0 0x00000000000017bc <+115>: jle 0x18c6 <__afl_die> 0x00000000000017c2 <+121>: mov rdx,0x4 0x00000000000017c9 <+128>: lea rsi,[rip+0x285c] # 0x402c <__afl_temp> 0x00000000000017d0 <+135>: mov rdi,0xc7 0x00000000000017d7 <+142>: call 0x1170 0x00000000000017dc <+147>: jmp 0x1749 <__afl_fork_wait_loop> End of assembler dump.
__afl_fork_resume 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 (gdb) disassemble __afl_fork_resume Dump of assembler code for function __afl_fork_resume: 0x00000000000017e1 <+0>: mov rdi,0xc6 0x00000000000017e8 <+7>: call 0x11a0 0x00000000000017ed <+12>: mov rdi,0xc7 0x00000000000017f4 <+19>: call 0x11a0 0x00000000000017f9 <+24>: pop rdx 0x00000000000017fa <+25>: pop rdx 0x00000000000017fb <+26>: mov rsp,r12 0x00000000000017fe <+29>: pop r12 0x0000000000001800 <+31>: mov rax,QWORD PTR [rsp] 0x0000000000001804 <+35>: mov rcx,QWORD PTR [rsp+0x8] 0x0000000000001809 <+40>: mov rdi,QWORD PTR [rsp+0x10] 0x000000000000180e <+45>: mov rsi,QWORD PTR [rsp+0x20] 0x0000000000001813 <+50>: mov r8,QWORD PTR [rsp+0x28] 0x0000000000001818 <+55>: mov r9,QWORD PTR [rsp+0x30] 0x000000000000181d <+60>: mov r10,QWORD PTR [rsp+0x38] 0x0000000000001822 <+65>: mov r11,QWORD PTR [rsp+0x40] 0x0000000000001827 <+70>: movq xmm0,QWORD PTR [rsp+0x60] 0x000000000000182d <+76>: movq xmm1,QWORD PTR [rsp+0x70] 0x0000000000001833 <+82>: movq xmm2,QWORD PTR [rsp+0x80] 0x000000000000183c <+91>: movq xmm3,QWORD PTR [rsp+0x90] 0x0000000000001845 <+100>: movq xmm4,QWORD PTR [rsp+0xa0] 0x000000000000184e <+109>: movq xmm5,QWORD PTR [rsp+0xb0] 0x0000000000001857 <+118>: movq xmm6,QWORD PTR [rsp+0xc0] 0x0000000000001860 <+127>: movq xmm7,QWORD PTR [rsp+0xd0] 0x0000000000001869 <+136>: movq xmm8,QWORD PTR [rsp+0xe0] 0x0000000000001873 <+146>: movq xmm9,QWORD PTR [rsp+0xf0] 0x000000000000187d <+156>: movq xmm10,QWORD PTR [rsp+0x100] 0x0000000000001887 <+166>: movq xmm11,QWORD PTR [rsp+0x110] 0x0000000000001891 <+176>: movq xmm12,QWORD PTR [rsp+0x120] 0x000000000000189b <+186>: movq xmm13,QWORD PTR [rsp+0x130] 0x00000000000018a5 <+196>: movq xmm14,QWORD PTR [rsp+0x140] 0x00000000000018af <+206>: movq xmm15,QWORD PTR [rsp+0x150] 0x00000000000018b9 <+216>: lea rsp,[rsp+0x160] 0x00000000000018c1 <+224>: jmp 0x15c8 <__afl_store> End of assembler dump.
调用close
关闭子进程中的文件描述符(状态管道和控制管道)
恢复子进程的寄存器状态
跳转到__afl_store
开始执行
__afl_store 1 2 3 4 5 6 7 (gdb) disassemble __afl_store Dump of assembler code for function __afl_store: 0x00000000000015c8 <+0>: xor rcx,QWORD PTR [rip+0x2a51] # 0x4020 <__afl_prev_loc> 0x00000000000015cf <+7>: xor QWORD PTR [rip+0x2a4a],rcx # 0x4020 <__afl_prev_loc> 0x00000000000015d6 <+14>: shr QWORD PTR [rip+0x2a43],1 # 0x4020 <__afl_prev_loc> 0x00000000000015dd <+21>: inc BYTE PTR [rdx+rcx*1] End of assembler dump.
计算并存储代码命中位置 ,__afl_prev_loc为前一次跳转位置,rcx为当前跳转位置,rdx为共享内存的地址
令__afl_prev_loc获取到rcx的值,即当前跳转位置,然后右移一位
在共享内存中,在新的存储路径的位置(将__afl_prev_loc与rcx异或后的结果作为下标)自增1
这部分直接通过汇编来解释,不是很好理解,拖进IDA,查看伪代码
先来看几个关键的变量,首先是a4,这里__afl_maybe_log
虽然有4个参数,原因是IDA识别的问题,IDA误将保存现场的操作当成了参数传递。因此在整个执行流程中,这里的a1,a2,a3都没有用到,真正的参数只有这里的a4 。回顾前文trampoline
中的汇编指令,可以得知,这里的a4 ,就是那通过 R(MAP_SIZE) 生成的一个随机数,这个随机数的作用就是定位当前插桩的位置 。另一个关键变量v6,这个通过对前面__afl_setup
和__afl_setup_first
的分析,可以得出,这个v6就是共享内存的地址 。根据这些信息,我们对这部分伪代码做个优化(这里摘取了sakura 与hicookie 的分析):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 cur_location = a4; shared_mem = v6; v7 = cur_location ^ prev_location; shared_mem[v7]++; prev_location = (prev_location ^ v7) >> 1 = cur_location >> 1
__afl_die 1 2 3 4 5 (gdb) disassemble __afl_die Dump of assembler code for function __afl_die: 0x00000000000018c6 <+0>: xor rax,rax 0x00000000000018c9 <+3>: call 0x1150 <_exit@plt> End of assembler dump.
设置参数status的值为0
调用_exit
终止程序
__afl_setup_abort 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 (gdb) disassemble __afl_setup_abort Dump of assembler code for function __afl_setup_abort: 0x00000000000018ce <+0>: inc BYTE PTR [rip+0x275c] # 0x4030 <__afl_setup_failure> 0x00000000000018d4 <+6>: mov rsp,r12 0x00000000000018d7 <+9>: pop r12 0x00000000000018d9 <+11>: mov rax,QWORD PTR [rsp] 0x00000000000018dd <+15>: mov rcx,QWORD PTR [rsp+0x8] 0x00000000000018e2 <+20>: mov rdi,QWORD PTR [rsp+0x10] 0x00000000000018e7 <+25>: mov rsi,QWORD PTR [rsp+0x20] 0x00000000000018ec <+30>: mov r8,QWORD PTR [rsp+0x28] 0x00000000000018f1 <+35>: mov r9,QWORD PTR [rsp+0x30] 0x00000000000018f6 <+40>: mov r10,QWORD PTR [rsp+0x38] 0x00000000000018fb <+45>: mov r11,QWORD PTR [rsp+0x40] 0x0000000000001900 <+50>: movq xmm0,QWORD PTR [rsp+0x60] 0x0000000000001906 <+56>: movq xmm1,QWORD PTR [rsp+0x70] 0x000000000000190c <+62>: movq xmm2,QWORD PTR [rsp+0x80] 0x0000000000001915 <+71>: movq xmm3,QWORD PTR [rsp+0x90] 0x000000000000191e <+80>: movq xmm4,QWORD PTR [rsp+0xa0] 0x0000000000001927 <+89>: movq xmm5,QWORD PTR [rsp+0xb0] 0x0000000000001930 <+98>: movq xmm6,QWORD PTR [rsp+0xc0] 0x0000000000001939 <+107>: movq xmm7,QWORD PTR [rsp+0xd0] 0x0000000000001942 <+116>: movq xmm8,QWORD PTR [rsp+0xe0] 0x000000000000194c <+126>: movq xmm9,QWORD PTR [rsp+0xf0] 0x0000000000001956 <+136>: movq xmm10,QWORD PTR [rsp+0x100] 0x0000000000001960 <+146>: movq xmm11,QWORD PTR [rsp+0x110] 0x000000000000196a <+156>: movq xmm12,QWORD PTR [rsp+0x120] 0x0000000000001974 <+166>: movq xmm13,QWORD PTR [rsp+0x130] 0x000000000000197e <+176>: movq xmm14,QWORD PTR [rsp+0x140] 0x0000000000001988 <+186>: movq xmm15,QWORD PTR [rsp+0x150] 0x0000000000001992 <+196>: lea rsp,[rsp+0x160] 0x000000000000199a <+204>: jmp 0x15e0 <__afl_return> End of assembler dump.
将变量__afl_setup_failure的值置1
恢复寄存器的状态
调用__afl_return
__afl_return 1 2 3 4 5 6 7 (gdb) disassemble __afl_return Dump of assembler code for function __afl_return: 0x00000000000015e0 <+0>: add al,0x7f 0x00000000000015e2 <+2>: sahf 0x00000000000015e3 <+3>: ret 0x00000000000015e4 <+4>: nop DWORD PTR [rax+0x0] End of assembler dump.
调整一下寄存器AL的值,此操作不影响AH的值
将AH的内容送给标志寄存器的低8位,也就是恢复EFLAGS低8位的值
执行ret指令返回
伪代码 将经过插桩编译后的程序,扔进IDA,找到函数__afl_maybe_log
并查看伪代码,便可以更加清晰的理解整个桩代码的执行流程:
参考资料
skr:sakuraのAFL源码全注释
Seebug:AFL 二三事——源码分析
AFL内部实现细节小记
AFL:afl-as.h
HICOOKIE:AFL-Learning
简书:AFL源码分析
EFLAGS寄存器图解
初号机/ScUpax0s:AFL源码阅读笔记之gcc与fuzz部分
CSDN:x86汇编基础
Jussi Judin:afl-fuzz on different file systems