• 标题: How Machine Learning Is Solving the Binary Function Similarity Problem
  • 作者: Andrea Marcelli, Mariano Graziano, Xabier Ugarte-Pedrero, and Yanick Fratantonio, Cisco Systems, Inc.; Mohamad Mansouri and Davide Balzarotti, EURECOM
  • 关键字: 二进制安全
  • 来源: SEC'22
  • 链接: https://www.usenix.org/conference/usenixsecurity22/presentation/marcelli

本文是关于二进制函数相似性问题的Measurement研究,这是一个在系统安全领域非常重要和具有挑战性的问题。作者对现有的研究进行了系统化的分析,并重新实现了一些代表性的方法,然后在一个新的数据集上进行了公平和有意义的比较。他们发现当前的研究存在一些主要的挑战,例如可重复性、评估结果的不透明性和研究方向的不清晰。他们希望通过发布他们的整个模块化框架和数据集来激励未来在这个研究领域的工作。

Measuring Function Similarity 函数相似性对比技术的分类。

相似性对比技术

首先介绍了两种测量函数相似度的技术:直接对比和间接对比技术。直接对比是指给定一对函数的特征,用机器学习模型输出一个相似度分数。间接对比是指将输入特征映射到一个"压缩"的低维空间,然后用简单的距离度量计算相似度。这两种技术都需要实现索引策略来提高搜索效率。

其中模糊哈希是低维表示方法的典型代表。模糊哈希是由与传统密码哈希不同的算法产生的,因为它们故意设计成将相似的输入值映射到相似的哈希值。Pagani等人研究了在原始可执行文件上计算传统模糊/局部敏感哈希的局限性,得出结论:输入字节的微小变化会显著影响生成的哈希值。然而,即使普通模糊哈希可能不适合函数相似度,一些方法(如FunctionSimSearch)提出了更专业的哈希技术来比较两个函数。

另一种低维表示形式是基于嵌入。嵌入指的是将高维样本映射到一个低维空间,其中语义上相似的输入被映射到彼此接近的点,而不管它们在原始表示中看起来有多么不同。机器学习模型的目标是学习如何产生嵌入,使得相似函数之间的相似度最大化,而不同函数之间的相似度最小化。在文献中包括两种主要类型的嵌入:函数代码级嵌入和图结构嵌入。

代码嵌入。利用自然语言处理(NLP)技术来解决二进制函数相似性问题,把汇编代码当作文本来处理。代码嵌入根据不同的标记(例如指令、助记符、操作数、规范化指令)生成代码块或指令的嵌入向量。有三类方法:一类是基于word2vec的方法,如Asm2Vec,可以在不同的指令集上训练,但不能跨架构映射语义;一类是基于seq2seq编码器-解码器模型的方法,可以将不同架构的语义映射到同一个嵌入空间;一类是基于BERT的方法,如OrderMatters和Trex,使用预训练的变换器模型来学习近似程序执行语义,并用于识别语义相似的函数。

汇编代码嵌入通常受到它们能够处理的不同指令数量(所谓的词汇外问题)和能够作为模型输入的最大指令数量的影响。因此,某些方法计算指令级嵌入、基本块嵌入或函数级嵌入。

图嵌入。图嵌入是一种为图中的每个实体(通常是节点)确定固定长度向量表示的方法,这些嵌入是图的低维表示,保留了图的拓扑结构。基于函数控制流图的图嵌入方法具有跨架构的特点。这些嵌入可以由定制算法 或更复杂的机器学习技术,如图神经网络(GNN) 生成。一些最新的机器学习方法提出了GNN的变体,如GMN,这些变体能够在向量空间中产生可比较的嵌入 ,这些嵌入包含了从输入模型的两个图中提取的信息。

图嵌入方法还经常为每个基本块在其对应的图节点中编码信息,以增加表达能力。例如,一些解决方案为每个节点计算一组属性,从而导致具有属性的控制流图(ACFG),这些属性可以是手工设计的 或以无监督方式自动学习的。其他作者利用其他嵌入计算层使用前面讨论过的一些技术(例如,在基本块级别)。

函数表示技术

从二进制中提取信息的技术。

raw bytes 原始二进制 直接使用原始二进制信息作为相似性对比的输入(Catalog1 [74]),或者将原始字节与与从控制流图(CFG)或调用图(CG)[44]获取的其他信息结合起来  
Assembly 汇编 汇编指令作为输入、使用汇编指令的数量作为输入来计算函数的相似性  
Normalized assembly 标准化汇编 由于汇编代码经常编码常量值,导致操作和操作数的组合非常多。汇编规范化是可以抽象掉一些变化,减少词汇量,把同一操作的不同变体统一成一个表示。  
Intermediate representations 中间表示 中间表示是一种将二进制代码提升到更高抽象层次的技术,可以统一不同指令的语义,消除不同架构的差异,以及应用程序分析技术来简化代码结构。常用的中间表示有LLVM、VEX和IDA微码等。  
structure 结构特征 结构是一种反映函数内部或者在程序中的作用的特征。许多方法提取函数的控制流图(CFG),并且根据基本块的数据或者其他信息对其进行扩展,形成属性控制流图(ACFG)或者其他类型的图。还有一些方法利用CFG的结构来计算其他特征,例如tracelets(CFG中连续基本块的序列)。  
Data flow analysis 数据流分析 数据流分析是一种处理汇编级别的算术表达式的不同形式的方法。一些方法通过计算基于数据流依赖的程序切片,并将它们标准化和作为特征来反映函数的行为。另一些方法,例如Vulseeker,使用块之间的数据流边作为额外的特征。  
Dynamic analysis 动态分析。 动态分析通过运行函数对并根据输入输出关系提取特征,或者根据执行轨迹提取语义特征,或者使用模拟或混合技术。  
Symbolic execution and analysis 符号执行 用符号执行来完全捕获待分析函数的行为,并确定其输入和输出之间的关系,涵盖所有可能的路径。  

本文选择的方法

选择标准

  1. 可扩展性和实际应用能力
  2. 关注具有代表性的方法,而不是特定的论文
  3. 涵盖不同的研究领域
  4. 优先考虑最新的趋势

二进制代码相似性技术的演变: 二进制代码相似性技术的演变

根据时间的分类: 根据时间分类的二进制代码相似性技术的演变

实验

关于实验的一点补充说明。 实验中涉及了两种基于神经网络的方法,分别是Order Matters和CodeCMR,它们都是由腾讯安全科恩实验室提出的。Order Matters是一种利用图神经网络和注意力机制来捕捉二进制函数的语义信息,并生成函数嵌入向量的方法。CodeCMR是一种利用多模态检索技术来实现二进制函数和源代码之间的匹配的方法。这两种方法都在BinaryAI平台上进行了实现,BinaryAI是一个免费在线的软件成分分析平台,可以帮助用户检测二进制程序中的漏洞、克隆代码、第三方库等。这段文字还说明了作者没有公开他们的模型实现,但是他们同意在我们提供的数据集上重新训练和测试他们的模型,并与我们分享测试数据的函数嵌入向量。为了计算函数之间的相似度,Order Matters和CodeCMR使用余弦距离作为相似度度量。

实验复现

参看 :https://github.com/m2kar/m2kar.github.io/issues/19



欢迎在ISSUE参与本博客讨论: m2kar/m2kar.github.io#18