一、引言:harness——模糊测试的“桥梁”与“瓶颈”
模糊测试的高效性,取决于测试数据能否深入待测程序的内部逻辑。对于C语言编写的系统库和复杂应用,仅从最外层入口如命令行工具进行测试,往往只能覆盖外围代码,大量核心功能模块被层层封装,难以触及。为此,业界引入了模糊测试驱动(harness),并借助大语言模型(LLM)辅助harness的自动生成。
Harness 是一段“桥梁代码”,它接收模糊引擎生成的原始变异数据,将其转换为目标函数所需的参数格式,并按正确顺序调用一个或多个内部函数,从而将测试数据精准注入到待测模块的深层逻辑中,以覆盖从资源初始化、数据格式转换到核心业务处理、资源回收的完整链路。然而,在真实软件中,待测函数之间往往存在严密的调用顺序和数据依赖关系。harness自动生成过程的任何一步错误或缺失,都可能导致编译失败、运行时崩溃,甚至产生虚假的漏洞报告。
因此,为解决harness自动生成过程中函数粒度过粗、未匹配真实数据流以及LLM幻觉等问题,提升漏洞挖掘质量与效率,奇安信星图实验室、信息支援部队工程大学和武汉大学的研究团队在CCS 2026会议上发表了论文《Thinking More, Harnessing Better: Automatic Harness Generation with Dataflow Aggregation and Workflow Decomposition》。这项工作由奇安信星图实验室安全研究员张兴主导完成,其余作者为杨刚(信息支援部队工程大学)、黄子康(奇安信和武汉大学联培硕士生)、应凌云(奇安信星图实验室)、王聪冲(奇安信星图实验室)、刘璐(奇安信星图实验室)、尹斌(奇安信星图实验室)、王明义(奇安信星图实验室)、赵梓荃(奇安信天工实验室)、李敏(奇安信天工实验室)、陈震宇(奇安信星图实验室)和吴波(信息支援部队工程大学)。
论文结果表明,论文工具SynapseFlow相较于当前最先进的OSS-Fuzz-Gen(Google)和PromeFuzz(CCS 2025),分别带来3.07倍和4.26倍的分支覆盖率(llvm-cov branch)提升,并发现7个此前未知的漏洞。
论文链接:https://arxiv.org/abs/2607.07007 论文的代码及实验部分数据将在通过CCS组委会的评审后公开。

二、问题的本质:为什么LLM生成的harness质量受限?
LLM的发展为自动化harness生成带来了新的研究思路。然而,现有基于LLM的harness生成方法普遍存在一个根本性的缺陷——单轮生成。这些方法通常的做法是:将目标函数的源代码、以及静态分析预处理得到的控制流辅助信息一次性提交给LLM,引导LLM在单次交互中直接生成完整的harness代码。
这种单轮生成的思路存在两个核心问题:
- 函数选择不准确,缺乏数据流感知。现有工具在决定harness的待测函数序列时,往往依赖于简单的启发式规则(如函数调用关系)或API级别的语义相似度,缺乏对数据流的系统性理解。这导致生成的harness遗漏了关键的初始化或处理函数,覆盖率低;或引入了不相关的函数,降低模糊测试效率。
- LLM幻觉在生成中累积放大。当LLM被要求一次性生成一段复杂的、涉及多个函数调用的harness时,容易编造不存在的函数、错误使用宏定义、或插入文件I/O等损害模糊测试性能的操作。且在单轮生成的模式下,这些错误产生后无法被及时发现和修正,只能在最后的迭代修复过程根据错误信息尝试修复所有错误,容易在迭代过程中产生新的幻觉。
以论文中提到的j40项目(JPEG XL图像解析库)为例。一个高质量的harness需要按正确顺序调用7个关键函数,从j40_from_memory读取原始字节流开始,经过j40_output_format、j40_next_frame、j40_current_frame、j40_frame_pixels、j40_row等一系列处理,最后调用j40_free释放资源。
然而,在测试现有最先进的harness生成工具时,发现了许多问题:OSS-Fuzz-Gen只选择了两个不相关的函数,完全无法进行有意义的测试;CKGFuzzer生成了一个不完整的序列,还引入了手动的内存分配、拷贝等多余操作;PromeFuzz虽然识别了更多函数,却错误地包含了两个不同的输入处理函数j40_from_memory和j40_from_file,违反了libFuzzer的单入口原则,还加入了损害性能的文件操作。

导致这些问题的核心原因是,这些工具无法识别由输入/输出结构体所定义的函数间数据依赖关系,且出现函数组合错误时也无法得到有效的验证与修复。
三、SynapseFlow的核心设计与解决方案
面对上述挑战,论文设计并实现了harness自动化生成工具SynapseFlow,基于数据流聚合以及分阶段、可回滚的工作流分解,逐步解决复杂的harness生成任务。
SynapseFlow的整体工作流程如下图所示,包括两部分核心流程:

1.基于数据流聚合的函数三元组提取
这一阶段的目标是从源代码中自动识别出应该被放入同一个harness中协同测试的函数集合。论文将该集合称为函数三元组(Function Triplet, FT)。
步骤1:函数语义标注。首先,SynapseFlow对项目中的每个函数进行语义分类,定义了如下三种类型:
输入流函数(ISF):将字节流等外部原始数据输入内部结构体的函数,例如j40_from_memory。
处理函数(PRF):对已初始化的结构体进行读取、验证或转换等处理操作的函数,例如j40_next_frame、j40_frame_pixels。
辅助函数(HPF):辅助资源与生命周期管理的函数,包括结构体的初始化和释放等,例如j40_free。
这一标注过程结合了轻量级静态分析(基于tree-sitter实现)和LLM语义推理辅助:基于静态语法分析充分解析函数实体及数据结构类型,且对于指针参数等静态分析无法区分输入/输出的情形,设计相应的提示模板让LLM进行判断,并采用三提示词投票机制提升准确性。
步骤2:构建结构体流图(Structural Flow Graph, SFG)。完成静态分析后,SynapseFlow还将构建一张结构体流图:有向图,节点代表结构体类型,边代表函数对结构体的“消费—生产”关系。例如,j40_frame_pixels消费j40_frame、生产j40_pixels,就在图中形成一条从j40_frame到j40_pixels的边。结构体流图清晰地体现了数据在数据结构以及函数间的流动路径。

步骤3:函数三元组提取。最后,对于每一个ISF,SynapseFlow在SFG上进行前向数据流分析,收集所有可达的PRF和相关的HPF,形成一个完整的函数三元组。以j40为例,提取出的FT包含了7个关键函数。
2.基于工作流分解的harness生成
得到函数三元组之后,接下来进行harness生成。如前所述,让LLM一次性生成完整harness是脆弱的。因此,SynapseFlow将harness生成分解为四个顺序执行的阶段,并基于静态语法分析以及编译与短时运行验证,为每个阶段设计了相应的校验机制:
阶段1:函数文档生成。将FT中每个函数的原始源代码转换为结构化的API文档——包括函数签名、用途描述、使用场景和调用示例。这一步将低级语法抽象为高级语义知识,为后续代码生成提供知识基础。
阶段2:结构体代码片段拼接。利用SFG,识别FT中共享相同输入/输出结构体的函数,分组形成多个处理单元。对于每个单元,通过LLM生成一个局部的代码片段,正确地将输入结构体转换为输出结构体。该阶段将代码生成问题分解为了若干个可管理、可校验的局部问题。

阶段3:粗略代码组装。将阶段2生成的所有局部代码片段,按照SFG中的数据流顺序,逐步合并成一个完整的、可执行的harness原型。

阶段4:格式转换与代码优化。将粗略原型转换为最终的、可用于模糊测试的harness——包装成标准的libfuzzer harness格式,移除损害性能的操作,并基于编译与短时运行反馈优化函数调用及资源清理。
此外,SynapseFlow引入了一个分阶段回滚算法。其核心思想是:如果最终阶段harness无法编译或无法通过基本的运行时测试,不再迭代尝试修复错误,而是回滚到之前的某个阶段重新生成。例如,如果阶段4生成的代码编译失败,系统会回滚到阶段3重新组装;如果反复失败,则进一步回滚到阶段2甚至阶段1。这种机制有效遏制了错误的传播和累积,避免了LLM在迭代修复过程中可能由于幻觉引入的新错误。

四、实验评估
1.数据集构建及基准工具选取
论文在25个真实世界的开源C项目(包括17个库和8个应用程序)上对SynapseFlow进行了全面评估,并与三个最先进的工具进行了对比:OSS-Fuzz-Gen、CKGFuzzer和PromeFuzz,所有工具均使用相同的LLM后端Qwen3-32B。其中,数据集选取遵循三项原则:
- 基准可比性:纳入6个在前期工作中广泛使用的标准测试目标,确保评估结果可与现有研究直接对比。
- 压力测试:选取具有复杂协议或文件解析逻辑的项目,以检验各工具在复杂场景下的生成能力上限。
- 数据污染消减:引入11个此前从未在相关研究中出现过的项目(包括8个应用程序)。由于LLM可能已在训练集中包含有热门库的现有harness,在这些全新目标上评估能更纯粹地反映各生成技术的内在性能,而模型预训练数据的记忆效应。
2.代码覆盖率的显著提升
SynapseFlow在24个项目上取得了优于所有基线工具的分支覆盖率。具体而言,相比OSS-Fuzz-Gen、CKGFuzzer、PromeFuzz,分支覆盖率提升了3.07倍、 1.71倍、4.26倍。在函数覆盖方面,SynapseFlow分别提升了4.97倍、2.33倍和1.52倍。
经分析,代码覆盖率的提升源于三个关键因素:
- 全面的函数选择:通过SFG捕获了传递性依赖和长距离数据流,而基线工具依赖的启发式规则系统性遗漏了这些关系。
- 分阶段生成流程:将高风险的单轮生成转化为一系列可验证的简单步骤。
- 输入函数隔离:每个ISF对应一个harness,避免了多个输入函数混合在同一个harness中导致模糊测试的遗传算法失效。
3.漏洞检测能力的提升
论文选取了25个已知漏洞作为检测目标,包括19个代表性CVE和6个OSS-Fuzz已记录问题。对于每个漏洞函数,每个工具生成10个可编译的harness并运行24小时。结果显示,SynapseFlow生成的harness实现了更高的漏洞触发率,相比OSS-Fuzz-Gen、CKGFuzzer、PromeFuzz,分别提升1.77倍、1.51倍、1.36倍。
人工分析表明,基线工具的harness易出现参数初始化错误、遗漏关键函数调用、重复定义目标函数等问题,而SynapseFlow的分阶段验证机制有效避免了这些错误。
3.真实漏洞发现
SynapseFlow成功发现了7个此前从未被报告过的漏洞。这些漏洞涵盖了堆溢出、栈溢出、释放后使用、无限循环等多种类型,分布在file、libarchive、sqlite3等多个广泛使用的项目中。
分析发现,这些易受攻击的函数大多不在OSS-Fuzz的现有测试目标集合中,这表明尽管这些项目已经经历了约五年的持续模糊测试,这些漏洞却始终未被发现。SynapseFlow通过为这些被忽视的API自动生成有效harness,发掘了现有基础设施遗漏的漏洞。以expat项目中的堆溢出漏洞为例:漏洞函数在被调用时未检查目标缓冲区的大小,直接执行了内存拷贝操作。而lz4项目中的堆溢出则发生在处理最终未压缩字面量时,由于对目标缓冲区剩余空间的错误计算导致。这些漏洞的触发需要对特定函数进行正确的初始化序列调用,而只有SynapseFlow生成的harness包含了完整的调用链。
五、总结
面对日益复杂的软件生态和庞大的代码库,依靠人工编写模糊测试驱动已无法适应安全防护需求,而让LLM一步到位地生成完整harness同样存在多种缺陷。SynapseFlow研究证明,高质量的harness生成需要两方面的突破:一是使用数据流与语义来指导待测函数的选取与组合,而非依赖粗糙的启发式规则;二是将复杂的生成任务分解为多个可验证的子任务,避免在单次LLM调用中处理过多信息、产生难以修复的错误。
SynapseFlow将模糊测试的覆盖范围从零散的、不准确的函数调用,拓展到了由数据流定义的完整功能路径。这不仅减轻了安全研究员繁重的测试代码编写工作,更能让模糊测试真正覆盖到那些被忽视的、却潜藏着真实漏洞的代码路径。
此外,SynapseFlow研究工作作为奇安信技术研究院“天象”软件漏洞挖掘系统相关研究的一部分,目前已在“天象”软件漏洞挖掘系统中落地使用,能够自动化对源代码进行深入安全检测,并取得了良好的测试效果,发现多个真实软件中的漏洞。
论文链接:https://arxiv.org/abs/2607.07007
论文的代码及实验部分数据将在通过CCS组委会的评审后公开。