Neural Machine Translation Inspired Binary Code Similarity Comparison beyond Function Pairs(INNEREYE)阅读笔记

二进制代码相似性检测

Posted by Yunlongs on March 20, 2020

请咨询作者同意后转载。

Neural Machine Translation Inspired Binary Code Similarity Comparison beyond Function Pairs(INNEREYE)

数据集,模型,评估结果:https://nmt4binaries.github.io

期刊/会议: NDSS(B类)
发表时间: 2018年12月
发表机构: South Carolina&Temple University

前言

以不同的观点来看待跨平台二进制代码相似性检测问题,指出以前的方法都是以函数级别来进行检测的,不能任意挑一代码段进行检测。

为此,作者将跨平台二进制代码相似性检测问题分解为两个问题:

Problem Ⅰ:给一对不同指令集平台下的二进制基本块,判断其语义是否相似。

Problem Ⅱ:给定关键代码的片段,看它是包含在不同指令集的其他片段中出现。

方法概述

如上图,分别在三层分析语义信息:基本块、CFG路径、代码。

模型的输入: 要查询的代码段和被查询的程序集合。

Front-end: 反汇编二进制程序和构建控制流图

basic block embedding模块: Neural network-baseed cross-lingual model 来对每个basic block进行embedding,所有的embedding存在LSH数据库中。其中embedding分为 instruction embedding and a block embedding两个层次。

Path Similarity comparison: 利用LCS (Longest Common Subsequence)算法来比较两条Path的语义相似性。

Componet similarity comparison: 探索多条路径所共同计算出的相似性得分。

相似性检测模块: 利用LSTM和Siamese生成相似性分数(0-1),越接近1越相似。

Instruction Embedding Generation

提出了在进行Instruction embedding时面临的挑战:在机器翻译中,我们只需要使用大规模的语料训练一次就可以得到词嵌入,然后直接被其他人用。但是在这里,我们必须自己训练一个instruction embedding。还有像常量、字符串之类缺失词的嵌入生成。

定义block级别的指令流,其中$b_i$为基本块$\mathrm B$中指令的: \(\pi(\mathrm{B})=\left(b_{1}, \cdots, b_{n}\right)\) 预处理训练数据: 为了解决缺失词的问题,对训练数据做如下处理:

(1) 负号保留,但数字常量全替换成0

(2)字符串替换成<STR>

(3)函数名替换成<FOO>

(4)其他符号常量全替换成<TAG>

然后使用word2vec里的skip-gram练词向量。

Block embedding Generation

因为指令在不同的平台下具有不同的embedding,所以我们不同对其简单的累加获得block embedding。

为此搭建了如下的LSTM+Siamese网络来学习block embedding。 其中Siamese的网络输入为两个基本块$\mathrm B_1和\mathrm B_2$的instruction的embedding,而LSTM网络可以通过instruction embedding学习到block embedding。

其中Siamese网络的损失函数为平方损失: \(\min _{\mathbf{W}_{i}, \mathbf{W}_{f}, \ldots, \mathbf{v}_{o}} \sum_{i=1}^{N}\left(y_{i}-\operatorname{Sim}\left(\mathrm{B}_{1}^{i}, \mathrm{B}_{2}^{i}\right)\right)^{2}\)

但其中存在的困难如下: Siamese网络需要大量的训练数据对,但不同于Genimi所采用的针对函数级别做标签,这里要对被个基本块做标签。其难度体现为如下:1.没有可以暗示是否相似的基本块命名可以使用。2.即使两个基本块有两段代码编译而成,它们也可能相似或者不相似。

数据集生成 如上图所示,LLVM由左边front-end和右边backend组成,front-end会生成统一的中间表示,所以我们修改每个backend增加每个基本块的边界注释器,并添加唯一的标识ID,由相同IR编译生成的基本块获得相同的ID。

尽管相同的ID总是语义相同,但是不同的ID并不一定语义不同。 为了解决这个问题,使用N-gram来判断两个由不同代码编译所得的基本块的相似度。实验中采用n=4,0.5为threshold。

Path/Code Component Similarity Comparison

将CFG分解成许多的路径,在于目标程序的路径 利用LCS进行比较相似性分数。

线性独立路径: 至少增加一个不包括在其他线性独立路径中的节点。一旦 $Q$和目标$T$的起始block是一样的,那么我们就可以用DFS算法来寻找线性独立路径的集合。

定义:PATH相似性分数:

给定一Query代码段的线性独立路径$P$,目标程序$T$的所有线性独立路径$\Gamma=\left\lbrace \mathcal{P}_ {1}^{t}, \ldots, \mathcal{P}_ {n}^{t}\right\rbrace $。令$\left[\mathrm{LCS}\left(\mathcal{P}, \mathcal{P}_{i}^{t}\right)\right]$为$Q在\Gamma$中具有最大语义相似路径的LCS的个数。路径$P$的path相似性分数定义如下: \(\psi(\mathcal{P}, T)=\frac{\max _ {\mathcal{P}_ {i}^{t} \in \Gamma}\left|\operatorname{LCS}\left(\mathcal{P}, \mathcal{P}_{i}^{t}\right)\right|}{|\mathcal{P}|}\)

Component Similarity Comparison

在这方面遇到的挑战是:如何正确的在target program中找到Query的起始block。 解决:

  1. 首先所有基本块的embedding都存在LSH数据库中供我们查询。
  2. 我们从Query代码段的第一个基本块开始,在数据库中寻找target program中的语义相等基本块。
  3. 如果我们找到一个或多个语义相等基本块,我们就从此基本块开始发现路径。否则我们选择Query的第二个基本块作为起始块。

Component similarity score: 根据选择出的线性独立路径计算出相似性分数,并根据每个路径的query path的长度分配一个权重,最后的得分就是加权平均分。

实验评估

实验设置

Dataset Ⅰ:evaluate the cross-lingual basic-block embedding model。 数据源使用Openssl等软件,并使用不同的平台、编译器、优化选项编译得来。具有标签。

Instruction embedding 的定量分析:使用t-SNE对x86和ARM平台下的embedding做了可视化,结果显示有相同平台编译得到的embedding聚在一起。

并且还进一步分析发现,相似的指令也聚类到了一起。

Accuracy of INNEREYE-BB :使用DatasetⅠ来进行评估。并且与Gemini手动提取的特征作为对比,并使用SVM分类器进行分类,结果显示此方法提取特征的准确率更高,手动提取特征可能导致大量的语义信息丢失。

Efficiency of INNEREYE-BB:使用具有6,199,651个指令的数据集Ⅰ做Instruction Embedding,可以看出花费时间很短。

Code Component Similarity Comparison: