返回顶部
h

harness-writing驾驭写作

>

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.0.0
安全检测
已通过
111
下载量
免费
免费
0
收藏
概述
安装方式
版本历史

harness-writing

编写模糊测试驱动

模糊测试驱动是一个入口函数,它从模糊测试器接收随机数据,并将其路由到被测系统(SUT)。驱动的质量直接决定了哪些代码路径会被执行,以及是否能发现关键缺陷。编写不良的驱动可能会遗漏整个子系统,或产生不可重现的崩溃。

概述

驱动是连接模糊测试器随机字节生成与应用程序API之间的桥梁。它必须将原始字节解析为有意义的输入,调用目标函数,并优雅地处理边界情况。任何模糊测试设置中最重要的部分就是驱动——如果编写不当,应用程序的关键部分可能无法被覆盖。

关键概念

概念描述
驱动接收模糊测试器输入并调用被测目标代码的函数
SUT
被测系统——被模糊测试的代码 | | 入口点 | 模糊测试器要求的函数签名(例如 LLVMFuzzerTestOneInput) | | FuzzedDataProvider | 用于从原始字节中结构化提取类型化数据的辅助类 | | 确定性 | 确保相同输入始终产生相同行为的特性 | | 交错模糊测试 | 单个驱动基于输入执行多个操作 |

何时应用

应用此技术当:

  • - 首次创建新的模糊测试目标
  • 模糊测试活动代码覆盖率低或未发现缺陷
  • 模糊测试中发现的崩溃不可重现
  • 目标API需要复杂或结构化输入
  • 多个相关函数应一起测试

跳过此技术当:

  • - 使用项目中已有的经过良好测试的驱动
  • 工具提供满足需求的自动驱动生成
  • 目标已有全面的模糊测试基础设施

快速参考

任务模式
最小化C++驱动extern C int LLVMFuzzerTestOneInput(const uint8t* data, sizet size)
最小化Rust驱动
fuzz_target!(|data: &[u8]| { ... }) | | 大小验证 | if (size < MIN_SIZE) return 0; | | 转换为整数 | uint32t val = (uint32t)(data); | | 使用FuzzedDataProvider | FuzzedDataProvider fuzzed_data(data, size); | | 提取类型化数据(C++) | auto val = fuzzeddata.ConsumeIntegralt>(); | | 提取字符串(C++) | auto str = fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF); |

分步指南

步骤1:识别入口点

在代码库中找到以下函数:

  • - 接受外部输入(解析器、验证器、协议处理器)
  • 解析复杂数据格式(JSON、XML、二进制协议)
  • 执行安全关键操作(认证、加密)
  • 具有高圈复杂度或许多分支

好的目标通常是:

  • - 协议解析器
  • 文件格式解析器
  • 序列化/反序列化函数
  • 输入验证例程

步骤2:编写最小化驱动

从调用目标函数的最简单驱动开始:

C/C++:
cpp
extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
target_function(data, size);
return 0;
}

Rust:
rust
#![no_main]
use libfuzzersys::fuzztarget;

fuzz_target!(|data: &[u8]| {
target_function(data);
});

步骤3:添加输入验证

拒绝过小或过大而无意义的输入:

cpp
extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
// 确保有意义输入的最小大小
if (size < MININPUTSIZE || size > MAXINPUTSIZE) {
return 0;
}
target_function(data, size);
return 0;
}

理由: 模糊测试器生成各种大小的随机输入。你的驱动必须处理空、极小、极大或格式错误的输入,而不会在驱动本身中引起意外问题(SUT中的崩溃是可以的——这正是我们要寻找的)。

步骤4:结构化输入

对于需要类型化数据(整数、字符串等)的API,使用强制转换或像FuzzedDataProvider这样的辅助工具:

简单强制转换:
cpp
extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
if (size != 2 * sizeof(uint32_t)) {
return 0;
}

uint32t numerator = (uint32t)(data);
uint32t denominator = (uint32t)(data + sizeof(uint32_t));

divide(numerator, denominator);
return 0;
}

使用FuzzedDataProvider:
cpp
#include FuzzedDataProvider.h

extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
FuzzedDataProvider fuzzed_data(data, size);

sizet allocationsize = fuzzeddata.ConsumeIntegralt>();
std::vector str1 = fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF);
std::vector str2 = fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF);

concat(&str1[0], str1.size(), &str2[0], str2.size(), allocation_size);
return 0;
}

步骤5:测试和迭代

运行模糊测试器并监控:

  • - 代码覆盖率(是否到达所有感兴趣的路径?)
  • 每秒执行次数(是否足够快?)
  • 崩溃可重现性(能否用保存的输入重现崩溃?)

迭代改进驱动以优化这些指标。

常见模式

模式:超越字节数组——转换为整数

使用场景: 当目标期望原始类型如整数或浮点数时

实现:
cpp
extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
// 确保恰好2个4字节数字
if (size != 2 * sizeof(uint32_t)) {
return 0;
}

// 将输入拆分为两个整数
uint32t numerator = (uint32t)(data);
uint32t denominator = (uint32t)(data + sizeof(uint32_t));

divide(numerator, denominator);
return 0;
}

Rust等价实现:
rust
fuzz_target!(|data: &[u8]| {
if data.len() != 2 * std::mem::size_of::() {
return;
}

let numerator = i32::fromnebytes([data[0], data[1], data[2], data[3]]);
let denominator = i32::fromnebytes([data[4], data[5], data[6], data[7]]);

divide(numerator, denominator);
});

为什么有效: 任何8字节输入都是有效的。模糊测试器学会输入必须恰好为8字节,每次位翻转都会产生一个新的、可能有趣的输入。

模式:用于复杂输入的FuzzedDataProvider

使用场景: 当目标需要多个字符串、整数或可变长度数据时

实现:
cpp
#include FuzzedDataProvider.h

extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
FuzzedDataProvider fuzzed_data(data, size);

// 提取不同类型的数据
sizet allocationsize = fuzzeddata.ConsumeIntegralt>();

// 使用终止符消费可变长度字符串
std::vector str1 = fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF);
std::vector str2 = fuzzed_data.ConsumeBytesWithTerminator(32, 0xFF);

char* result = concat(&str1[0], str1.size(), &str2[0], str2.size(), allocation_size);
if (result != NULL) {
free(result);
}

return 0;
}

为什么有帮助: FuzzedDataProvider处理从字节流中提取结构化数据的复杂性。对于需要多种不同类型参数的API特别有用。

模式:交错模糊测试

使用场景: 当多个相关操作应在单个驱动中测试时

实现:
cpp
extern C int LLVMFuzzerTestOneInput(const uint8t *data, sizet size) {
if (size < 1 + 2 * sizeof(int32_t)) {
return 0;
}

// 第一个字节选择操作
uint8_t mode = data[0];

// 后续字节是操作数
int32_t numbers[2];
memcpy(numbers, data + 1, 2 * sizeof(int32

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 harness-writing-1776001201 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 harness-writing-1776001201 技能

通过命令行安装

skillhub install harness-writing-1776001201

下载

⬇ 下载 harness-writing v1.0.0(免费)

文件大小: 7.72 KB | 发布时间: 2026-4-13 10:32

v1.0.0 最新 2026-4-13 10:32
harness-writing 1.0.0 – Initial release

- Introduces comprehensive guidance for writing effective fuzzing harnesses across multiple languages.
- Covers key concepts, when to apply or skip harness techniques, and provides quick reference patterns for C++ and Rust.
- Includes step-by-step instructions: identifying entry points, writing minimal harnesses, adding input validation, structuring input, and best practices for iteration.
- Documents common patterns such as casting byte arrays, use of FuzzedDataProvider, and interleaved fuzzing.
- Provides rationale and tips to maximize fuzzing code coverage and bug discovery.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large