VulDeeLocator

VulDeeLocator: A Deep Learning-based Fine-grained Vulnerability Detector

μvuldeepecker的再升级,不仅能检测出漏洞而且能够定位到具体的位置。

https://github.com/VulDeeLocator/VulDeeLocator

主要的思想是通过中间代码来实现的。有两个关键名称的定义是

  1. 程序P。程序P是由一个个pi(不同的程序文件)组成的。每个程序文件pi又是由不同的函数、宏定义fij组成的。每个函数、宏定义fij又是由不同的语句sijk组成的。每个语句sijk是由不同的token tijkl组成的。
  2. vulnerability syntax characteristics。H={h1,…,hη},表示整个vulnerability syntax characteristic的集合。
  3. sSyVC(从源码中切取出来的与漏洞特征相关的token序列)。一个sSyVC, yijkz 表示的是在一个语句sijk中,能与某个vulnerability syntax characteristic规则相匹配的token 序列。
  4. 程序P的中间语言表示P。P又是由一个个pi '(不同程序文件的中间语言形式)组成的。这些pi '又是由不同的函数、宏定义的中间语言形式fij组成的。每个用中间语言表示的函数,宏定义fij又是由不同的语句sijk组成的。与源代码不同的是,这些语句不再划分成token序列了。
  5. iSeVC(从中间代码中切取出来的与漏洞特征相关的程序语句序列)。与sSyVC相对应的iSeVC是语句sijk的集合。(源码中的token,在经过中间语言变换后就是一条条语句了,这种对应关系不是很明白?)

然后通过定义的四种特征从源代码中提取sSyVCs.

  1. Library/APT function call 。即库函数或者API函数,且其参数至少有一个变量
  2. Array Definition。数组变量声明
  3. Pointer Definition 。 指针变量声明
  4. Arithmetic Expression 。 算术表达式

overview of vuldeelocator

  1. 根据定义的四种vulnerability syntax characteristics,从程序的源代码中切出相应的片段组成sSyVcs。
  2. 然后将程序源代码转换成用LLVM中间语言表示的形式。根据之前从源码中切分出的sSyVcs,然后在转换的LLVM代码中进行替换,生成与sSyVc相关的LLVM切片iSeVCs。
  3. 标记提取出来的iSeVCs。
  4. 训练神经网络。
  5. 用训练好的模型进行检测和定位。

implement

  1. 提取sSyVCs。首先将程序转换成抽象语法树(AST),然后根据AST上每个节点的类型是否满足之前定义的提取规则进行提取。即节点是库函数/API 调用,数组的声明,指针的声明,算术表达式(赋值表达式)。

    作者在这里说上述四个规则,并不是意味着是漏洞的特征。(我想着,可能包含漏洞的语句大概率在这些里面产生,先提取出来减少了检测的范围,过滤了一些无关的语句,但是就将这些提取出来的拼凑,不考虑其它语句的作用是否能提取出漏洞的特征???

  2. 生成iSeVCs。主要可以分为三个步骤,clang 生成bitcode 文件;生成与sSyVCs相关的LLVM切片;生成iSeVCs。算法如下:

    输入:程序P={p1,p2,p3…,pn},sSyVCs的集合 Y={yijkz}

    输出: iSeVCs集合 E={eijkz}

    首先对程序P中的每个文件clang 编译生成 LLVM bitcode 文件pi,然后对这些编译后的文件进行分组。互相有依赖关系的分为一组(比如这个文件的函数在另一个文件中被调用),然后将这一个组的文件链接起来生成bμ

    然后对sSyVCs集合中的每个yijkz在分组后的bμ进行遍历,如果某个sSyVCs yijkz在bμ中,那么就在bμ中将与此yijkz相关的(数据流,控制流依赖)语句切片出来(dg工具进行切片),生成eijkz

    接着将eijkz中所有的被调用的函数(这些函数的源码不在原调函数中)的函数语句附加在原调函数后面,并对这些函数中的变量名进行修改,即接着原调函数中变量名的顺序(比如原调函数最后的变量为%4,那么被调函数的变量则从%5开始)。

  3. 标记iSeVCs。如果此eijkz 有漏洞,那么就用漏洞所在的语句行号作为标签,没有为0。(在源代码中有具体漏洞的位置即行号,这要与中间代码相对应,即在LLVM中间代码中是哪行,不会有多行嘛

  4. 对iSeVCs进行归一化处理,由于LLVM已经对变量名进行了归一化,那么剩下的函数名就统一转换成FUN1,FUN2…

  5. 神经网络构建。由于需要做到输出更细粒度的结果,而一般的BRNN的输入和输出的粒度都是相同的(作者理解的这种相同的粒度不太理解,输出不应该是更加糅杂后的结果嘛)。所以提出了一种新的结构BRNN-vdl

    首先是标准的BRNN结构。双向的RNN,接着dense layer 降维,然后接着 activation layer。BRNN的输入是将iSeVCs转换成token的序列,其输入维度就是token的序列长度。

    后面接了个multiply layer。这层将标准BRNN输出的结果与vulnerability location matrix(这个是对角矩阵。矩阵的维数和BRNN输出的维度相同,即与iSeVCs分解成token序列长度相同。对于用LLVM IR表示后的iSeVCs,之前已经将漏洞位置标记出来了,即漏洞在第几行。那么从漏洞行的第一个token开始到漏洞行结束,这之间的所有token他们对应的对角矩阵中的数值为1,其余为0。如果iSeVCs没有漏洞,那么所有的值均为1) 相乘。

    最后接了个k-max pooling layer 和 average pooling layer。 这个是为了定位到具体的漏洞行数(最后的行数是怎么确定的呢?)。最后输出的是经过max 和 平均后的数值,这个和具体行数的对应关系没有想明白?难道在将iSeVCs转换成token序列时,先记录了每行的token数量?文中并没有提到,不过在对对角矩阵赋值时,是根据漏洞行的token数量进行的,那么应该是将每行的token记录下来了,并将每行的分隔点也记录了

    在训练时,这些层都参与了后向传播,并加入了对角矩阵。在检测时,没有对角矩阵,将网络输出的结果进一步处理得到漏洞的位置。(并不是直接通过网络得到漏洞的定位,是通过学习过程中的信息来得到的)

evaluation

用两个标准来评估。一个是检测是否有漏洞的准确率,一个是定位的准确率。

  1. 检测是否有漏洞的准确率。F1,Accuracy,Precision

  2. 检测定位的准确率。standard Intersection over Union(IoU)。

    用检测出来的漏洞行与实际上的漏洞行交集中的漏洞行数量,与 检测出来的漏洞行与实际上的漏洞行并集中的漏洞行数量的比值。(这个漏洞行应该是对应的源代码)

数据的准备。

  1. 检测是否有漏洞的数据。训练集10,246(NVD)+9,864(SARD)个程序,测试集 2561个程序。然后转换成切片后,下面这是训练集中的正负样本分布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9JTOrT3q-1594777451618)(C:\Users\khy\AppData\Roaming\Typora\typora-user-images\image-20200312000113161.png)]

  1. 定位漏洞的数据。

    2.1 从NVD中提取的iSeVCs,这些NVD数据有diff文件,那么可以根据文件中的行数变化来对漏洞行进行定位(diff文件中有“-”前缀的程序语句)。即这些漏洞语句转换成LLVM后,在LLVM中的行数作为标记。

    2.2 从SARD中提取的iSeVCs,这些SARD数据没有diff文件,如果iSeVCs中有中间代码与源代码中的漏洞代码有关系,那么就将中间代码的行数作为标记。

    这里的疑问还是,转换后不会有多行而非单行的情况嘛

ff文件,如果iSeVCs中有中间代码与源代码中的漏洞代码有关系,那么就将中间代码的行数作为标记。

这里的疑问还是,转换后不会有多行而非单行的情况嘛

你可能感兴趣的:(文章笔记)