使用 afl-unicorn: Fuzzing 任意二进制代码
字数 1259 2025-08-03 16:44:58

AFL-Unicorn 模糊测试任意二进制代码教学文档

1. AFL-Unicorn 概述

AFL-Unicorn 是 American Fuzzy Lop (AFL) 的一个扩展模式,它结合了 Unicorn 引擎的能力,允许对任意二进制代码进行模糊测试,即使这些代码无法通过传统命令行访问。

1.1 主要特点

  • 能够模糊测试嵌入式系统中的解析函数
  • 可以测试深藏在复杂、缓慢程序中的特定代码段
  • 提供 AFL 的所有基于覆盖率(coverage-based)的优点
  • 支持通过模拟(emulation)而非实际执行来测试代码

1.2 适用场景

  1. 嵌入式系统通过RF接收输入且不易调试的情况
  2. 复杂程序中难以通过传统工具访问的深层代码
  3. 需要测试特定函数而非整个程序的情况

2. 安装与配置

2.1 系统要求

  • Linux 系统(推荐 Ubuntu 16.04 LTS)
  • 已卸载任何现有的 Unicorn 二进制文件

2.2 安装步骤

# 克隆 afl-unicorn 仓库
git clone https://github.com/[afl-unicorn-repo]

# 构建和安装 AFL
cd /path/to/afl-unicorn
make
sudo make install

# 构建 Unicorn 支持
cd unicorn_mode
sudo ./build_unicorn_support.sh

注意:构建过程会编译并安装修补版的 Unicorn Engine v1.0.1

3. 工作原理

AFL-Unicorn 通过实现 AFL 的 QEMU 模式用于 Unicorn 引擎的块边缘检测来工作:

  1. AFL 使用来自模拟代码段的块覆盖信息驱动输入生成
  2. 测试工具加载目标代码,设置初始状态,并加载 AFL 变异的数据
  3. 模拟目标二进制代码
  4. 如果检测到崩溃或错误,抛出信号通知 AFL

4. 使用示例

4.1 目标代码示例

#define DATA_ADDRESS 0x00300000

int main(void) {
    unsigned char* data_buf = (unsigned char*)DATA_ADDRESS;
    
    if(data_buf[20] != 0) {
        // 崩溃条件1
        unsigned char invalid_read = *(unsigned char*)0x00000000;
    } 
    else if(data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
        // 崩溃条件2
        unsigned char invalid_read = *(unsigned char*)0x00000000;
    }
    else if(data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) {
        // 崩溃条件3
        unsigned char invalid_read = *(unsigned char*)0x00000000;
    }
    return 0;
}

4.2 Python 测试工具框架

import argparse
import os
import signal
from unicorn import *
from unicorn.mips_const import *

# 内存映射配置
CODE_ADDRESS = 0x00100000   # 代码加载地址
CODE_SIZE_MAX = 0x00010000  # 最大代码大小(64KB)
STACK_ADDRESS = 0x00200000  # 栈地址
STACK_SIZE = 0x00010000     # 栈大小(64KB)
DATA_ADDRESS = 0x00300000   # 变异数据存放地址
DATA_SIZE_MAX = 0x00010000  # 最大数据大小(64KB)

def force_crash(uc_error):
    """强制崩溃以通知AFL"""
    mem_errors = [UC_ERR_READ_UNMAPPED, UC_ERR_READ_PROT, ...]
    if uc_error.errno in mem_errors:
        os.kill(os.getpid(), signal.SIGSEGV)
    elif uc_error.errno == UC_ERR_INSN_INVALID:
        os.kill(os.getpid(), signal.SIGILL)
    else:
        os.kill(os.getpid(), signal.SIGABRT)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('input_file', type=str, help="变异输入文件路径")
    parser.add_argument('-d', '--debug', default=False, action="store_true")
    args = parser.parse_args()

    # 初始化Unicorn引擎(MIPS32大端)
    uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
    
    # 加载并映射二进制代码
    with open(BINARY_FILE, 'rb') as f:
        binary_code = f.read()
    uc.mem_map(CODE_ADDRESS, CODE_SIZE_MAX)
    uc.mem_write(CODE_ADDRESS, binary_code)
    
    # 设置程序计数器
    start_address = CODE_ADDRESS
    end_address = CODE_ADDRESS + 0xf4  # main()结束地址
    uc.reg_write(UC_MIPS_REG_PC, start_address)
    
    # 设置栈
    uc.mem_map(STACK_ADDRESS, STACK_SIZE)
    uc.reg_write(UC_MIPS_REG_SP, STACK_ADDRESS + STACK_SIZE)
    
    # 启动AFL fork服务器(必须执行至少1条指令)
    try:
        uc.emu_start(uc.reg_read(UC_MIPS_REG_PC), 0, 0, count=1)
    except UcError as e:
        print(f"启动fork服务器失败: {e}")
        return
    
    # 加载变异输入
    with open(args.input_file, 'rb') as f:
        input_data = f.read()
    uc.mem_map(DATA_ADDRESS, DATA_SIZE_MAX)
    uc.mem_write(DATA_ADDRESS, input_data)
    
    # 执行模拟
    try:
        uc.emu_start(uc.reg_read(UC_MIPS_REG_PC), end_address, timeout=0, count=0)
    except UcError as e:
        force_crash(e)

if __name__ == "__main__":
    main()

4.3 运行模糊测试

afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python simple_test_harness.py @@

参数说明:

  • -U: 启用Unicorn模式
  • -m none: 禁用内存限制(推荐用于Unicorn)
  • -i: 输入样本目录
  • -o: 输出目录
  • @@: AFL将替换为输入文件路径

5. 高级用法

5.1 性能优化

  • 基于C的测试工具比Python版本快5-10倍
  • 尽量减少测试工具中的不必要操作
  • 合理设置内存映射大小

5.2 路径探索

可以通过在特定条件下强制"崩溃"来探索代码路径:

if pc == TARGET_ADDRESS:  # 当执行到目标地址时
    os.kill(os.getpid(), signal.SIGUSR1)  # 使用自定义信号

AFL会保存导致到达该点的输入,可用于符号执行替代方案。

5.3 调试技巧

  1. 启用调试钩子:

    uc.hook_add(UC_HOOK_CODE, unicorn_debug_instruction)
    uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, unicorn_debug_mem_access)
    
  2. 使用Capstone反汇编:

    from capstone import *
    cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
    for i in cs.disasm(code, size):
        print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
    
  3. 寄存器转储:

    print(f"PC: 0x{uc.reg_read(UC_MIPS_REG_PC):x}")
    

6. 注意事项

  1. 必须执行至少一条指令才能正确启动AFL的fork服务器
  2. 内存映射应合理设置,避免冲突
  3. 测试工具必须正确处理各种错误条件
  4. 实际系统验证:仿真中发现的崩溃需要在真实系统上验证
  5. 性能考虑:复杂测试工具会显著降低模糊测试速度

7. 实际应用案例

  1. 嵌入式系统漏洞挖掘(如Broadcom WiFi芯片组漏洞)
  2. Windows/Linux/Android进程功能模拟测试
  3. 封闭系统(如IoT设备)的安全分析
  4. 协议解析器测试

8. 参考资料

  1. AFL-Unicorn GitHub仓库
  2. Unicorn引擎官网
  3. AFL官方文档
  4. Capstone反汇编框架

通过本教学文档,您应该能够理解AFL-Unicorn的核心概念、安装配置方法、基本和高级使用技巧,以及在实际安全研究中的应用方式。

AFL-Unicorn 模糊测试任意二进制代码教学文档 1. AFL-Unicorn 概述 AFL-Unicorn 是 American Fuzzy Lop (AFL) 的一个扩展模式,它结合了 Unicorn 引擎的能力,允许对任意二进制代码进行模糊测试,即使这些代码无法通过传统命令行访问。 1.1 主要特点 能够模糊测试嵌入式系统中的解析函数 可以测试深藏在复杂、缓慢程序中的特定代码段 提供 AFL 的所有基于覆盖率(coverage-based)的优点 支持通过模拟(emulation)而非实际执行来测试代码 1.2 适用场景 嵌入式系统通过RF接收输入且不易调试的情况 复杂程序中难以通过传统工具访问的深层代码 需要测试特定函数而非整个程序的情况 2. 安装与配置 2.1 系统要求 Linux 系统(推荐 Ubuntu 16.04 LTS) 已卸载任何现有的 Unicorn 二进制文件 2.2 安装步骤 注意:构建过程会编译并安装修补版的 Unicorn Engine v1.0.1 3. 工作原理 AFL-Unicorn 通过实现 AFL 的 QEMU 模式用于 Unicorn 引擎的块边缘检测来工作: AFL 使用来自模拟代码段的块覆盖信息驱动输入生成 测试工具加载目标代码,设置初始状态,并加载 AFL 变异的数据 模拟目标二进制代码 如果检测到崩溃或错误,抛出信号通知 AFL 4. 使用示例 4.1 目标代码示例 4.2 Python 测试工具框架 4.3 运行模糊测试 参数说明: -U : 启用Unicorn模式 -m none : 禁用内存限制(推荐用于Unicorn) -i : 输入样本目录 -o : 输出目录 @@ : AFL将替换为输入文件路径 5. 高级用法 5.1 性能优化 基于C的测试工具比Python版本快5-10倍 尽量减少测试工具中的不必要操作 合理设置内存映射大小 5.2 路径探索 可以通过在特定条件下强制"崩溃"来探索代码路径: AFL会保存导致到达该点的输入,可用于符号执行替代方案。 5.3 调试技巧 启用调试钩子: 使用Capstone反汇编: 寄存器转储: 6. 注意事项 必须执行至少一条指令 才能正确启动AFL的fork服务器 内存映射应合理设置,避免冲突 测试工具必须正确处理各种错误条件 实际系统验证:仿真中发现的崩溃需要在真实系统上验证 性能考虑:复杂测试工具会显著降低模糊测试速度 7. 实际应用案例 嵌入式系统漏洞挖掘(如Broadcom WiFi芯片组漏洞) Windows/Linux/Android进程功能模拟测试 封闭系统(如IoT设备)的安全分析 协议解析器测试 8. 参考资料 AFL-Unicorn GitHub仓库 Unicorn引擎官网 AFL官方文档 Capstone反汇编框架 通过本教学文档,您应该能够理解AFL-Unicorn的核心概念、安装配置方法、基本和高级使用技巧,以及在实际安全研究中的应用方式。