Page 92 - 《软件学报》2025年第7期
P. 92
贾昂 等: 面向函数内联场景的二进制到源代码函数相似性检测方法 3013
(2) 节点是非根节点, 它有到其他节点的内联调用, 并且还有其他节点通过普通调用连接到它.
如图 7(b) 所示, 使用规则 (1), 可以识别出两个节点 A 和 D. 应用规则 (2), 可以识别出一个节点 C. 其中, A 和
D 分别是它们各自内联子图的根节点, 因此内联将从这些位置开始.C 还被正常函数 B 调用, 因此不会被删除, 所
以需要保存其副本以生成一个新的内联树.
如果一个节点不满足这两个条件, 它要么是没有向其他节点发出内联边的节点 (比如图 7(a) 中的 B、E 和 F),
要么是在内联子图中但仅被内联边调用的节点 (如图中的 F). 前者没有可以内联到源代码函数集合的节点, 而后
者则会始终被内联到它的调用者中, 并且不会作为独立的函数在二进制文件中被编译.
而在图 2 的例子中, O2NMatcher 所识别的内联函数子图只包含了 dtls1_get_record dtls1_process_buffered_
records, dtls1_get_bitmap, dtls1_record_replay_check 这 4 个函数, 函数 dtls1_get_record 对其他 3 个函数存在内联
调用关系, 因此只有函数 dtls1_get_record 可以作为根节点.
4.3.2 调用边扩展
调用边扩展同样遵循两条规则.
(1) 如果调用者和被调者之间只有内联边, 则遍历内联子图中根节点可达的所有节点.
(2) 如果调用者与被调者之间同时存在内联边和普通边, 则生成两种版本的源代码函数集合. 一种沿着内联边
继续包含后续节点, 另一种在遇到普通边时停止.
以 D 为根节点时, 子树中只有内联边, 因此根节点 D 进行边扩展后生成源代码函数集合“D→F”. 使用 A 为根
节点时, 节点 C 和 E 之间存在 c1 内联边和 c2 普通边两种边, 于是为根节点 A 生成源代码函数集合 “A→C→E”和
“A→C”, 如图 7(c) 所示. 对于根节点 C, 则会生成源代码函数集合“C→E”.
如果内联子图中存在循环, O2NMatcher 会记录已遍历的节点并在遇到已记录的节点时停止探索该路径.
而在图 2 的例子中, 4 个函数之间只存在内联边, 因此通过上述步骤, 可以生成源代码函数集合 (dtls1_get_
record + dtls1_process_buffered_records + dtls1_get_bitmap + dtls1_record_replay_check), 以用于后的内联二进制函
数匹配.
得到源代码函数集合后, O2NMatcher 使用 Understand 进行源代码函数内联, 针对每个源代码函数集合生成最
终含内联的源代码函数, 以作为内联二进制函数匹配的目标. 需要注意的是, 源代码函数集合的生成是在进行二进
制到源代码函数相似性检测之前进行的, 在生成过程中并不需要二进制函数的相关信息.
5 实验分析
本节主要对 O2NMatcher 进行相关实验评估. 第 5.1 节介绍实验设置. 第 5.2 节对 O2NMatcher 的检测精度进
行衡量. 第 5.3 节对 O2NMatcher 的运行时效进行分析. 第 5.4 节对 O2NMatcher 选取的特征进行贡献度的分析.
第 5.5 节对实验结果进行讨论.
5.1 实验设置
5.1.1 评估基准
鉴于 O2NMatcher 旨在作为现有二进制到源代码函数匹配研究的补充, 本文需要选定一项研究作为二进制
到源代码相似性匹配的基准方法来评估 O2NMatcher 的提升效果. 目前存在多种二进制到源代码相似性检测的方
法 [1−11] , 其中, CodeCMR 达到了最准确的函数级匹配精度. 此外, CodeCMR 还提供了一个名为 BinaryAI 的工具,
方便本文进行深入的评估工作.
5.1.2 对比方法
在 O2NMatcher 的实验衡量中, 本文选取了 Bingo [20] 和 Asm2Vec [21] 作为对比方法. Bingo 和 Asm2Vec 采用手
工设计的规则来模拟函数内联的过程, 然后比较内联后的函数以获取相似度. 由于他们旨在解决函数内联下的二
进制到二进制匹配问题, 本文迁移了它们的规则来为二进制到源代码相似性检测生成源代码函数集合.
在 ECOCCJ48 的实验衡量中, 本文选取了 5 种 MLC 方法作为对比方法. Bogatinovski [24] 对目前已有的多标签

