[AFL IV] afl-showmap
This tool displays raw tuple data captured by AFL instrumentation.
afl-showmap这个工具用来打印 一次程序执行过程中 被命中的执行路径
从这个工具中能看出, 执行路径是以什么方式存储的
举个🌰
还是以统计输入前缀中的‘a’个数为例子
1 | ┌──(root㉿Destroyer)-[/home/dustball/testafl] |
1 | afl-gcc -O0 -g test.c -o test |
1 | echo 'aaaaaaaabbc' > in |
1 | afl-showmap -o trace -- ./test < ./in |
afl-showmap的 打印效果
是<路径哈希值:命中次数桶>
元组
1 | ┌──(root㉿Destroyer)-[/home/dustball/testafl] |
注意这里打印的是命中次数桶,不是命中次数
044520这条路径命中8,9,…,15次都会打印为5
命中4,5,6,7次会打印4
🧄法分析
afl系列工具的老套路, afl-showmap先处理命令行参数, 然后建立共享内存, 然后执行一次程序, 然后就应该打印命中的执行路径了
1 | run_target(use_argv); |
在write_results中
1 | //u8* trace_bits = shmat(shm_id, NULL, 0); 就是共享内存, 用于记录执行路径 |
trace_bits中的值是谁填写的呢?showmap中显然没有写操作.

可以这个trace_bits由afl-showmap创建, 之后afl-showmap对trace_bits只有读操作, 至于如何记录, 这是目标程序中的afl桩要干的事情
1 | //桩干的事情: |
在目标程序执行完之后, afl-showmap会遍历一遍trace_bits, 进行一个按桶分类
1 | classify_counts(trace_bits, binary_mode ? |
1 | static void classify_counts(u8* mem, const u8* map) { |
这个桶实际上就是一个映射:
1 | static const u8 count_class_human[256] = { |
因此经过count_class_human
的映射后,
假设某条路径命中次数为7, 那么实际得到的trace_bits
值就是4,
意思是落到了第4个桶里
至于为甚么只记录8个桶子, 命中次数最大值是255
这是因为trace_bits以字节为单元, 一个字节代表一个执行路径元组. 一个字节最多就能表示[0,255],再命中一次就会整数上溢, 回绕到0
但是开发者认为可以为了性能牺牲这个准确性, 凑活着用吧