美文网首页读书简友广场机器学习与深度学习
EKLAVYA -- 利用神经网络推断二进制文件中函数的参数

EKLAVYA -- 利用神经网络推断二进制文件中函数的参数

作者: Mezereon | 来源:发表于2021-10-04 23:38 被阅读0次

EKLAVYA -- 利用神经网络推断二进制文件中函数的参数

这一次介绍一篇文章,名为Neural Nets Can Learn Function Type Signatures From Binaries

来自于新加坡国立大学Zhenkai Liang团队,发在了Usenix Security 2017上

问题介绍以及形式化定义

该工作主要关注的问题是函数的参数推断,包含两个部分:

  • 参数的个数
  • 参数的类型,比如int, float等

传统方法通常会使用一些先验知识,将指令的语义ABI惯例 (Application Binary Interface)编译器的风格等进行编码。

一旦编译器发生了改变,指令集合发生了改变,那么我们就需要重新引入一些先验知识。

如果我们可以摆脱,或者说是减少这些先验知识的利用,那么就不会受限了!

那么,使用神经网络来进行自动化的学习和推断,就是一种思路了。

前提假设

  • 我们首先能知道一个函数的边界 (boundary)
  • 在一个函数内部,我们知道它的指令边界
  • 我们知道代表一个函数调用(function dispatch)的指令,比如call

通过反汇编工具,我们可以满足上述假设。

值得一提的是,函数边界也可以使用神经网络来做,有兴趣的读者可以参考 Dawn Song 发在Usenix Security 2015 的 Recognizing functions in binaries with neural networks.

这里,首先给出一些符号的定义:

  • 我们定义我们的模型为 M(\cdot)

  • 定义函数 a 反汇编出来的代码为 T_aT_a[i] 代表函数 a 的第 i 个字节

  • 函数 a 的第 k 条指令可以被写成 I_a[k]:= <T_a[m], T_a[m+1],...,T_a[m+l]>

    • 其中 m 是对应指令的起始字节的位置索引
    • l 是该指令所包含的字节数
  • 一个包含 p 条指令的函数 a 可以被表示为 T_a:=<I_a[1],I_a[2],I_a[p]>

  • 如果一个函数 b 有一个直接调用 call 对于函数 a, 我们将该条call指令之前的所有指令拿出来,称为 caller snippet,可译为调用者片段。定义为 C_{b,a}[j]:=<I_b[0],...,I_b[j-1]>

    • 其中 I_b[j] 对应 call 函数 a 的那一条指令
    • 如果 I_b[j] 是一个间接调用,我们令 C_{b, a }[j] := null
  • 我们会收集函数 a 的所有调用者的调用者片段,记为 \mathcal{ D }_a:=T_a\cup(\bigcup_{b\in S_a}(\bigcup_{0\leq j\leq |T_b|}C_{a,b}[j]))

    • 其中 S_a 是调用 a 的所有函数的集合

由于调用者片段的长度可能非常长,这里文章设置为不超过500条指令

我们的函数 M(\cdot) 接受输入 \mathcal{ D }_a , 输出两个变量:

  • 函数 a 的参数个数
  • 函数 a 的每一个参数的类型
    • C-风格的参数类型可以被定义为 int, char, float, void*, enum, union, struct

方法设计

我们这里先直接给出整体的方法流程图:

image-20211004214934260

简单来说,可以划分成两个模块:

  • 指令编码模块
    • 首先,将输入的二进制文件进行函数抽取、指令的分割、调用点的抽取。
    • 然后对指令进行Word Embedding编码,得到对应的向量表示,这一部分可以参照 NLP 中的 Word2Vec。
  • 参数还原模块
    • 将这些数据切分成训练集和测试集,分别使用4个递归神经网络(RNN)来从两个方面(调用者和被调用者)推断函数参数的个数以及类型,也就是对应上图中的4个任务(Task2,Task4 对应被调用者,Task1,Task3对应调用者)。

究竟是怎么推断多个参数类型的呢?

一个RNN,输入一个序列,只能推断出来一个类型。

所以这篇文章的实现是,训练多个RNN,每一个RNN独立推断固定位置的参数类型。

先用一个RNN推断出来参数个数,然后分别使用多个RNN来推断不同的位置的参数。

数据准备

该文章使用一些linux的包,然后使用clang和gcc来进行编译,通过设定debug模式,就可以直接在binary中的DWARF字段找到对应函数边界、参数个数以及类型,作为ground truth。

构建了两个数据集:

  • 数据集1: 包含了3个流行的linux包(binutils,coreutils 以及 findutils), 使用了O0到O3的优化等级进行编译
  • 数据集2: 将数据集1包含的linux包进行扩展,多增加5个 (sg3utils, utillinux, inetutils, diffutils 和 usbutils), 也在4个优化等级上进行编译

训练集和测试集的划分比例为8:2

不平衡的数据

在数据集的构造中,会出现不同类的数据比例相距甚远的情况。比如参数为pointer类型的数据就是union类型的数百倍,大部分函数都是少于3个参数。该文章中并没有解决这个问题。

实验结果

image-20211004232753476

这里贴出来Task1和Task2,也就是通过调用者和被调用者,推断参数个数的结果

可以看到:

  • 优化级别越高,越难推断,但并没有严格的递增关系
  • 参数个数越多,越难推断,和训练数据量也有关系
  • 从调用者方面,更容易推断出来参数个数
image-20211004233105566

上面是,关于参数类型推断的结果

可以看到:

  • 优化级别似乎干扰性不强,甚至优化级别越高,推断类型越精确
  • 参数的位置越靠后,越难推断出来了类型
  • 从调用者和被调用者两方面来推断,差别不是很大

相关文章

  • EKLAVYA -- 利用神经网络推断二进制文件中函数的参数

    EKLAVYA -- 利用神经网络推断二进制文件中函数的参数 这一次介绍一篇文章,名为Neural Nets Ca...

  • 【C++ Templates(14)】模板实参推断

    推断的过程 对函数调用,推断会比较实参类型和模板参数类型(即T),对要被推断的参数分别推断出替换,每个实参-参数对...

  • 【runoob.7】函数定义

    表达式作为函数体,返回类型自动推断: 无返回值的函数(类似Java中的void): 可变长参数函数 函数的变长参数...

  • python 将输出重定向到文件中

    5.2 将输出重定向到文件中 直接在print函数上加file参数即可 要确保文件是可写的,还有如果文件是以二进制...

  • 推断统计-假设检验

    推断统计是研究如何利用样本数据来推断总体特征的统计方法。包含参数估计和假设检验。参数估计即利用样本信息推断总体特征...

  • 为何需要最大后验概率推断

    1 在最大似然函数推断中,我们通过求取使得似然函数最大的参数值来估计参数。 比如在投硬币中,我们用似然函数 ( 其...

  • Tensorflow简单神经网络

    神经网络参数与Tensorflow变量 tf.Variable作用是保存和更新神经网络中的参数 其它生成器 函数随...

  • 假设检验

    参数估计和假设检验是统计推断的2个组成部分,它们从不同角度利用样本对总体进行推断。在参数估计中,总体参数是未知的,...

  • 统计中的假设检验

    推断统计的概念 推断统计是研究如何利用样本数据来推断总体特征的统计方法。包含两个内容:参数估计,即利用样本信息推断...

  • 似然函数

    在数理统计学中,似然函数是一种关于统计模型中的参数的函数,表示模型参数中的似然性。 似然函数在统计推断中有重大作用...

网友评论

    本文标题:EKLAVYA -- 利用神经网络推断二进制文件中函数的参数

    本文链接:https://www.haomeiwen.com/subject/yedwnltx.html