模糊测试如穴居人第五篇:面向初学者的代码覆盖率之旅
引言
我们已在本系列前期讨论过代码覆盖率的重要性,今天将尝试理解一些基础概念、常见方法、相关工具,并了解流行模糊测试框架能够利用的技术。我们将避开晦涩策略,专注于被称为"面包黄油"的成熟主题领域。如果你是模糊测试或软件测试的新手,本文将以友好方式呈现内容。
核心定义
代码覆盖率
代码覆盖率是衡量测试、输入等覆盖程序代码程度的指标。这对模糊测试至关重要,因为它能跟踪目标程序中可触及的范围。
基本块
基本块是线性执行的代码序列,没有分支入口和出口。通过Ghidra分析示例密码检查程序,可以看到main()
函数被自动分解为多个代码块。
边/分支/转换
这些术语描述基本块之间的关系。在我们的示例中,基本块001006cf与两个不同块存在关系:001006e4和00100706,具体取决于命令行参数数量的条件判断。
路径
路径是程序执行遍历的基本块列表。示例程序中有三条不同路径,用橙色、绿色和红色线标示。
插桩
插桩是为模糊测试目标提供代码覆盖率反馈数据的过程,可以是重写无源代码的编译二进制文件,也可以是在每个基本块入口地址设置断点。
仅二进制
指没有源代码的目标,只有二进制文件。这类目标在嵌入式系统、MacOS和Windows环境中更常见。
常见策略
跟踪基本块
最简单的覆盖率收集方法是跟踪给定输入到达的基本块数量。这种方法实现简单,适用于各种目标,性能表现良好。但可能限制于首次到达基本块的输入值。
跟踪边和路径
AFL及其衍生工具采用此策略,不仅关注到达的基本块,还关注块间关系。AFL使用涉及关系的块地址元组来跟踪覆盖率,并通过编译时插桩或QEMU模拟器收集数据。
比较覆盖率/比较粉碎
不仅跟踪输入在程序块/边中的进展,还试图理解测试在程序比较中的进展。通过将大型比较分解为更小的块,可以更精细地跟踪进度。AFL++的LLVM模式和TinyInst等工具实现了这一技术。
奖励领域:使用硬件获取覆盖率数据
利用实际硬件获取覆盖率数据对仅二进制目标特别有帮助。Intel-PT是新款Intel CPU提供的实用程序,可提取运行软件的控制流信息。libxdc库能够高效解码Intel-PT跟踪数据,提供完美的覆盖率信息。
结论
本文介绍了该领域的基础术语、获取有意义覆盖率数据的常见策略,以及用于提取数据的工具。流行的模糊测试框架如AFL++和honggfuzz努力使其框架尽可能灵活,适用于广泛的目标。