### 讲一下 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`