1. 引言
研究背景:为了加快软件开发进程并集成外部功能,开发人员通常依赖开源代码存储库和包管理平台(如 Conan、Vcpkg、GitHub 以及 SourceForge)中的现有代码。这些资源被称为第三方库(Third Party Library,TPL)。随着开源软件生态系统的不断扩展,越来越多的软件项目正在基于TPL构建。Synopsys 最近的一份报告表明,令人震惊的是,97% 的经过审核的软件至少包含一个TPL。TPL 广泛使用
现存问题:然而,大量TPL的可靠性难以保证,一个软件项目中的安全漏洞很容易在整个软件供应链中传播,从而影响其他软件项目。在 Synopsys 报告中审查的软件中,81% 的软件至少包含一个已知的安全漏洞。此外,无意中引入不当 TPL 的开发人员也可能违反开源许可法规,从而导致法律问题。例如,思科和 VMware 都因不遵守 Linux 许可证中的规定而遇到了重大法律问题。这强调了在将 TPL 纳入软件项目时保持清醒的重要性,以维护最终应用程序的安全性和法律完整性。TPL 的引入可能导致安全漏洞的传播,并违反开源许可法规
TPL 检测是一种检测软件之间代码复用关系的通用技术,可以应用于大量的下游任务。一方面,开发人员和用户都热衷于在其软件中识别和管理 TPL,以减轻与 TPL 重用相关的安全风险。另一方面,软件抄袭和开源代码侵权的检测近年来引起了研究人员的极大关注。针对通过 TLP 减轻代码重用相关安全风险。TPL 的有效检测成为目前亟待解决的问题
1.1 研究现状
为了应对不可靠的 TPL 带来的潜在风险,许多研究人员专注于为软件应用程序开发有效的 TPL 检测方法。最初,大部分研究工作集中在 Java 中的 TPL 检测上。最近,人们对 C/C++ 二进制文件中的 TPL 检测越来越感兴趣。C/C++ 二进制文件中的 TPL 检测提出了更大的挑战,因为使用不同优化选项和架构编译的二进制文件表现出显着差异。具体来说,C/C++ 二进制文件中 TPL 检测的方法通常涉及收集候选 TPL 的广泛数据库,然后确定其中哪些已在目标二进制文件中重用。
C/C++ 二进制文件中的 TPL 检测可分为基于常量的 TPL 检测与基于相似性的 TPL 检测,其中前者通过从目标二进制文件和候选 TPL 中提取相同的常量特征(例如字符串、函数名称以及跳转表)来识别目标二进制文件中的 TPL 重用;后者将目标二进制文件的所有函数与候选 TPL 的函数进行比较。随后,设置预定阈值以确定是否发生了重用。基于常量的 TPL 检测,基于相似性的 TPL 检测
1.2 研究挑战
Challenge 1:基于常量的 TPL 检测在不同的优化选项和架构中表现出鲁棒性,但当常量数量有限或当重复的常量出现在不同的二进制文件中时,会导致检测 TPL 的性能下降。基于函数相似性的 TPL 检测可以通过比较所有函数来检测每个重用实例,但随着相似函数数量的增加以及不同优化选项和架构之间的变化,孤立函数匹配的准确性显着下降。现有 TPL 检测方法难以保证高精度
Challenge 2:现有TPL 检测仅限于文件级粒度,不足以揭示复杂的重用关系。复杂的重用关系可能包括部分重用和伪传播重用。现有方法只能检测目标软件重用了哪些 TPL,但无法进一步检测 TPL 中代码粒度的重用。现有的 TPL 检测方法无法有效实现细粒度检测
Challenge 3:现有 TPL 检测仅限于特定编译环境,无法有效应用于现实世界。现实世界中二进制文件的具体形态由其指令集架构和编译优化选项决定,只能检测特定编译环境中 TPL 的检测技术存在实际应用问题。现有工作在复杂编译设置下的 TPL 检测效果未知
1.3 研究内容
论文介绍了一种新颖的区域匹配框架 LibAM,它在各种优化选项和架构中表现出准确性和鲁棒性,可以检测精确的重用区域。研究发现,函数的重用不仅存在部分重用,还存在伪传播重用(对于一个二进制函数,其重用函数的被调用函数也是重用函数)。为了解决上述问题,LibAM 不直接在函数粒度进行匹配,而是利用函数调用关系将孤立的函数连接到 FCG 上的区域,并比较这些区域的相似性,而不是单个函数来判断重用。函数内联、函数调用删除以及编译器的其他对孤立函数匹配造成影响的更改对 FCG 的图相似性影响不大。LibAM 基于 FCG 的匹配实现 TPL 检测
LibAM 包括两个主要模块:区域生成和区域比较。这种创新框架可有效用于两项任务:TPL 检测和重复使用区域检测。前者旨在实现目标二进制文件 TPL 粒度的检测,后者旨在实现目标二进制文件函数粒度的检测。LibAM 将目标二进制文件和待检测二进制文件作为输入,最终输出目标二进制文件对应的重用的 TPL 与重用函数列表。LibAM 可以实现 TLP 检测和重复使用区域检测
1.4 实验结果
论文在公共数据集的基础上构建涵盖不同指令集架构与编译优化选项的数据集,对 LibAM 与 SOTA(LibDX、B2SFinder、ISRD 以及 LibDB) 研究进行全面的评估。实验结果显示,即使在不同的优化选项和架构中,LibAM 的性能也优于所有现有的 TPL 检测方法,并且在平均精度和召回率上分别超过了 SOTA 方法 23% 和 36%。此外,LibAM 在精确重用区域检测任务中表现出了高达 0.99 的精度和 0.844 的召回率(SOTA 无法实现)。TPL 粒度检测与函数粒度检测实验
论文通过检测大规模物联网固件中的重用关系并关联由 TPL 引入的漏洞,进一步评估了区域匹配在检测复杂重用关系和处理精确重用区域的下游任务中的能力。ModX 表明大量漏洞通常集中在软件代码的一小部分中。通过检测特定的重用区域,论文可以确定存在漏洞的函数是否被重用,避免了因为文件级别的重用检测而导致错误的漏洞关联。物联网固件漏洞检测实验
2. 研究动机
论文发现,当特定函数被重用时,其被调用函数也经常会被重用。例如,下图中由于 Minizip 重用了 Bzip2 中的函数 BZ2_bzCompress,因此 BZ2_bzCompress 的被调用函数也被重用。由此可知,相较于单独的函数(BZ2_bzCompress),函数调用关系(BZ2_bzCompress 的 FCG)中包含着更丰富的重用信息。函数调用关系包含更丰富的重用信息
在实际场景中存在很多部分复用的情况,且复用比例远小于文件级 TPL。下图中显示了 snkfile2k 在 Dataset_ISRD 数据集的 41 次重用中的重用比例,图中超过一半的重用关系仅重用了 TPL 中不到 50% 的函数,而这些部分重用可能会严重影响基于单独函数匹配 TPL 检测的性能。单独函数包含的重用信息不足
3. 研究概述
TPL 检测将目标二进制文件和待检测二进制文件作为输入,并尝试检测目标二进制文件重用了哪些 TPL。 论文旨在设计一种通用方法,以解决多种场景下 C/C++ 二进制文件的 TPL 检测任务。
3.1 问题描述
论文旨在检测来自软件和固件的目标二进制文件中的 TPL,如上图所示。软件中的二进制文件往往在单一架构中编译(例如,B2SFinder 仅检测 Windows 下的 PE 文件)。然而,固件中的二进制文件往往来自不同的架构,这提高了对 TPL 检测技术的要求。提出的方法旨在实现不同编译设置下目标二进制文件中的 TPL 的有效检测。实现不同编译设置二进制文件的 TPL 检测
论文旨在检测各种类型的 TPL 重用(动态链接、静态链接以及直接副本重用)。其中,动态链接重用中目标软件或固件会在文件目录中保留动态链接库文件,例如 .dll 或 .so 文件。论文构建一个由常用动态链接库文件组成的 TPL 数据库,并利用目标软件或固件中的动态链接库文件作为目标二进制文件进行检测。静态链接重用或直接副本重用中复杂的重用关系给 TPL 检测带来了挑战,论文从流行的 C/C++ 项目中收集二进制文件来创建 TPL 数据库,随后检测目标二进制文件中的哪些代码部分源自这些 TPL 二进制文件。值得注意的是,这些目标二进制文件可能会对重用的 TPL 进行较小的修改,例如 Minizip 删除了 Bzip2 中 BZ2_bloockSort 函数的字符串打印指令。论文的目标是从大量不同的代码中识别出相似的区域,并克服微小的修改差异。对于严重影响语义的剧烈变化,具有较大变化的代码是否被视为重用以及如何识别它们(甚至对于人类来说)是一个严峻的挑战,这超出了论文的数据集和论文的目标。论文只考虑之前工作中公共数据集中的微小可重用代码更改。实现动态连接、静态连接以及直接副本重用的检测
论文的目标是检测重用的 TPL 和重用的代码区域。先前关于 TPL 检测的研究无法确定 TPL 中的哪些代码部分被重用,这种不确定性被称为 TPL 结果的可解释性差。研究显示,大量的 TPL 重用是部分的,文件级 TPL 检测结果无法确定敏感部分(如易受攻击的代码或恶意软件)是否被重用。这种限制阻碍了许多下游任务,包括漏洞关联、恶意软件检测、软件抄袭检测等。论文的方法旨在确定目标二进制文件中哪些代码部分重用了 TPL 中代码的特定部分,为 TPL 检测结果提供可解释的证据。此外,由于 TPL 二进制文件中的函数名称是可访问的,可以通过从 NVD 收集补丁信息,通过比较重用的 TPL 函数名称和漏洞函数名称来检测重用区域中是否存在易受攻击的函数,即使目标二进制文件中的函数名称被剥夺了。对于 TPL 检测任务,论文收集广泛重用的 TPL 二进制文件并确定其中哪些被重用。对于区域检测任务,确定目标二进制文件中哪些函数源自 TPL,并可以获取重用的函数名称,因为 TPL 中相应函数名称很容易获得。文件粒度与函数粒度的 TPL 检测
3.2 概念定义
在论文中,从软件或固件中提取的检测到的二进制文件称为 目标二进制文件(Target Binary),而 TPL 数据库中的二进制文件表示为 TPL 二进制文件(TPL Binary)。此外,CFG(Control Flow Graph)代表控制流图,FCG(Function Call Graph)代表函数调用图,ACFG(Attribute Control Flow Graph)代表属性控制流图(由 Gemini 提出)。
锚点的定义:论文采用函数相似度计算方法来匹配 Target Binary 与 TPL Binary 中的函数。成功匹配的函数称为锚点,而一对匹配的函数对称为锚点对(Target Binary,TPL Binary)。具体来说,令 F_target 表示从 Target Binary 中提取的函数集,F_TPL 表示从 TPL Binary 中提取的函数集。 函数相似度计算方法记为 Sim(𝑓𝑖, 𝑓𝑗 ),其中 𝑓𝑖∈F_target,𝑓𝑗∈F_TPL。 锚点的定义如下所示:
区域的定义:论文将独立的锚点及其在 FCG 上的所有子函数连接起来,生成一个函数列表作为函数区域(Function Area)。具体来说,论文为每个锚点对生成两个不同的区域:一个是目标区域(Target Area),另一个是 TPL 区域(TPL Area)。给定锚对 (𝑎, 𝑏),目标区域 A(𝑎) 和候选区域 A(𝑏) 被定义为:
4. 研究方法
研究团队提出了一种新颖的区域匹配框架 LibAM,该框架由区域生成模块和区域比较模块组成,可以实现 Target Binary 中的 Reuse TPL 和 Reuse Function 的有效检测。
区域生成模块:首先使用 IDA Pro 从 Target Binary 和 TPL Binary 中提取 Function 并生成 FCG。之后通过 GNN 生成 Function 对应的嵌入向量并通过 Annoy 实现嵌入向量的高效匹配,其中成功匹配的函数被视为锚点对。 然后在 FCG 上建立了锚点对与其被调用函数之间的连接,为每个锚点对生成一个对函数区域。为 Target Binary 和 TPL Binary 创建了多对区域
区域比较模块:计算区域对(Target Area,TPL Area)之间的相似度,来确定是否构成重用区域。 相似度计算的综合考虑 structure similarity(通过 GNN 实现) 和 alignment length(锚点对齐算法),最终确定一个区域是否真正被重复利用。通过区域对之间的相似度确定区域是否被重用
4.1 区域生成模块
区域生成模块通过函数相似度计算技术,生成 Target Binary 与 TPL Binary 之间的锚点对,并基于锚点对生成区域对。该模块的实现包括锚点生成阶段和锚点扩展阶段,下面将详细介绍这两个阶段。
4.1.1 锚点生成阶段
这一阶段使用改进的 Gemini 作为函数相似度计算方法。具体来说,首先为每个基本块提取一个 7 维向量(字符串常量、数值常量、传输指令、调用指令、所有指令、算术指令和后代数量)。然后,将提取到的向量作为 CFG 上的节点实现 Target Binary 和 TPL Binary 中函数 ACFG 的生成(针对 Target Binary 中基本块数量大于 5 且指令数量大于 10 的函数,针对 TPL Binary 中的所有函数)。最后,将 ACFG 输入Structure2vec 网络中,得到函数的向量表示。GNN 网络的结构如上图所示。通过改进的 Gemini 实现 Target Binary 和 TPL Binary 中函数的相似度计算
4.1.2 锚点扩展阶段
上一阶段实现了锚点对列表的生成,列表中所有锚点对均可以映射到 Target FCG 和 TPL FCG 的节点(FCG 中的节点表示函数)。由于存在现象:Target Binary 的重用函数的被调用函数也可能是重用函数。锚点扩展阶段利用函数调用关系将独立的 FCG 节点扩展为 FCG 区域,如上图所示。具体来说,该阶段以锚点对作为输入,并为每个锚点对生成由 Target Area 和 TPL Area 组成的区域对。需要注意,Target Area 是不包含函数名称的函数列表,TPL Area 是包含函数名称的函数列表。通过锚点扩展将锚点对转换为区域对
4.2 区域比较模块
通过上一个模块可以实现 Target Binary 与 TPL Binary 间区域对的生成,区域比较模块的目标是比较这些区域对之间的相似度,以确定区域对之间是否存在重用关系。该模块的实现包括结构相似度计算阶段与对齐长度计算阶段,下面将详细介绍这两个阶段。
4.2.1 结构相似度计算阶段(粗粒度)
区域比较模块利用 GNN(Structure2vec) 生成区域向量(区域向量由一系列函数向量构成),并将向量的余弦相似度视为结构相似度 S。Structure2vec 的核心原理涉及图形模型推理,该模型对图像中节点特征进行一系列聚合操作,实现这些节点特征的有效表示(节点嵌入)。模型的训练包括初始化步骤、迭代聚合步骤以及监督学习优化步骤。
初始化步骤:使用节点特征矩阵初始化节点嵌入,该矩阵包含图中所有节点的初始特征向量。这些初始嵌入被用作后续迭代邻域聚合过程的起点。
迭代聚合步骤:在初始嵌入的基础上从邻居节点聚合信息,实现节点嵌入的更新。具体来说,该步骤以迭代的方式,通过神经网络的聚合函数为当前节点聚合来自于邻居节点的信息,并更新当前节点的嵌入,聚合表达式如下所示:
其中, 𝜇𝑖(𝑡) 表示节点 𝑖 在迭代 𝑡 时更新的嵌入,𝑁(𝑖) 代表节点 𝑖 的邻居集合,AGGREGATE 是基于神经网络的函数。上述聚合过程会迭代执行 T 次,最终生成嵌入 𝜇𝑖 (𝑇 ) :𝑖 ∈ 𝑉。
监督学习优化步骤:将同源区域视为正样本,非同源区域视为负样本构建数据集。以监督学习的方式训练 Structure2Vec 模型,以实现同源区域嵌入之间相似性的最大化。模型训练完成后,通过模型生成区域的嵌入表示。
4.2.2 对齐长度计算阶段(细粒度)
锚点对重叠问题:在锚点生成阶段,由于将所有相似度大于阈值的函数对视为锚点对,因此导致 Target Function 与 TPL Function 之间存在一对多的匹配关系(正确的匹配关系应该是一对一)。在下图中,TPL FCG 上的节点 A 和 节点 C在 Target FCG 上均具有三个匹配节点,节点 A 与节点 C 均与节点 6 存在匹配关系(A,C → 6)。
解决锚点重叠问题最直观的方式是枚举所有匹配组合以获取所有对齐区域组,但这种方法存在效率上的问题。为了有效该问题,论文提出 Anchor Alignment 算法以生成最长且不重叠的理想锚点对列表,并将理想锚点对列表的长度称为对齐长度。在下图中,理想锚点对列表为 [(1, A), (2, B), (3, C), (4, D)],对齐长度为 4。
Anchor Alignment 算法:参考图对齐领域的 RANSAC 算法(用于找到两幅图中点的映射关系),Anchor Alignment 算法不计算同型矩阵而是计算对齐长度,其伪代码如下所示。
经过对齐后,论文得到每个区域的最长对齐长度。在上图中,理想列表为 [(1, A), (3, C), (4, D)]。由于节点 (2, B) 在锚点检测阶段缺失,最终的最长对齐长度为 3。
4.3 优化策略
TPL 检测任务优化:在 Target Binary 和 TPL Binary 的每个组合中,论文迭代地随机选择一对候选区域来计算它们的结构相似性和对齐长度。 一旦候选区域的结构相似性(S)和比对长度(A)都超过指定的阈值,论文就可以确定 Target Binary 重用了TPL Binary 并终止循环。首先判断是否存在 TPL重用
区域检测任务优化:仅在 TPL 检测任务之后对检测到的元组(Target Binary、TPL Binary)进行区域检测。首先根据区域大小对区域生成模块中生成的区域进行降序排列。 当较大的区域被识别为重复使用时,其中包含的任何较小的区域都不会被重复计算,这进一步避免了区域数量过多的影响。 此外,如果一个区域同时与多个区域匹配,我们选择比对长度和结构相似度得分最高的区域作为最终重用区域。 这种方法不仅减少了计算冗余,而且保证了更准确的区域检测结果。之后判断哪些 Area 存在 TPL 重用
5. 实验评估
本节首先提出一系列 Research Question(RQ) ,并通过实验回答这些 RQ。下面列出了论文提出的一系列 RQ:
- RQ1:相较于其他工作,LibAM 在公共真实数据集的 TPL 检测任务中表现如何?
- RQ2:相较于其他工作,LibAM 在公共真实数据集的 Area 检测任务中表现如何?
- RQ3:LibAM 在检测不同优化选项和架构中的 TPL 方面是否足够稳健?
- RQ4:LibAM 的各个组件如何影响最终精度?
- RQ5:相较于其他工作,LibAM 的效率是否足够高?
- RQ6:LibAM 在大规模真实固件的 TPL 检测任务中表现如何?
5.1 数据集构建
为了实现 LibAM 在不同环境中准确性的评估,论文通过一个独立的数据集对所提模型进行训练,并通过三个额外的数据集进行训练好的模型进行评估。
Dataset_OSS:从 Github 和 SourceForge 爬取 260 个常用的开源项目,并手动将这些项目编译成 22,100 个二进制文件,涵盖三种架构(ARM、x86、x64)和四种优化选项(O0、O1、O2、O3)。这个广泛的数据集确保所提模型经过良好的训练并且能够处理各种现实场景,论文按 8:1:1 的比例将该数据集分为训练集、验证集以及测试集。开源软件数据集包括不同编译设置的各类开源软件
Dataset_ISRD:为了验证 LibAM 在现有公共现实世界数据集上的能力,论文将 ISRD 使用的公共现实世界数据集对模型进行评估。该数据集包含来自不同领域的 24 个流行开源项目的 85 个二进制文件,使用 x64 中的默认优化选项进行编译,并包含 74 个真实的部分重用。ISRD 数据集是唯一完整的公开 TLP 检测数据集
Dataset_ExtISRD:通过手动编译三种架构和四种优化选项来扩展 ISRD 数据集,这个扩展数据集包含 289 个二进制文件和 477 个真实的部分重用,是论文能够在更广泛的条件下评估 LibAM 的准确性,从而对其功能进行更全面的评估。通过使用不同指令集架构和编译优化选项实现 ISRD 数据集的扩展
Dataset_FW:收集了来自 10 个不同供应商的 167 个固件。此类固件涵盖各种设备类别,例如 IP 摄像机、路由器和交换机。论文使用 Binwalk 解压固件并提取了 12,699 个二进制文件。这个大规模数据集可以进一步测试 LibAM 在现实情况下的可扩展性和实用性。真实固件二进制文件组成的数据集
5.2 现有工作对比
将 LibAM 与各种现有方法进行比较,检查它们在不同场景下的优缺点。论文的目的是对基于常量和基于函数相似性的工作的准确性进行全面评估,并证明 LibAM 的有效性。
LibDX:是一种简单且快速的 TPL 检测方法。然而,LibDX 对恒定字符串的依赖可能影响其 TPL 检测性能。除此之外,当 Target Binary 和 TPL Binary 中的逻辑块恰好相似时,此方法可能会产生误报。
B2SFinder:具有较全面的常量特征,能够在检测 TPL 重用时执行更深入的分析。然而,由于特征数量的增加,B2SFinder 将具有更高的计算复杂性和时间成本。除此之外,作为一项基于常量的工作,B2SFinder 仍然面临着常量特征较少的二进制带来的性能下降。
ISRD_Gemini:ISRD 通过检查 TPL 是否存在一半以上的函数与目标二进制文件中的函数匹配,以确定重用。由于没有直接空用的 ISRD 源码,论文使用 Gemini 作为 ISRD 策略的基线,提出 ISRD_Gemini。
LibDB:引入 FCG 来对函数匹配结果进行简单的过滤,检测 FCG 上是否有超过三个匹配的函数以确定重用。这种方法虽然一定程度提高了重用检测的精度,但仍存在重叠问题。
5.3 RQ 1: TPL 检测
该实验评估了 LibAM 在数据集 Dataset_ISRD 上 TPL 检测任务的精确度、召回率以及 F1 分数,如下表所示。
LibAM 在精确度、召回率以及 F1 分数上全方位碾压了传统方法(LibDX、B2SFinder、ISRD-Gemini、LibDB)。针对精确度,LibAM 相较于排名第二的 LibDX 提高了 8%;针对召回率,LibAM 相较于排名第二的 LibDB 提高了 7.3%;针对 F1 分数,LibAM 相较于排名第二的 LibDX 提高了 15.9%。LibAM 可以精确的识别绝大多数 Dataset_ISRD 数据集中的重用,但由于 lzbench 中第三方组件 liblzg 的代码区域过小,因此 LibAM 无法有效识别(如何精确检测小代码区域的准确检测是一个潜在的研究方向)。LibAM 与其他方法进行对比
在现有的工作中,LibDX 实现了第二高的精度和召回率,证明二进制文件中的连续字符串可以提供弱语义信息;使用更多类型常量特征的 B2SFinder 的各项评价指标均较低,其原因可能在于该方法在整个文件粒度进行 TPL 检测。虽然 LibDX 具有不错的 TPL 检测性能,但由于 10 个连续字符串的条件较为苛刻,因此该方法存在漏报的情况。例如,在 csc 的 lzbench 重用中仅存在两个连续字符串。基于常量的 TPL 检测分析。ISRD-Gemini 的各项评价之别均较低,这证明直接使用函数相似度结果作为 TPL 检测结果是不可行的。LibDB 利用 FCG 中的公共边来过滤函数相似性结果并获得更高的召回率,但由于过滤机制过于无法解决重叠问题而造成了很多误报。基于相似度的 TLP 检测分析。LibAM 在函数匹配结果的基础上,将比较粒度扩大到 FCG 上的区域,进一步利用区域相似度和对其长度来检测区域相似度,可以实现 TPL 的准确检测。LibAM 的分析
5.4 RQ 2: Area 检测
该实验评估了 LibAM 在数据集 Dataset_ISRD 上 Area 检测任务的精确度、召回率以及 F1 分数,如下表所示。
LibAM 在精确度、召回率以及 F1 分数上全方位碾压了传统方法(LibDX、B2SFinder、ISRD-Gemini、LibDB)。针对精确度,LibAM 相较于排名第二的 LibDX 提高了 20.6%;针对召回率,LibAM 相较于排名第二的 LibDB 提高了 12.8%;针对 F1 分数,LibAM 相较于排名第二的 LibDX 提高了 29.1%。为了避免误报,论文将对其长度大于 3 的区域设置为重用区域,这使得一些小区域很容易被遗漏,从而导致召回率与精度之间的不一致(精度高于召回率,高精度对应低误报率,高召回率对应低漏报率)。LibAM 与其他方法进行对比
由于之前的工作不具备 Area 检测的能力,论文首先对这些工作进行了简单的修改。针对 LibDX 和 B2SFinder,论文将使用匹配常量特征的函数视为重用区域;针对 ISRD-Gemini,论文将匹配的函数作为重用区域;针对 LibDB,论文将满足三个公共边的函数作为复用区域。
LibDX 虽然具有较高的精度,但存在召回率较低的问题。通过对漏报案例进行分析,发现大量匹配的字符串没有被 LibDX 中的函数调用,这将严重影响 Area 复用的确认。B2SFinder 也存在同样的问题,但得益于更多特征的使用,该方法相较于 LibDX 具有更高的召回率。综上所述,基于常量的 TPL 检测方法的 Area 检测能力较差。基于常量的 Area 检测分析。ISRD-Gemini 直接使用匹配函数作为重用区域,其召回率为 57.3%;LibDB 通过公共边构建重用区域,其召回率为 71.9%。基于函数相似的工作相较于基于常量的工作在 Area 检测任务中具有更好的效果,但与 LibAM 相比仍有较大的差距。基于函数相似性的 Area 检测分析
5.5 RQ 3: 跨编译设置
该实验评估了 LibAM 在数据集 Dataset_ExtISRD 上 TPL 与 Area 检测能力。具体来说,该实验首先评估 LibAM 的跨编译优化级别 TPL 检测能力,实验结果如下图所示。需要注意,默认编译优化级别 default 是 O2 和 O3 的混合。
之后,该实验评估了 LibAM 的跨指令集架构 TPL 检测能力,实验结果如下图所示。需要注意,Mix 对应跨指令集架构+跨编译优化级别实验。
在不同优化级别实验中,LibAM 的平均精度为 93%;在不同架构实验中,LibAM 的平均精度为 96%。不同的优化级别对 LibAM 的影响相对更大,但即使在最坏的情况 LibAM 的 TPL 的检测精度仍为 90%。除此之外,在 Mix 实验中 LibAM 的检测精度也保持在 90%。综上所示,LibAM 在所有环境中均保持着较高的精度。 LibAM TPL 检测性能分析
基于常量特征的 TLP 检测在不同编译设置下具有天然的鲁棒性,B2SFinder 的结果非常稳定。相比之下,由于在不同环境中字符串顺序的变化,LibDX 的准确性显著下降但仍由于基于函数相似的 TLP 检测方法。基于常量的 TPL 检测分析
基于函数相似性的 TLP 检测在不同编译设置下极不稳定,LibDB 的最高召回率和最低召回率分别为 85% 个 47%,ISRD-Gemini 的最低精度甚至只有 13%。这是由于在不同环境下编译得到的同源函数变化很大,通过独立函数的相似性匹配的 TPL 检测性能无法得到保障。基于函数相似性的 TPL 检测分析
由上表可知,尽管 LibAM 在不同编译设置下可以实现很好的 TPL 检测,但其在不同编译设置下的 Area 检测仍是一个挑战。虽然,LibAM 的区域检测精度达到了 94%,但其区域检测召回率却只有 46.2%(存在较高的漏报率,如何平衡误报率和漏报率是未来研究的方向)。其原因在于,FCG 在不同优化选项和架构之间发生变化,LibAM 通过严格的过滤来保证高精度,但代价是损失一些召回率。LibAM Area 检测性能分析
5.6 RQ 4: 消融实验
为了评估 GNN 算法和锚点对齐算法对 LibAM 准确性的影响,创建两个 LibAM 变体并进行消融实验。LibAM_align 是不包含锚点对齐的 LibAM 变体,LibAM_gnn 是不包含 GNN 的 LibAM 变体。此外,论文还对锚点对齐算法阈值 n 的选择进行敏感性实验。
在 LibAM_align 的情况下,通过函数匹配获得锚点后,该框架仅依靠 GNN 算法来比较相关区域的结构相似性。如果一个区域的结构相似度超过阈值,则该区域被视为重用区域。该方法具有较高的召回率(漏报率低),但却存在精度较低(误报率高)的问题。这主要是由于存在大量相似结构相似(CFG,FCG)但无法对齐的非同源函数,从而导致 Negative 样本被判定为 Positive 样本。实验结果表明,锚点对齐算法在进一步过滤误报和提高 LibAM 精度方面起着重要作用。锚点对齐算法的有效性
在 LibAM_gnn 的情况下,通过函数匹配获得锚点后,该框架仅依靠对齐长度来比较相关区域的对齐相似性。如果一个区域的对齐相似度超过阈值,则该区域被视为重用区域。该方法具有具有较高的召回率(漏报率低),但却存在精度较低(误报率高)的问题。这主要是由于存在大量可以对齐但结构不相似的同源函数,从而导致 Negtive 样本被判定为 Positive 样本。实验结果表明,GNN 在进一步过滤误报和提高 LibAM 精度方面起着重要作用。GNN 的有效性
论文利用 Dataset_ISRD 与 Dataset_ExtISRD 数据集进一步研究了锚点对齐算法中不同阈值 n 对 LibAM 在 TPL 检测任务中准确性的影响,如上表所示。
对于 Dataset_ISRD,结果表明精度随着 n 的增加而逐渐增加,在 n=3 时达到最大值。 这种改进可归因于随着阈值变得更加严格,算法区分真假重用关系的能力增强。 相反,随着 n 的增加,召回率逐渐减弱,在 n=4 时出现大幅下降。 这种下降很可能是由于较高的阈值无意中排除了一些相关的重用关系。 尽管如此,LibAM 在 n=3 和 n=4 的 Dataset_ISRD 上都表现出了令人满意的准确性,实现了精度和召回率之间的平衡。Dataset_ISRD 数据集上阈值 n 实验
对于 Dataset_ExtISRD,该数据集中样本具有更复杂的重用模式。当 n 小于 4 时,精度随着 n 的增长而持续增加。当 n 大于或等于 4 时,精度随着 n 的增加而减小。这种现象表明,较高的阈值可能会阻止算法对微妙的重用模式的敏感性。 另一方面,随着n的增加,召回率仍然显着下降,这表明较大的阈值更有可能错过较小的重用区域。 该评估表明,即使在更复杂的场景中,算法也能够准确识别真正的重用关系。Dataset_ExtISRD 数据集上阈值 n 实验
5.7 RQ 5: 检测效率
该实验评估了各模型检测 Dataset_ISRD 和 Dataset_ExtISRD 所需的时间,实验结果如下表所示。论文对各模型每个步骤执行所用时间进行了统计,最终完成各模型效率的分析。
对于基于常量的工作,最重要的耗时步骤是 TPL detection。基于常量的工作中 Feature extraction 步骤专注于提取字符串或其他常量特征,比基于函数相似性的工作要快得多。LibDX 仅采用由向后索引算法加速的字符串特征,是所有方法中最快的。B2SFinder 由于无法使用倒排索引或字符串或数组等前缀树来加速 if/switch 特征的比较,因此需要更长的时间来匹配特征。基于常量方法的效率实验
对于基于函数相似性的作品,最耗时的步骤是 IDA Pro 上的 Feature extraction 。ISRD_Gemini 超过90%的时间花在提取 Feature extraction 上。LibDB 与 LibAM 也在该阶段花费了大量的时间,但由于引入优化策略其效率得到一定的提升。基于函数相似性方法的效率实验
4.8 RQ 5: 固件漏洞
在该实验中,论文评估了 LibAM 检测大规模现实世界中重用关系的能力,并验证了重用区域检测在关联漏洞方面的可能性。Firmware 收集:首先选择了 10 各供应商并未每个供应商收集了 30 个固件,之后使用 Binwalk 提取固件中的文件系统和二进制文件,最终成功从 164 个固件中提取出 12,699 个二进制文件。TPL 收集:首先从 Conan 和 Vcpkg 收集广泛使用的 TPL,然后对 Github 和 SourceForge 的一些知名项目进行编译,此外在一些基于 Linux 的操作系统中提取已知的 TPL,最后选择出 216 个存在公开漏洞信息的 TPL。
通过将 Firmware Binary 与 TPL Binary 作为 LibAM 的输入,对 Firmware Binary 中存在的 TPL 进行检测,最终从 164 个 Firmware 中检测到 3,353 个 TPL 并分析不同 TPL 对固件的影响,如下图所示。
除了 TPL 检测之外,论文进一步关联 TPL 重用可能引入的漏洞。为了实现这一目标,论文首先提取 TPL 版本相关字符串,之后通过字符串匹配技术检测 TPL 的特定版本,最后为 3,353 个 TPL 关联 14,863 个潜在漏洞。
不同的目标二进制文件总是倾向于重用 TPL 的相同区域:在上图 (a) 中,超过 85.8% 的 TPL 满足超过 50% 的检测到的目标二进制文件重复使用该区域的要求。 此外,43.5% 的TPL有超过 90%的目标二进制文件重用了其相同区域。 这一发现与公共 Dataset_ISRD 的基本事实相符。 例如,重用 Bzip2 的所有二进制共享 BZ2_bzBufferToBuffCompress 和 BZ2_bzBufferToBuffDecompress 函数以及它们各自的子函数。 这表明 TPL 中的某些代码区域比其他代码区域更有可能被重用,并且这些代码区域中的漏洞的影响范围更广泛。 因此,当 TPL 中的代码区域被识别为正在重用时,该区域更有可能被其他软件重用。 基于这一发现,研究人员可以分配额外的手动分析资源来仔细检查重用可能性较高的代码区域,从而提高漏洞检测和缓解工作的有效性。
不同的 TPL 中有许多相同的重用区域:在上图 (b) 中,超过 97.5% 的目标二进制文件满足检测到同一区域与两个以上TPL具有重用关系的要求。 此外,同一区域最多可以在 15 个不同的 TPL 中检测到。 这也反映在 Dataset_ISRD 的基本事实中。 例如,lzbench 重用了 precomp 中的大量函数,其中许多实际上来自 Brotli。 Dataset_ISRD 只分析了 lzbench 复用了 precomp 和 Brotli,但是经过区域检测,我们发现这两个复用实际上是同一个代码区域。 这表明区域检测能够检测复杂的重用关系。 此外,TPL 的不同区域可能代表不同的功能。 区分被更多 TPL 重用的区域和仅属于一个 TPL 的更具体区域有助于进一步的手动分析,例如,对更频繁重用的区域进行分析将产生更有价值的结果。