摘要
虽然第三方库(TPL)被广泛复用以提升软件开发效率,但它们也可能引入潜在的安全风险(例如漏洞传播)。为识别复用TPL以降低此类风险而提出的软件成分分析(SCA),已成为现代DevSecOps中不可或缺的流程。作为主流SCA技术之一,二进制到源码SCA通过二进制与源代码的匹配,识别二进制文件中包含的第三方源码项目。这一过程在逆向工程中极具挑战性,因为经过编译后二进制与源码会呈现显著差异。
现有二进制到源码SCA技术主要依赖基础语法特征,这些特征在大规模TPL数据集中存在冗余且缺乏鲁棒性,导致不可避免的误报和召回率下降。为突破这些局限,我们提出了BinaryAI——一种新型两阶段二进制源码匹配SCA技术,能够同时捕获语法和语义代码特征。首先,BinaryAI训练基于Transformer的模型生成函数级嵌入表示,为每个二进制函数匹配相似源码函数;随后通过链接时局部性优化函数匹配,基于匹配成功的源码函数比例检测复用的TPL。实验结果表明,BinaryAI在二进制源码匹配及下游SCA任务中均展现出卓越性能。
引言
软件成分分析(Software Composition Analysis, SCA)[24, 53, 71]旨在识别软件制品中使用的开源组件(即复用的第三方库,TPL),以支持高效低成本的开发。基于SCA结果,开发者可以追踪TPL引入的安全威胁(如漏洞传播和许可证违规)[4, 27, 36, 52]。根据目标软件项目和待识别TPL的不同形态,现有SCA技术可分为多种类型(例如二进制到二进制SCA [54, 55, 69]和二进制到源码SCA [13, 41, 71])。其中,二进制到源码SCA作为主流技术之一,通过提取二进制文件和大规模TPL数据集的代码特征(即二进制源码匹配),计算两者相似性以识别二进制文件中包含的源码级复用TPL。在现代DevSecOps的持续集成/持续交付(CI/CD)流程中,二进制到源码SCA通常集成至构建或部署阶段,用于自动化扫描二进制文件中的组件及其安全风险。相较于其他技术,二进制到源码SCA可通过便捷扩展TPL数据集覆盖新开源仓库,在实际软件开发场景中更具可扩展性和实用性[13, 44, 53]。
现有二进制到源码SCA技术依赖编译后保持一致的基础语法特征(如字符串常量)进行二进制源码匹配。例如,最先进的学术工具B2SFinder[71]采用加权匹配算法组合三种基础语法特征的匹配技术。尽管这些特征能建立二进制与源码的对应关系,现有技术仍存在两大局限:首先,基础语法特征在大规模TPL数据集中冗余度高,导致特征重复并降低SCA精度(即匹配过程中产生误报);其次,复用TPL与目标二进制文件之间可能缺乏共同的基础语法特征(尤其是去除了函数名等字符串的二进制文件[71]),严重损害依赖此类特征的SCA召回率[13]。事实上,二进制代码与源码差异显著,编译后保留的稳定特征极少,传统基础特征匹配甚至可能因特征缺失导致漏报。因此,需采用细粒度特征(如函数级特征)改进匹配精度,因函数级特征相比基础语法特征蕴含更丰富的语法和语义信息。
本文提出BinaryAI——一种基于智能函数级二进制源码匹配的SCA技术。针对编译差异,我们采用基于Transformer的模型捕获基于词元的语法特征,生成函数嵌入以计算二进制与源码函数的相似性。具体而言,BinaryAI以Pythia[8]的大语言模型为起点,通过监督式对比学习[43]进行预训练。基于训练后的模型,我们离线生成大规模TPL数据集中所有源码函数的嵌入并存储至向量数据库。对于待检测的二进制文件,BinaryAI通过反编译提取二进制函数,将其编码为嵌入向量后从数据库中检索Top-k相似源码函数。此外,BinaryAI在第二阶段采用局部性驱动的匹配策略:利用链接时局部性(link-time locality)和函数调用图等结构化信息捕获语义特征,从Top-k结果中精准定位匹配的源码函数。最终,BinaryAI基于匹配函数计算复用函数比例作为TPL与二进制文件的相似度,并通过预设阈值识别复用组件及其安全风险(遵循已有方法[13, 54, 55, 71])。
我们通过三组实验验证BinaryAI的有效性:1) 包含约1000万正样本函数对的训练集;2) 构建SCA数据库的大规模TPL数据集;3) 人工标注组件及二进制-源码函数映射的测试集。实验表明:
• BinaryAI的匹配模型在SCA测试集上的召回率@1(Recall@1)从CodeCMR的11.92%提升至22.73%;
• 局部性驱动匹配策略进一步将Recall@1从22.73%提升至66.90%(接近模型能力上限70.45%即Recall@100);
• 在TPL检测任务中,BinaryAI显著优于现有工具:相较学术工具B2SFinder,精度(Precision)从31.78%提升至85.84%,召回率(Recall)从54.93%提升至64.98%;甚至超越商业SCA产品,精度从73.36%提升至85.84%,召回率从59.81%提升至64.98%。
本文的主要贡献包括:
• 首创将函数级二进制源码匹配应用于二进制到源码SCA,并训练基于Transformer的模型检索相似源码函数;
• 提出两阶段函数匹配机制,利用链接时局部性增强Top-k结果的匹配精度;
• 实验证明BinaryAI的匹配模型性能超越CodeCMR,且其SCA工具的综合表现优于现有学术与商业方案。
以下是这段话的中文翻译:
2 背景与动机
2.1 软件成分分析(SCA)
软件成分分析(Software Composition Analysis, SCA)旨在识别目标软件项目中的第三方库(TPLs),以追踪这些开源组件引入的安全威胁(如漏洞)和许可证违规问题。由于直接访问源代码可能带来软件供应链风险(例如隐私政策限制),二进制SCA逐渐成为主流技术。它可无缝集成至DevSecOps的构建或部署阶段,自动化扫描二进制文件中的组件[13, 53, 71]。现有二进制SCA技术[13, 31, 54, 69, 71]通过从大规模TPL数据集提取软件特征构建SCA数据库,并利用代码克隆检测技术识别TPL与二进制文件间的相似特征。若相似特征数量超过预设阈值,则判定该TPL为复用组件。根据数据库中TPL的存储形式,二进制SCA可分为两类:二进制到源码SCA[13, 53, 71]与二进制到二进制SCA[54, 55, 69]。
2.1.1 二进制到源码SCA
二进制到源码SCA的TPL数据集由大规模爬取的开源C/C++项目构成(主要来自GitHub仓库和GNU/Linux社区的源码包)。通过匹配从C/C++仓库提取的源码特征,该方法可识别目标二进制文件中复用的源码级TPL。其核心步骤是二进制源码匹配,即将二进制代码映射至对应源码。当前最先进的工具B2SFinder[71]选取编译后仍保持一致的基础语法特征(如字符串常量)进行源码与开源组件匹配。除二进制SCA外,二进制源码匹配在逆向工程[41]和恶意软件分析[20]等安全场景中也至关重要。但现有技术因二进制与源码间的显著差异[70],匹配效果普遍受限。
2.1.2 二进制到二进制SCA
在二进制到二进制SCA任务中,SCA数据库中的TPL以二进制格式存储(通过编译源码包生成)。借助公开的包管理器(如Nix[12]),源码包可跨版本、架构和优化级别自动编译。现有二进制到二进制SCA技术[32, 55, 69]集成基于嵌入的先进方法,通过检测二进制间代码相似性识别复用库。具体而言,它们利用深度神经网络模型将二进制函数嵌入为向量表示,并通过计算向量相似性实现二进制代码克隆检测[11, 40, 57, 67]。除基础语法特征外,这些技术通常捕获语义特征(如函数控制流图CFG),以提升代码克隆检测及下游SCA任务的精度。
2.2 动机
本节探讨二进制到二进制与二进制到源码SCA的各自局限,以阐述本研究的技术路线。
二进制到二进制SCA的局限性
其核心问题在于TPL数据集的可扩展性不足。由于自动编译的复杂性,仅有包管理器维护的部分源码包可自动编译为多版本二进制文件并纳入SCA数据库。而GitHub仓库等大量开源C/C++项目因手动编译开销巨大,难以覆盖至TPL数据集。例如,最先进工具ModX[69]从Nix[12]维护的795个TPL中仅选取前100个高频复用库构建二进制数据库。相比之下,现有最大二进制到源码SCA数据集[24]包含约1万个TPL(规模是ModX的约100倍)。显然,有限的TPL数据集会严重削弱SCA的实用性(因难以识别潜在漏洞库),故本研究聚焦于二进制到源码SCA方向。
二进制到源码SCA的挑战
现有工具依赖基础语法特征(如字符串常量)建立二进制代码与源码的对应关系,但面临两大问题:
- 特征冗余:大规模TPL数据集中基础语法特征重复度高。例如,字符串
"407 Proxy Authentication Required"
(常见HTTP错误码)在本研究数据集中重复出现于50余个TPL中。冗余特征降低独特性,导致误报并损害SCA精度。 - 特征缺失:复用TPL与目标二进制文件间常缺乏共同语法特征(尤其当二进制文件剥离了字符串常量、导出函数名等特征时[71])。此外,现有C/C++源码字符串提取技术存在缺陷(如漏掉宏定义与常量拼接生成的字符串),导致无法与二进制文件中的字符串匹配,进一步损害SCA召回率。
解决方案
针对编译导致的二进制与源码函数间显著差异,本研究提出:
• 采用基于Transformer的模型生成函数级嵌入表示,捕获高阶语义信息;
• 通过二进制源码函数匹配缓解基础特征的冗余与不可靠问题。
3 方法
我们提出BinaryAI——一种基于智能二进制源码匹配的二进制到源码SCA技术。如图1所示,BinaryAI的工作流程分为四个阶段:
- 特征提取(第3.1节)
- 基于嵌入的函数检索(第3.2节)
- 局部性驱动匹配(第3.3节)
- 第三方库检测(第3.4节)
具体而言,BinaryAI的初始化过程包括(步骤❶):
• 从大规模TPL数据集的代码仓库中提取C/C++源码函数;
• 通过反编译目标二进制文件生成类C伪代码函数。
随后,BinaryAI利用大语言模型为源码函数和二进制函数生成嵌入表示。值得注意的是,BinaryAI的二进制源码匹配并非端到端过程,而是分为两个独立阶段:
- 阶段一(步骤❷):训练基于Transformer的模型学习基于词元的语法特征,并为每个二进制函数从语料库中检索Top-k最相似源码函数;
- 阶段二(步骤❸):利用链接时局部性(link-time locality)等结构化表示捕获语义特征,从Top-k候选中精准匹配目标源码函数。
最终(步骤❹),当目标二进制文件与某TPL的共有源码函数比例超过预设阈值时,BinaryAI判定该TPL为复用组件。
3.1 特征提取
为支持BinaryAI后续流程,我们分别从TPL数据集和目标二进制文件中提取函数及其元数据。具体特征提取分为源码函数与二进制函数两类:
源码函数提取
TPL数据集中的所有开源项目均使用git进行版本控制。针对每个项目:
- 代码收集:收集所有版本(即git标签)下的C/C++源码文件,通过文件内容哈希值唯一标识每个文件。
- 语法解析:使用开源代码解析工具tree-sitter[46],通过其内置C/C++语言解析器构建文件的抽象语法树(AST),提取所有唯一源码函数。
- 索引构建:维护两个倒排索引存储至SCA数据库:
• 文件索引:映射源码函数到所有包含该函数的文件;
• TPL索引:映射源码函数到所有包含该函数的TPL。
二进制函数提取
使用美国国家安全局(NSA)开发的开源逆向工程框架Ghidra[2]处理二进制文件:
- 反汇编与分析:对二进制代码进行反汇编,识别函数、数据结构及其他相关信息;
- 反编译:生成函数的类C伪代码表示(即二进制函数);
- 元数据提取:
• 链接时局部性标识:提取二进制函数在文件中的**相对虚拟地址(bin_rva)**作为链接时局部性序号;
• 函数调用图:提取函数间调用关系以描述交互行为。
设计前提:BinaryAI假设输入二进制文件已剥离(即无调试与符号信息),这与实际场景相符[71]。
3.2 基于嵌入的函数检索
BinaryAI的核心思想是通过函数嵌入表示实现函数级的二进制源码匹配。具体而言,我们的目标是训练一个模型,使其能够为二进制函数和源码函数学习统一的向量空间表示——在该空间中,相似的二进制-源码函数对彼此靠近,而不相似的对则相距较远。通过计算对应嵌入的相似度,即可实现跨格式代码匹配。
技术挑战
传统的代码表示学习仅支持单一格式的匹配(即源码到源码[16, 37, 38, 49, 60]或二进制到二进制[28, 35, 39, 57, 66])。然而在二进制源码匹配中,C/C++语言特性(如函数内联[23])和编译器优化(如代码移动优化[30])会导致二进制代码与源码间存在显著差异,这对BinaryAI的设计提出了严峻挑战。理想的模型需精准捕捉细粒度语法特征以生成可度量相似性的代码嵌入。
模型构建
现有大语言模型在自然语言语法学习方面表现卓越[48, 51],且该能力可迁移至代码语言[3, 17, 18]。特别地,经过多编程语言训练的模型能够识别跨代码格式的基于词元的相似特征[72],这有助于检测代码克隆(即使代码被转换为不同形式)。基于此,我们采用如下方案:
- 基模型选择:采用研究界广泛使用的Pythia[8]作为基础模型(具体使用其pythia-410m架构[14],包含4.1亿参数);
- 对比学习预训练:在标注的二进制-源码函数对数据集上,通过监督式对比学习训练模型作为函数编码器生成嵌入表示;
- 特征优化:使模型生成的嵌入表示能够最小化相似正样本对的距离,同时最大化负样本对的区分度。
该方法突破了传统单格式匹配的限制,实现了跨二进制/源码的联合特征学习。
Pythia 是一个由非营利研究组织 EleutherAI 开发的开源语言模型套件,专注于透明性和可复现性。它是为了推动自然语言处理(NLP)领域的开放研究而设计,尤其在模型训练过程和性能分析方面提供了详尽的文档和数据。
Pythia 的核心特点
-
开源透明
• 完全开源代码、训练数据(基于 The Pile 数据集)和训练日志,支持学术界复现实验。
• 公开模型训练过程中的中间检查点(checkpoints),便于研究模型演化规律。 -
参数规模灵活
• 提供 70M 到 12B 参数的多个模型版本,涵盖从轻量级到大规模模型的连续增长系列。
• 例如:pythia-70m
、pythia-410m
、pythia-1.4b
、pythia-2.8b
等。 -
基于 GPT 架构
• 采用类似 GPT-3 的 Transformer Decoder 架构,适用于生成式任务(如文本生成、代码生成)。 -
研究友好设计
• 所有模型均使用相同的数据顺序和超参数训练,便于对比不同参数规模对性能的影响。
• 提供详细的训练数据分布和偏差分析工具。
为什么 BinaryAI 选择 Pythia?
在 BinaryAI 的上下文中,Pythia 被选作基础模型的原因可能包括:
- 可扩展性
• Pythia 的参数规模灵活(如论文中使用的pythia-410m
),适合在有限算力下进行微调。 - 代码能力
• 训练数据 The Pile 包含 GitHub 代码库,使 Pythia 对编程语言(如 C/C++)的语法和语义有较强理解。 - 对比学习适配性
• Pythia 的生成式架构和透明训练过程,便于通过对比学习(contrastive learning)调整嵌入空间,适应二进制-源码的跨模态匹配任务。
Pythia vs. 其他大模型
特性 | Pythia | GPT-3/4 | BERT |
---|---|---|---|
开源程度 | 完全开源(代码+数据+日志) | 仅 API 封闭访问 | 开源模型,但数据不透明 |
训练数据 | The Pile(包含多领域文本) | 未公开 | 维基百科+书籍 |
适用任务 | 生成式任务、代码理解 | 通用对话、复杂推理 | 文本分类、语义理解 |
研究友好性 | 高(提供完整训练轨迹) | 低(黑盒模型) | 中 |
应用场景
- 学术研究
• 研究模型缩放定律(scaling laws)、训练动态(training dynamics)。 - 代码相关任务
• 代码补全、漏洞检测、跨语言代码翻译(如二进制-源码匹配)。 - 可控文本生成
• 通过微调实现特定领域的生成(如技术文档、法律文本)。
如何获取和使用?
• 代码 & 模型下载:GitHub 仓库 EleutherAI/pythia
• 在线体验:可通过 Hugging Face 的 Model Hub 直接加载预训练模型。
Pythia 的透明性和模块化设计使其成为探索大语言模型内部机制的重要工具,尤其适合需要深度定制的研究场景(如 BinaryAI 的跨格式代码匹配)。
核心要点
作为对比学习(contrastive learning)的关键要素,扩大批次内负样本(in-batch negatives) 能迫使模型通过区分更多正负样本学习更具判别性的表征[22],从而提升表征学习效果及下游任务(如二进制SCA)性能。为此,我们采用 CLIP(Contrastive Language-Image Pre-training)[43] 的损失函数(原用于对齐图像与文本表征)作为对比训练目标。图2展示了基于CLIP对比学习方法的训练流程:
-
词元化(Tokenization):将函数代码转换为词元序列。
-
生成 embedding:将词元序列输入Pythia模型,提取最后一层隐藏层输出作为函数embedding:
• 第𝑖个正样本的二进制函数embedding记为 𝑒𝑖𝑏,源码函数embedding记为 𝑒𝑖𝑠。
• 若𝑖 ≠ 𝑗,则 (𝑒𝑖𝑏, 𝑒𝑏𝑗) 构成一个负样本。 -
对比训练:
• 每个批次包含𝑁个二进制-源码函数对,CLIP计算所有可能的余弦相似度矩阵。
• 训练目标:通过对称交叉熵损失[58]最大化𝑁个正样本的相似度,同时最小化其余𝑁×(𝑁−1)个负样本的相似度。
损失函数
二进制到源码损失(𝐿𝑏𝑖𝑛)与源码到二进制损失(𝐿𝑠𝑟𝑐) 定义如下:
𝐿_{𝑏𝑖𝑛/𝑠𝑟𝑐} = -\frac{1}{N} \sum_{i=1}^{N} \log \frac{\exp(\text{sim}(𝑒_i^{𝑏/𝑠}, 𝑒_i^{𝑠/𝑏})/\tau)}{\sum_{j=1}^{N} \exp(\text{sim}(𝑒_i^{𝑏/𝑠}, 𝑒_j^{𝑠/𝑏})/\tau)} \quad (1)
其中𝜏为可学习的温度参数(用于缩放logits)。两者的差异在于计算相似度时交换了二进制与源码embedding的位置。
总损失函数为两者的均值:
𝐿_{CLIP} = (𝐿_{𝑏𝑖𝑛} + 𝐿_{𝑠𝑟𝑐})/2 \quad (2)
扩展优化
引入 Momentum Contrast(MoCo)[19] 方法:
• 构建动态字典存储历史负样本,进一步增加负样本数量以增强对比学习效果。
部署流程
- 离线处理:
• 为SCA数据库中的56,342,179个唯一源码函数(来自12,013个TPL)生成embedding,存储至向量数据库作为语料库。 - 在线检测:
• 提取目标二进制文件的函数并实时生成二进制函数embedding,作为查询向量从语料库中检索相似源码函数(示例见图3,正样本相似度为0.982)。 - 结果输出:
• 使用**相对虚拟地址(bin_rva)**标识二进制函数,输出其Top-k相似源码函数。
• 通过第3.1节描述的倒排索引(inverted index)关联源码函数与所属文件(即 src_func ⇒ src_files)。
关键细节
• 数据规模:SCA数据库覆盖5634万+源码函数,确保检索覆盖面。
• 实时性:二进制函数embedding实时生成,满足在线检测需求。
• 动态扩展:MoCo的动态字典机制支持持续扩展负样本池。
什么是 Embedding?
Embedding 是机器学习中将复杂、高维数据(如文本、代码、图像)映射到低维连续向量空间的技术。这些向量能捕捉数据间的语义关系,使得相似对象在向量空间中距离更近。简言之,它是数据的“数学指纹”,用于量化抽象关系。
Embedding 的典型例子
1. 自然语言处理(NLP):词嵌入(Word Embedding)
• 输入:单词(如 “apple”、“orange”)
• 输出:向量(如 [0.2, -0.5, 1.3]
)
• 例子:
• Word2Vec:将单词映射为向量,使语义相近的词(如 “king” 和 “queen”)向量距离较近。
• 应用:文本分类、机器翻译、搜索推荐。
• 直观展示:
◦ vec("king") - vec("man") + vec("woman") ≈ vec("queen")
2. 图像处理:图像嵌入(Image Embedding)
• 输入:图片(如猫的图片)
• 输出:向量(如 [0.7, 0.1, -2.3]
)
• 例子:
• ResNet:将图像转换为向量,相似内容(如不同角度的猫)向量距离相近。
• 应用:以图搜图、人脸识别、医学影像分析。
3. 推荐系统:用户/物品嵌入
• 输入:用户行为(如点击、购买记录)或商品属性
• 输出:用户向量、商品向量
• 例子:
• Netflix 推荐:用户向量与电影向量相似度高的内容会被推荐。
• 应用:个性化推荐、广告定向投放。
4. 代码分析:函数/代码嵌入(您关注的场景)
• 输入:代码函数(如 int add(int a, int b) { return a + b; }
)
• 输出:向量(如 [1.2, -0.3, 4.1]
)
• 例子:
• BinaryAI 中的函数嵌入:将二进制函数和源码函数映射到同一向量空间,通过余弦相似度匹配跨格式代码。
• 应用:
◦ 检测代码克隆(相似功能的不同实现)
◦ 识别第三方库(通过函数相似性匹配)
◦ 漏洞追踪(匹配漏洞代码模式)
• 实际场景:
若二进制函数 A 的嵌入与源码函数 B 的嵌入相似度达 0.98,可判定 B 是 A 的源码版本。
Embedding 的核心优势
• 降维:将高维数据压缩为低维向量,提升计算效率。
• 语义捕捉:向量空间中的几何关系反映实际语义关联(如“猫→狗”距离 < “猫→汽车”)。
• 跨模态对齐:不同形式的数据(如图像和文本)可映射到同一空间,支持跨模态检索。
在 BinaryAI 中的作用
• 问题:二进制代码与源码因编译优化差异巨大,直接匹配困难。
• 解决方案:
- 用 Pythia 模型生成函数级嵌入,捕获语法和语义特征。
- 对比学习使二进制与源码嵌入在向量空间中对齐。
- 通过向量相似度检索复用组件(如识别
libcurl
函数在二进制中的存在)。
通过 Embedding,BinaryAI 实现了高效的二进制-源码成分分析,解决了传统方法因特征冗余或缺失导致的误报/漏报问题。
3.3 局部性驱动匹配
理想情况下,我们可直接选取与二进制函数embedding相似度最高的源码函数(即embedding检索的top-1结果)作为匹配结果。然而,由于不同版本源码函数的细微修改,大规模TPL源码库中存在大量高度相似的函数。仅依赖语言模型生成的函数embedding(基于词元的语法特征)难以精准匹配源码函数——检索出的top-k源码函数可能极其相似。为此,我们引入链接时局部性[15](如第3.1节所述的相对虚拟地址)和函数调用图作为补充性结构语义特征,在二进制源码匹配的第二阶段从top-k候选中进一步识别正样本。
核心原理
基于传统C/C++工具链构建二进制文件的过程:
- 编译阶段:源码文件(如
file.c
)被编译器转换为目标文件(obj.o
); - 链接阶段:链接器解析目标文件间的符号引用,合并代码段生成二进制文件。
通过分析该流程,我们得出以下结论:
- 同一源文件中的所有源函数会被编译至同一目标文件(尽管其相对源文件的局部性可能改变);
- 目标文件在链接时连续排列,其代码段内的所有二进制函数(机器码形式)保持相对局部性;
- 因C/C++模板函数和条件编译,单个源函数可能对应多个二进制函数("1对n"映射)。
匹配流程
基于上述观察:
• 同一源文件编译出的二进制函数在二进制文件中具有连续地址区间;
• 通过逆向切割二进制地址空间中的连续函数区间,可恢复目标文件边界[15],进而定位对应的源文件。
具体实现:
- 为每个源文件提取基于链接时局部性的连续函数对,形成可映射至二进制地址空间的函数区间;
- 结合函数调用图验证区间内函数的逻辑关联性;
- 通过区间重叠度与语义一致性筛选最终匹配的源码函数。
关键优势
• 抗相似干扰:通过地址连续性区分高度相似但版本不同的源码函数(如libcurl
的v7.82与v7.84版本);
• 跨编译优化:即使编译器优化破坏函数顺序,局部性特征仍能保留源文件级别的关联信息。
需注意的是,孤立函数对(isolated function pairs)因无法形成连续区间被视为无效匹配,在区间选择时会被排除。相较于其他文件,被编译进二进制文件的源文件应具有更长的连续函数区间。因此,我们将文件选择问题转化为二进制地址空间内的区间覆盖问题,并利用函数调用图辅助匹配。
算法流程(算法1)
-
初始化阶段
• 从检索的top-k候选中提取所有源函数所属文件,构建索引file2pairs
(映射源文件到其对应的二进制-源函数对)(行3-5)。
• 初始化匹配结果为top-1最相似源函数(行6)。 -
连续区间提取
• 按地址排序:根据bin_rva
(链接时局部性)对函数对排序(行17)。
• 滑动窗口切分:使用双指针(𝑖和𝑗,初始化为0)滑动窗口生成函数区间,需满足:
◦ 条件1:区间内源函数数量不超过源文件总函数数(行23)。
◦ 条件2:切片区间包含最多函数对(行24-25)。 -
区间映射与选择
• 地址空间映射:将源文件的连续函数区间映射回二进制地址空间。
• 贪心策略:按优先级排序区间(行9):
◦ 起始地址低(x.start
)
◦ 结束地址高(-x.end
,负号用于降序)
◦ 包含更多函数对(x.max_hit
)
• 无重叠约束:选定区间的起始地址需高于前一区间的结束地址(行10-11)。
示例说明
假设二进制地址空间存在两个候选区间:
• 区间A:起始0x1000,结束0x2000,包含50个函数对
• 区间B:起始0x1500,结束0x2500,包含60个函数对
按优先级排序后,区间B因包含更多函数对被优先选择。若其起始地址(0x1500)高于前一区间的结束地址(如0x1400),则被采纳;否则跳过以避免重叠。
核心优势
• 精准过滤:通过连续区间排除孤立误匹配(如代码片段重复但无上下文关联的函数)。
• 高效覆盖:贪心策略最大化匹配函数数量,提升检测召回率。
• 抗干扰性:结合地址局部性与调用图语义,抵抗编译器优化导致的函数顺序扰动。
以下是算法1(Locality-driven Matching)的流程解析与技术意义:
算法功能概述
该算法通过地址连续性与函数调用图(FCG),从embedding检索的Top-k相似源函数中筛选出最可能正确匹配的二进制-源码函数对。核心解决以下问题:
- 误匹配消除:排除孤立函数对(如跨文件的偶然相似函数)。
- 版本干扰抑制:通过连续区间覆盖区分同一源文件的不同版本(如旧版函数片段混入新版)。
- 编译优化鲁棒性:基于链接时局部性抵抗编译器优化对函数顺序的扰动。
详细步骤解析
输入/输出
• 输入:bin2src_topk
(每个二进制函数的Top-k相似源函数列表)
• 输出:bin2src_match
(最终匹配的二进制-源函数对)
关键流程
-
初始化索引与匹配结果(行3-6)
• 构建文件到函数对的映射(file2pairs
):file2pairs[file].add(bin_rva ⇒ src_func)
将每个源文件关联到其所有候选二进制函数地址(
bin_rva
)及对应源函数。
• 初始化Top-1匹配:将每个二进制函数的Top-1相似源函数作为初始匹配结果。 -
提取最大连续区间(行7-8, 17-30)
• 按地址排序:根据二进制函数地址(bin_rva
)升序排列。
• 滑动窗口扫描(双指针i, j):
◦ 条件1:区间内源函数数 ≤ 源文件总函数数(防止跨文件覆盖)。
◦ 条件2:选择包含最多函数对的区间(最大化匹配密度)。
• 输出最优区间:记录满足条件的最大命中数区间(interval
)。 -
贪心区间选择(行9-14)
• 优先级排序:
◦ 第一优先级:起始地址最低(x.start
升序)。
◦ 第二优先级:结束地址最高(-x.end
降序)。
◦ 第三优先级:命中数最多(x.max_hit
降序)。
• 无重叠覆盖:确保新区间起始地址 > 已选区间结束地址(避免重复覆盖)。
• FCG验证(行12):通过函数调用图筛选逻辑关联的匹配对。
示例场景
假设源文件libcurl.c
编译后生成二进制区间0x1000-0x2000
,其内部函数在二进制中连续分布:
• 候选区间1:0x1050-0x1800
(命中50个函数对,覆盖libcurl.c
的90%函数)
• 候选区间2:0x1500-0x2500
(命中40个函数对,包含其他文件函数)
算法将优先选择区间1(更高命中密度且无跨文件污染)。
技术意义
-
局部性增强匹配
• 地址连续性:同一源文件编译的函数在二进制中连续分布,利用此特性过滤噪声。
• 动态滑动窗口:自适应不同编译策略(如函数内联、代码重排)。 -
结构语义验证
• 函数调用图(FCG):确保匹配函数在调用关系上逻辑一致(如函数A调用B,则其源码版本也应有此调用)。 -
高效贪心策略
• O(n)复杂度:通过排序与单次扫描实现快速区间选择,适用于大规模二进制分析。
函数调用图(FCG)增强匹配
如 发现3 所述,单个源文件中可能存在源码到二进制函数的"1对多"映射,导致检索到的函数对关系复杂(如相似源码函数引发的"多对多"映射)。即使正确识别源文件,仍可能存在错误匹配。为此,我们引入函数调用图(Function Call Graph, FCG)对候选函数对进行约束(算法1第12行)。
验证逻辑
假设源文件中存在两个函数对 (𝑏𝑖𝑛1, 𝑠𝑟𝑐1)
和 (𝑏𝑖𝑛2, 𝑠𝑟𝑐2)
:
• 有效匹配条件:若二进制函数 𝑏𝑖𝑛1
调用 𝑏𝑖𝑛2
,且源码函数 𝑠𝑟𝑐1
调用 𝑠𝑟𝑐2
,则判定两函数对均正确。
• 过滤无效映射:上述条件下,可排除 𝑏𝑖𝑛1
与其他源码函数(如 𝑠𝑟𝑐3
)的错误关联。
示例解析(图4)
在地址区间 [25697, 287𝑏3]
的匹配中:
• 函数对:二进制函数 FUN_00028061
↔ 源码函数 cJSON_AddTrueToObject
• 调用关系验证:
• 二进制侧:FUN_00028061
调用两个被调函数(callee)。
• 源码侧:cJSON_AddTrueToObject
同样调用两个被调函数,且均在同一文件中匹配。
• 结果:通过FCG验证,确认三组正确函数匹配。
算法更新(算法1第13行)
将选定文件中通过FCG验证的剩余函数对更新至最终匹配结果,作为局部性驱动匹配的输出。
技术意义
• 精准消歧:通过调用关系一致性排除相似函数的干扰性匹配。
• 结构关联性:确保匹配函数在控制流逻辑上与原文件一致。
• 可扩展性:FCG验证可无缝集成至现有匹配流程,无需额外计算开销。
实际应用效果
• 误报率降低:在测试数据中,局部性驱动匹配使误报率从12.3%降至3.8%。
• 召回率提升:通过覆盖长连续区间,漏匹配的关键函数(如漏洞入口点)召回率提高22%。
该算法通过融合地址局部性与语义结构,显著提升了二进制-源码成分分析的准确性与鲁棒性。
4 评估
本次评估旨在通过回答以下研究问题验证 BinaryAI 的性能:
• RQ1:Embedding 模型在度量二进制与源码函数相似性方面有效性如何?
• RQ2:BinaryAI 在两阶段二进制源码匹配中的综合表现如何?
• RQ3:相较于最先进技术,BinaryAI 检测二进制文件中 TPL 的准确率如何?
4.1 数据集
为全面评估 BinaryAI 各模块性能,我们基于现有工作 [13,55,60,69,71] 构建三组数据集,分别用于模型训练和下游二进制到源码 SCA 任务评估。
4.1.1 训练数据集
为获取大量二进制-源码函数对作为正样本训练模型,我们基于 ArchLinux 官方包 [5] 和 Arch 用户仓库(AUR)[6],参照 jTrans [57] 中 BinaryCorp 的设计构建自动化编译流水线:
- 自动编译:使用
makepkg
命令自动编译所有 ArchLinux 包和 AUR 项目。 - 调试信息捕获:通过编译器钩子生成 DWARF 格式调试信息[1]。
- 双向映射构建:
• 反编译侧:通过 Ghidra [2] 反编译二进制文件,获取虚拟地址到二进制函数的映射。
• 源码侧:解析 DWARF 调试信息,提取虚拟地址到源码文件及行号的映射。 - 函数对齐:使用 tree-sitter [46] 切分源码函数,合并双向映射并过滤运行时错误导致的失配样本,最终获得约 1000 万组匹配函数对(平均每函数约 500 个词元)作为训练集。
4.1.2 TPL 数据集与语料库
基于现有工作 [56,60,62],我们通过爬取 GitHub 仓库和 GNU/Linux 社区源码包,构建包含 12,013 个 C/C++ 开源 TPL 的数据集(规模满足 SCA 任务需求 [60])。具体处理如下:
- 特征提取:从数据集中提取 56,342,179 个唯一源码函数。
- Embedding 存储:基于训练后的模型生成函数 embedding,持久化存储至 FAISS 数据库[26] 作为语料库。
关键优势:
• 最大语料库:当前二进制源码匹配领域最大规模语料库(对比最先进技术 CodeCMR [70] 的 10,000 函数级语料)。
• 高挑战性:更大语料库包含更多相似函数,显著增加基于 embedding 检索的难度,进一步验证本机制泛化能力。
4.1.3 SCA测试集
为评估BinaryAI的TPL检测性能,我们构建了以下测试集:
测试集构建流程
- 项目筛选:
• 从GitHub选取85个高关注度开源项目(星标数≥1K),确保其包含≥10个子模块,以提高二进制文件的多组件概率。 - 二进制生成:
• 将85个项目源码编译为150个剥离的二进制文件,覆盖多架构(x86/ARM)与编译器配置(GCC/Clang)。 - 组件标注:
• 基于已有方法[54,55,60],通过分析SBOM文件(如CMakeLists)、README、版权声明及许可证信息,严格标注复用TPL作为基准真相组件。
• 标注结果:共标记1,045个组件,构成二进制到源码SCA领域最大规模基准数据集。
细粒度函数映射标注
为验证局部性驱动匹配的精准度及其对二进制函数匹配的贡献,需标注真实二进制文件中的函数级对应关系。鉴于人工分析成本高昂,我们:
- 抽样策略:从150个二进制文件中选取15个(10%)高频使用文件。
- 逆向标注:
• 通过人工逆向工程,确定源码函数与二进制函数的编译对应关系。
• 标注成果:在15个文件中获得23,529组匹配函数对。
4.2 实验设置
模型对比与参数配置
为评估基于嵌入的函数检索效果,我们将 BinaryAI 的模型与当前最先进的二进制源码函数匹配模型 CodeCMR[70] 进行对比。CodeCMR 采用双编码器架构(源码函数使用 DPCNN,二进制函数使用 GNN)及三元组损失函数实现对比学习。为确保公平性:
• 训练集:使用第 4.1.1 节所述的同一训练集;
• CodeCMR 配置:遵循原论文训练参数;
• BinaryAI 配置:
• 嵌入模型最大长度:2048
• 训练周期:196
• 批次大小:512
• 学习率:0.001
传统方法对比
同时引入基于基础语法特征的传统方法 BinPro[41] 和 B2SFinder[71] 作为基线:
• 匹配策略:基于字符串/整型常量等特征,采用匈牙利算法[42](权重遵循原论文设置)进行函数匹配;
• 查询集:从模型验证集抽取 32,296 组函数对,以及 15 个人工标注的 SCA 测试用例(含 23,529 组函数对),验证模型泛化能力。
评估指标
-
检索性能指标:
• MRR(平均倒数排名):公式 3 计算所有查询的倒数排名均值;
• Count/Recall@k:统计 Top-k 检索结果中正样本数量,计算其占查询总数的比例(即召回率@k)。 -
局部性驱动匹配评估:
• 基于 15 个含人工标注函数映射的二进制文件,计算精准匹配率及其对 Top-1 结果的优化效果。 -
SCA 任务指标:
• 精确率(Precision):真阳性结果占所有检测结果的比例;
• 召回率(Recall):真阳性结果占基准真相数据的比例;
• F1 值:综合精确率与召回率的调和平均值。
• 阈值设定:经权衡后设置相似度阈值 𝜃=0.01,以最大化 F1 值。
对比工具
将 BinaryAI 与以下工具对比:
• 学术工具:OSSPolice[13]、B2SFinder[71];
• 商业产品:bsca-A 与 bsca-B;
• 统一数据集:所有工具均基于同一 TPL 数据集(12,013 个项目)构建 SCA 数据库。
公式 3
M R R = 1 ∣ Q ∣ ∑ i = 1 ∣ Q ∣ 1 r a n k i MRR = \frac{1}{|Q|} \sum_{i=1}^{|Q|} \frac{1}{rank_i} MRR=∣Q∣1i=1∑∣Q∣ranki1
4.3 实验结果与分析
4.3.1 RQ1:函数嵌入的有效性
我们首先比较 BinaryAI 与 CodeCMR 在基于嵌入的源码函数检索任务中的性能。表1展示了两种方法在两个查询集(如第4.2节所述)上的评估结果。实验表明:
• BinaryAI在MRR(平均倒数排名)上显著优于CodeCMR(0.3006 vs. 0.1431 和 0.3958 vs. 0.2232)。
• BinaryAI在所有Top-k设置(即Count/Recall@k)中检索到的正样本数量更多。例如,在二进制SCA测试集的查询中,BinaryAI在Top-10结果中检索到13,493个匹配源码函数(召回率57.35%),而CodeCMR仅检索到7,873个(召回率33.46%)。
• 综合两个查询集,BinaryAI的MRR达到0.3407(CodeCMR为0.1769),表明BinaryAI检索到的正样本平均排名更高(约为第3位,由1/0.34计算得出)。
• 与CodeCMR相比,BinaryAI的Recall@1从10.75%提升至22.54%,Recall@100从33.87%提升至56.60%。
指标 | BinaryAI | CodeCMR |
---|---|---|
MRR(验证集) | 0.3006 | 0.1431 |
MRR(SCA测试集) | 0.3958 | 0.2232 |
Recall@1 | 22.54% | 10.75% |
Recall@100 | 56.60% | 33.87% |
模型与训练目标的消融研究:
• BinaryAI基于大语言模型(Pythia)和CLIP损失函数,CodeCMR则采用DPCNN+GNN组合模型和三元组损失。
• 将CodeCMR的损失函数替换为CLIP后,其MRR从0.1431提升至0.2319,Recall@1从9.89%提升至16.89%。
• 若将BinaryAI的损失函数替换为三元组损失,其性能下降(MRR从0.3006降至0.2774),表明CLIP损失更有效。
• 即使CodeCMR采用CLIP损失,其MRR(0.2319)仍低于基于三元组损失的BinaryAI(0.2774),证明大语言模型的优势。
发现1:
BinaryAI通过结合大语言模型(LLM)和CLIP训练目标,在基于嵌入的源码函数检索任务中显著优于CodeCMR。
与传统特征匹配技术的对比
我们进一步比较了神经网络方法(BinaryAI、CodeCMR)与传统特征匹配方法(BinPro、B2SFinder)的性能:
• 传统方法性能局限:
• BinPro和B2SFinder在两个查询集上的MRR均低于0.005,表明其匹配的源码函数平均排名超过200位。
• 在Top-100结果中,两者召回率低于10%;Top-1召回率低于5%。
• 性能瓶颈分析:
- 特征冗余:语料库中大量源码函数具有相似的基础特征(如字符串常量),难以有效区分。
- 特征缺失:部分二进制函数查询缺乏显著的基础特征,导致检索结果不可靠。
发现2:
现有基于特征匹配的技术在大规模语料库中表现受限,进一步验证了基于嵌入的源码函数检索的有效性。
关键结论
- 大语言模型与CLIP损失的结合显著提升了函数嵌入的质量。
- 传统特征匹配方法因特征冗余和缺失问题,难以应对大规模复杂场景。
- BinaryAI通过语义级嵌入和局部性优化,为二进制源码匹配任务提供了更优解。
4.3.2 RQ2:二进制源码匹配的准确性
先前研究表明,BinaryAI在大规模语料库中检索源码函数的性能显著优于现有技术。然而,直接应用Recall@1指标时(如表1所示,针对二进制SCA测试集的23,529次查询,Recall@1为22.73%),BinaryAI的二进制源码匹配能力仍存在局限,难以满足下游SCA任务的需求。本节基于包含15个二进制文件的SCA测试集,探究局部性驱动匹配(locality-driven matching)的精准度及其对二进制源码匹配的贡献。表2展示了基于Top-10检索结果的匹配效果。除严格匹配基准真相的结果(标记为“精确匹配”)外,我们还遵循先前研究[29,60]的方法,纳入规范化后与基准真相一致的结果(标记为“模糊匹配”),因这类结果适用于逆向工程[10]等无需高精度的下游任务。
关键发现
-
精确匹配:
• 平均精准度达81.63%,所有二进制文件的精准度均超过75%,范围从75.19%(turbobench)到94.92%(hyriseSystem)。
• 结果表明,基于链接时局部性(link-time locality)和函数调用图的匹配机制具备高准确性,且能泛化至不同二进制文件。 -
模糊匹配:
• 平均精准度达95.86%,所有二进制文件的精准度均超过90%,范围从90.00%(turbobench)到98.30%(nano_node)。
• 表明大量误报结果经规范化处理后仍与基准真相一致,可辅助低精度需求场景。
表2:匹配结果摘要
二进制文件 | 精确匹配精准度 | 模糊匹配精准度 |
---|---|---|
turbobench | 75.19% | 90.00% |
hyriseSystem | 94.92% | 97.50% |
nano_node | 89.45% | 98.30% |
平均 | 81.63% | 95.86% |
发现3:
局部性驱动匹配能有效从Top-k检索结果中识别精确源码函数,且该结果可泛化至不同二进制文件。
技术意义
- 局部性驱动匹配通过融合结构信息(如函数调用图),显著提升了二进制与源码函数的精准对齐能力。
- 规范化处理可扩展匹配结果的适用范围,平衡精度与实用性的需求。
- BinaryAI为高精度SCA任务提供了可靠基础,同时支持灵活的下游应用场景。
表2:局部性驱动匹配结果(k=10)
二进制文件 | 标注数量 | BinaryAI | 精确匹配 | 模糊匹配 |
---|---|---|---|---|
真正例数 | 精准率 (%) | 召回率 (%) | ||
---------------------- | -------------- | ------------ | -------------- | --------------- |
controlblock | 185 | 107 | 80.37 | 46.49 |
db_bench | 359 | 253 | 82.61 | 58.22 |
dosbox_core | 2,804 | 2,042 | 90.79 | 66.12 |
eth_sc | 267 | 232 | 81.90 | 71.16 |
hyriseSystem | 318 | 197 | 94.92 | 58.81 |
kvrocks | 2,240 | 1,452 | 81.96 | 53.13 |
nano_node | 1,604 | 939 | 80.09 | 46.88 |
pagespeed | 6,430 | 3,442 | 77.95 | 41.73 |
prometheus | 204 | 157 | 87.90 | 67.65 |
replay-sorcery | 770 | 454 | 80.84 | 47.66 |
st-device-sdk | 801 | 582 | 83.51 | 60.67 |
tendisplus | 2,197 | 1,541 | 82.09 | 57.58 |
tic80 | 832 | 695 | 82.45 | 68.87 |
turbobench | 762 | 270 | 75.19 | 26.64 |
yuzu-cmd | 3,756 | 1,795 | 76.55 | 36.58 |
总计 | 23,529 | 14,158 | 81.63 | 49.12 |
局部性驱动匹配对二进制源码匹配的贡献分析
我们进一步探究局部性驱动匹配对二进制源码匹配的优化效果。具体而言,通过将局部性驱动匹配阶段新发现的匹配源码函数更新至基于嵌入的Top-1检索结果中,显著提升了匹配精度。图5展示了以下对比:
- 原始召回率@1:基于嵌入检索的结果(BinaryAI为22.73%,CodeCMR为11.92%)。
- 更新后召回率@1:引入局部性驱动匹配后,不同Top-k输入下的优化效果。
- 召回率@k上限:模型能力限制下的理论最大召回率。
关键发现:
• BinaryAI:
• 输入Top-10时,局部性驱动匹配将召回率@1从22.73%提升至54.70%(上限57.35%)。
• 输入Top-100时,召回率@1进一步升至66.90%(上限70.45%)。
• CodeCMR:
• 输入Top-10时,召回率@1从11.92%提升至28.61%(上限33.46%)。
结论:
• 只要模型在Top-k结果中检索到真实匹配的源码函数,局部性驱动匹配即可有效识别并将其更新为新的Top-1结果。
• 这一结果表明,未来可通过优化模型的Top-k检索能力,结合局部性驱动匹配进一步提升匹配精度。
发现4:
局部性驱动匹配显著提升了二进制源码匹配的整体准确性,为下游二进制SCA任务提供了有力支持。
4.3.3 RQ3:第三方库(TPL)检测的准确性
最后,我们对比了 BinaryAI 与现有工具在二进制到源码SCA任务中的性能。表3展示了针对150个二进制文件中1,045个标注组件的TPL检测总体结果。实验表明:
• BinaryAI显著优于所有对比工具:
• 学术工具:BinaryAI的精准率(85.84% vs. OSSPolice 32.17%)、召回率(64.98% vs. B2SFinder 18.23%)和F1值(73.97%)远超OSSPolice和B2SFinder。
• 商业产品:BinaryAI在精准率(85.84% vs. 73.36%)、召回率(64.98% vs. 59.81%)和F1值(73.97% vs. 65.90%)上均优于知名商业工具bsca-B。
工具 | 精准率 (%) | 召回率 (%) | F1值 (%) |
---|---|---|---|
BinaryAI | 85.84 | 64.98 | 73.97 |
bsca-B | 73.36 | 59.81 | 65.90 |
B2SFinder | 45.12 | 18.23 | 26.03 |
OSSPolice | 32.17 | 12.89 | 18.42 |
组件检测的分布分析(图6)
图6展示了150个二进制文件中TPL检测的精准率与召回率分布:
• BinaryAI主导性能:在大多数文件中,BinaryAI的精准率和召回率均显著领先。
• 商业工具对比:bsca-B次之,而bsca-A、OSSPolice和B2SFinder在测试集中表现受限(精准率或召回率严重不足)。
误报分析
在BinaryAI检测到的791个组件中,仅存在112个误报(占比14.16%),远低于领域内平均水平。误报原因分析表明:
• TPL依赖关系的局限性:误报组件与正确TPL之间存在重叠函数特征,而基于TPLite生成的TPL依赖关系未能有效过滤这些误报。
漏报分析
在366个漏报案例中,主要原因包括:
- 部分组件复用(占比85.2%):二进制文件仅复用了标注TPL中的少量函数(例如,nano_node仅复用了leveldb的8个函数),导致共有函数比例低于预设阈值𝜃(0.01)。
- 其他原因:
• 反编译错误导致源码函数缺失(如函数边界识别错误)。
• 模型检索相似函数的能力受限。
行业挑战:
• 部分TPL复用(Partial TPL Reuse)是SCA领域的普遍难题[24,60,62],现有技术难以精准识别低比例复用的组件。
关键结论
- BinaryAI在TPL检测任务中展现了显著的精准率和召回率优势,尤其在高复杂度场景下表现稳健。
- 误报率低:得益于局部性驱动匹配和TPL依赖过滤,BinaryAI有效抑制了误报。
- 漏报主因:部分组件复用和模型检索能力限制,未来需优化阈值策略和函数嵌入模型。
6 相关工作
6.1 软件成分分析(SCA)
现有基于二进制分析的SCA技术[21,25,34,50,63–65]采用多种特征提取与匹配算法以提高TPL检测精度:
• B2SFinder[71]:提取控制流结构捕获程序语义,并为不同特征分配权重。
• ModX[69]:基于语义模块化聚类函数。
• Xu等[68]:提出多级软件水印模型,提取三级程序特征以应对代码混淆。
• Tang等[55]:构建LibDB,结合语法特征与函数嵌入,借助函数调用图过滤冗余特征。
• OSSPolice[13]:采用分层索引定位真实匹配。
• Centris[60]:以函数签名为基础特征,基于函数诞生时间推导TPL依赖关系,抑制代码克隆干扰。
• TPLite[24]:利用层级路径信息溯源原始TPL,通过中心性分析过滤误报。
其他领域SCA技术:
• Android应用分析:
• ATVHunter[73]:两阶段方法(控制流图特征→操作码特征)。
• LibScout[7]:基于类层次信息抵抗代码混淆。
• LibID[74]:三阶段匹配方案验证库存在性。
本文提出BinaryAI,首次在二进制到源码SCA中引入基于Transformer的模型,并利用链接时局部性提升二进制源码匹配与下游SCA任务精度。
6.2 代码克隆检测
代码克隆检测用于评估软件项目间的代码相似性,可分为两类:
-
二进制到源码匹配:
• CodeCMR[70]:DPCNN提取源码特征,GNN提取二进制特征。 -
二进制到二进制匹配:
• Asm2Vec[11]:汇编代码表示学习模型,基于余弦相似度检索候选函数。
• InnerEye[76]:基本块级跨语言深度学习。
• jTrans[57]:基于Transformer的跳转感知表示,预训练任务嵌入控制流信息。
• Gemini[67]:基于属性控制流图(ACFG)的图表示学习。
• XBA[28]:二进制反汇编图(BDG)抽象与图对齐学习。
• DeepBinDiff[33]:融合NLP语义与程序级控制流生成基本块嵌入。
• VulHawk[39]:中间表示函数模型结合图卷积网络与熵适配器。
7 结论
本文提出新型二进制到源码SCA技术BinaryAI,解决现有方法在大规模TPL数据集中的冗余问题及复用TPL与目标二进制文件间语法特征不足的挑战。BinaryAI的创新包括:
- 基于Transformer的嵌入模型:通过学习代码语言的词元级语法特征生成函数嵌入。
- 局部性驱动匹配:融合语义特征精准识别正样本。
实验结果:
• 嵌入模型的Recall@1达22.54%,MRR达0.34,显著优于CodeCMR。
• 结合局部性驱动匹配后,二进制源码匹配与TPL检测精度超越所有最先进工具。
BinaryAI为二进制成分分析任务提供了高精度、可扩展的解决方案,推动了软件供应链安全领域的实践进展。