# 26.16 讲一下 AFL 的插桩原理 · GitBook

### 讲一下 AFL 的插桩原理

插桩的本质：反馈导向的模糊测试

AFL 的插桩（instrumentation）就是一套用于收集代码覆盖率的探针。通过这些探针，AFL 可以知道某个输入执行了哪些代码路径

它的工作流程是这样的：

1. 编译时插桩：用 AFL 提供的特殊编译器（`afl-clang-fast` 或 `afl-gcc`）来编译目标程序
2. 运行时反馈：当程序执行时，插桩代码会向 AFL 反馈代码执行路径信息
3. 智能变异：AFL 根据这些反馈，判断哪些输入“有价值”（即探索了新的代码路径），然后对这些有价值的输入进行更多的变异

这个反馈循环是 AFL 高效的关键。它使得 AFL 能够自动绕过复杂的输入校验，深入到程序更深层次的逻辑中，从而找到隐藏的漏洞

插桩的原理实现

AFL 的插桩非常轻量级，它采用了一种基于基本块（Basic Block）的简单而巧妙的方案。

1. 什么是基本块？

在程序中，一个基本块是一段连续的代码，它只有一个入口点（第一条指令）和一个出口点（最后一条指令），且中间没有任何分支跳转

你可以把基本块看作是代码中的最小“执行单元”

2. AFL 的插桩步骤

AFL 在编译时，会在每个基本块的入口插入一段代码。这段代码会做两件事：

- 获取当前基本块的 ID：AFL 在编译时会给每个基本块分配一个唯一的随机 ID
- 记录基本块的 ID：AFL 维护一个共享内存区域，通常是一个大小为 64KB 的位图（bitmap）

当程序执行到一个新的基本块时，插入的代码会执行以下操作：

1. 获取当前基本块的 ID（假设是 `current_id`）
2. 获取上一个执行的基本块的 ID（假设是 `prev_id`）。AFL 用一个全局变量来保存这个 `prev_id`
3. 计算一个哈希值：`index = current_id XOR prev_id`
4. 将这个 `index` 映射到位图的某个位置，并将该位置的值加 1
5. 更新 `prev_id`，使其等于 `current_id`