c++ libfuzzer自定义mutator c++如何为fuzzing编写变异策略

陌磊君_7334

陌磊君_7334

2026-04-06

405人浏览

原创

LLVMFuzzerCustomMutator 是可选的语义感知变异接口,用于在默认变异无效时介入;需严格遵守无堆分配、无异常、仅用 async-signal-safe 函数、通过 Rand() 获取随机数、输出长度≤max_size 等约束。

c++ libfuzzer自定义mutator c++如何为fuzzing编写变异策略

libFuzzer 的 LLVMFuzzerCustomMutator 是什么角色

它不是必须实现的接口,而是当你发现默认变异(bit flips、byte swaps、dictionary insertion 等)对目标代码无效时,才需要介入的“最后手段”。libFuzzer 在每次调用 LLVMFuzzerCustomMutator 时,会传入原始输入缓冲区、长度、最大允许长度和一个随机数生成器句柄;你返回新长度,libFuzzer 负责后续执行与崩溃判定。

关键点:这个函数不能分配堆内存(libFuzzer 不管理你的 malloc/free)、不能抛异常、不能调用非 async-signal-safe 函数(如 printf、malloc、std::string::append),否则会导致进程被 kill 或行为不可控。

  • 必须用 uint8_t* 直接操作内存,避免 std::vector 或 std::string
  • 所有随机数必须通过传入的 mutate_data->Rand() 获取,不能用 rand() 或 std::random_device
  • 输出长度不能超过 max_size,否则 libFuzzer 会截断并静默失败

如何编写一个安全可用的自定义 mutator 示例

假设你在 fuzz 一个解析 JSON 字符串的函数,发现默认变异很难生成合法但边缘的 JSON(比如嵌套过深、键名含控制字符、数值溢出)。你可以写一个轻量级 mutator,在已有输入上做语义感知调整:

extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t max_size, unsigned int seed) {
  // 使用 seed 初始化本地 rng(仅用于确定性调试,实际应只用 mutate_data->Rand())
  // 但注意:libFuzzer 不传 seed 给你 —— 这里只是示意;真实代码中删掉这行,直接用 Rand()
  auto &mutate_data = *reinterpret_cast<fuzzermutatedata>(seed); // ❌ 错误!libFuzzer 不传 FuzzerMutateData*
<p>// ✅ 正确方式:libFuzzer v14+ 传的是 FuzzerMutateData<em>,但你不能依赖其内部布局
// 实际应这样(参考 llvm-project/llvm/lib/Fuzzer/FuzzerInterface.h):
// struct FuzzerMutateData { uint32_t (</em>Rand)(); };
// 所以你只能调用 ((FuzzerMutateData*)seed)->Rand()</p>
<p>if (size == 0 || max_size == 0) return size;</p>
<p>// 示例:50% 概率插入一个合法 JSON key("k":)
if (((FuzzerMutateData*)seed)->Rand() % 2 == 0 && size + 4 </p>
<p>// 示例:20% 概率把某个数字改成 "9223372036854775807"(int64_max)
if (((FuzzerMutateData<em>)seed)->Rand() % 5 == 0) {
for (size_t i = 0; i + 10 = '0' && data[i]  maxint = "9223372036854775807";
size_t len = strlen(maxint);
if (i + len <p>return size; // 默认不修改
}</p></em></p></fuzzermutatedata>

注意:上面示例中的 strlen 和 memcpy 是允许的(async-signal-safe),但 std::min 必须替换成 C 风格三元表达式或手动比较,因为 可能触发 STL 内部锁或异常。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

为什么 LLVMFuzzerCustomCrossOver 往往比自定义 mutator 更值得优先尝试

交叉变异(crossover)复用已有语料中的子结构,天然更贴近语法/协议边界。对 parser、decoder、config loader 类目标,它常比手工写 mutator 更快产出有效输入。

  • LLVMFuzzerCustomCrossOver 接收两个输入指针和长度,返回新长度;同样禁止堆分配和非 async-signal-safe 调用
  • 简单策略:随机选一个分割点,拼接 data1[0..pos] + data2[pos..],再做一次小范围翻转
  • libFuzzer 默认已启用 crossover,但只有在 corpus 达到一定规模(默认 1000 个输入)后才高频触发 —— 如果你刚启动 fuzz,先等它跑一阵再评估是否需自定义

调试自定义 mutator 时最常踩的三个坑

libFuzzer 不会告诉你 mutator 崩溃的具体原因,只会打印 ERROR: libFuzzer: deadly signal 或静默跳过变异 —— 这让你很难定位问题。

  • 误用 std::string 或 std::vector:它们的构造/析构可能调用 malloc 或抛 std::bad_alloc,触发信号终止
  • 越界读写:比如用 data[size] 当作结束符判断,但 size 可能为 0;或 memcpy 长度算错导致覆盖 max_size 边界
  • 忽略 max_size 限制:返回值 > max_size 时 libFuzzer 会截断,但你的逻辑可能已破坏数据一致性(比如插入字符串后没更新后续偏移),导致后续解析崩溃而非你的 mutator 崩溃

建议在 mutator 开头加一句:if (size > max_size) return size;,并始终用 memmove/memcpy 替代手写循环——边界更可控。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2335

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

3842

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

1276

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

4459

7

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

7519

3

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.18

1069

5

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.25

3520

5

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

2023.06.20

948

5

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.28

1029

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习