libFuzzer是C++中最常用、集成度最高且适合库函数级测试的模糊测试方案,需用clang≥v9配合ASan/UBSan编译,通过定义LLVMFuzzerTestOneInput函数实现目标测试,并依赖语料、字典和覆盖引导提升效果。

用 C++ 做模糊测试,libFuzzer 是最常用、集成度最高、也最适合库函数级测试的方案。它不是独立运行的黑盒工具,而是以 静态链接方式嵌入目标代码,配合 LLVM 编译器(clang)使用,能高效发现内存越界、空指针解引用、断言失败等安全问题。
一、环境准备:编译器与基础依赖
libFuzzer 是 LLVM 的一部分,需使用 clang(≥v9)并启用 sanitizer 支持:
- 安装 LLVM 工具链(推荐通过官方预编译包或系统包管理器,如 Ubuntu 上
sudo apt install llvm-dev libclang-dev) - 确保
clang++可用,且支持-fsanitize=fuzzer,address,undefined - 无需额外安装 libFuzzer 库——它已随 clang 分发,头文件在
<fuzzer/FuzzedDataProvider.h>(可选),核心是链接-fsanitize=fuzzer
二、编写一个最简 Fuzzer Target
关键:定义一个名为 LLVMFuzzerTestOneInput 的 C 风格函数,接收 const uint8_t* data 和 size_t size,返回 int(固定为 0):
// fuzz_target.cpp
#include <cstdint>
#include <cstddef>
<p>// 假设你要测的函数(示例:一个有漏洞的字符串解析)
bool parse_version(const char* s);</p><p>extern "C" int LLVMFuzzerTestOneInput(const uint8_t<em> data, size_t size) {
// 将输入转为以 '\0' 结尾的字符串(注意:原始数据可能含 \0,谨慎截断)
if (size == 0) return 0;
// 简单复制 + 添加终止符(实际中建议用 FuzzedDataProvider 或手动安全处理)
char</em> buf = new char[size + 1];
memcpy(buf, data, size);
buf[size] = '\0';</p><p>parse_version(buf); // 被测函数</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/6e7abc4abb9f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">C++免费学习笔记(深入)</a>”;</p><p>delete[] buf;
return 0;
}⚠️ 注意:不要在 fuzzer 中做不可控的 I/O、sleep、随机数(除非可控种子)、全局状态修改;避免无限循环(可加简单计数保护)。
三、编译与运行
用 clang++ 一次性编译+链接,开启 AddressSanitizer(ASan)和 UndefinedBehaviorSanitizer(UBSan)能显著提升 crash 捕获能力:
clang++ -g -O2 -fsanitize=fuzzer,address,undefined \ -I/path/to/your/include \ fuzz_target.cpp your_lib.cpp -o fuzzer
运行:
./fuzzer # 从内存生成随机输入,自动变异 ./fuzzer corpus/ # 从已有语料目录启动(推荐,加速覆盖) ./fuzzer corpus/ -max_len=1024 -timeout=30
常见参数:-max_total_time(总运行秒数)、-jobs(多进程)、-workers(工作线程)。
四、提升效果的关键技巧
让模糊测试更准、更快、更深入:
- 提供初始语料(corpus):放几个典型输入(如合法/非法 JSON、HTTP 头、协议片段)到文件夹,libFuzzer 会基于它们变异
- 使用 FuzzedDataProvider:方便地从原始字节数组提取 int/float/string/vector,避免手写解析逻辑出错
- 定制字典(-dict=):比如协议关键字、magic bytes,告诉 fuzzer 哪些 token 更可能触发深层逻辑
- 覆盖引导(默认开启):libFuzzer 自动追踪代码块/边缘覆盖,优先变异能扩大覆盖的输入
-
避免误报:若被测函数内部调用
exit()或abort(),需重写为返回错误码,否则 fuzzer 会误判为 crash
不复杂但容易忽略:真正有效的 fuzzing 不靠暴力,而靠精准的目标函数封装 + 合理的输入建模 + 持续的语料维护。从一个干净的 LLVMFuzzerTestOneInput 开始,比套框架更重要。











