书接上回:AFL源码阅读笔记(二)—— llvm_mode 和 pass 源码
💬 前两个笔记,我们看了两类插桩模式(gcc 和 llvm)及其代码。尽管插桩是 fuzzer 的一个重要环节,但我们不能只看到一点而忽略整体。afl-fuzz.c 文件就撑起了 AFL 整体,包括了种子变异、种子队列、种子选择等模糊测试的核心概念。
🧭 afl-fuzz.c 代码洋洋洒洒 8900 多行,对代码的解读不可能像前两个笔记一样,一行一行读。这部分代码阅读重在捋逻辑,弄清各部分间的关系。
程序作者(谷歌大佬)对整体代码的注释:
/* american fuzzy lop - fuzzer code --------------------------------由 Michael Zalewski 编写和维护;Forkserver 由 Jann Horn 设计这部分是真家伙(the real deal): 程序接受一个插桩的二进制文件,并尝试各种基本的模糊测试技巧,关注它们如何影响执行路径。
*/
头文件主要有三类来源,自定义头文件、C 标准库和 Linux C 头文件。
自定义头文件有:config.h
、types.h
、debug.h
、alloc-inl.h
、hash.h
和android-ashmen.h
。
Linux C 的头文件格式为
、
。
(1)对于 Linux 环境,定义宏 HAVE_AFFINITY
#ifdef __linux__
# define HAVE_AFFINITY 1
#endif /* __linux__ */
这个 affinity 是亲和的意思,这里指 CPU 亲和性。这样的直译让人迷惑,其实它指的就是 CPU 绑定。后面代码对 CPU 亲和性有处理。
CPU affinity 是一种调度属性, 它可以将一个进程“绑定” 到一个或一组CPU上。
(2)全局变量定义
作者对这部分做了一个描述,“许多全局变量,但它们主要是状态 UI 和其它没必要作为函数参数到处拖来拖去的东西”。
EXP_ST
是定义的宏,可以为空,可以为 static
。
#ifdef AFL_LIB
# define EXP_ST // 空
#else
# define EXP_ST static // 静态
#endif /* ^AFL_LIB */
至于变量类型,它们在 types.h
中定义。u
代表无符号 n 位整型,s
代表有符号 n 位整型。各变量含义见英文注释就行。
(3)测试用例队列 结构体
这是一个重要定义,测试用例队列也是 fuzzing 的核心概念之一,在整个模糊测试过程中都要维护这样一个队列。
struct queue_entry {u8* fname; // 测试用例的文件名 u32 len; // 输入长度,u8 cal_failed, // 校准失败?trim_done, // 修剪完了(即去除部分测试用例)? was_fuzzed, // 是否已完成过 fuzzing passed_det, // Deterministic stages passed? has_new_cov, // 触发新的覆盖率? var_behavior, // Variable behavior?favored, // Currently favored?fs_redundant; // Marked as redundant in the fs? u32 bitmap_size, // Number of bits set in bitmap exec_cksum; // Checksum of the execution trace u64 exec_us, // 执行时间(微秒)handicap, // Number of queue cycles behind depth; // Path depth u8* trace_mini; // Trace bytes, if keptu32 tc_ref; // Trace bytes ref count struct queue_entry *next, // 队列下一结点,如果有的话*next_100; // 100 elements ahead
};
(4)额外数据 结构体
struct extra_data {u8* data;u32 len;u32 hit_cnt;
};
(5)枚举类型
代码中定义了三种枚举类型,用作 Fuzzing 的阶段标识和错误码。
第一部分是 /* Fuzzing stages */
,表示 fuzzer 的种子变异策略。
enum {/* 00 */ STAGE_FLIP1, // 翻转 1 bit/* 01 */ STAGE_FLIP2, // 翻转 2 bit.../* 16 */ STAGE_SPLICE
};
第二部分是 /* Stage value types */
enum {/* 00 */ STAGE_VAL_NONE,/* 01 */ STAGE_VAL_LE,/* 02 */ STAGE_VAL_BE
};
第三部分是/* Execution status fault codes */
,对应执行过程中出现的异常。
enum {/* 00 */ FAULT_NONE,.../* 05 */ FAULT_NOBITS
};