Devign: Effective Vulnerability Identifification by Learning Comprehensive Program Semantics via Graph Neural Networks
NIPS 2019
数据集 https://sites.google.com/view/devign
识别的粒度在函数级别,将函数映射成为一个图。(V,X,A)。m 是图中节点V的总个数,d 是每个节点vj的特征向量xj的维数。X是所有的节点的特征向量组成的节点特征矩阵X ∈ Rm×d。A ∈{0*,* 1}k×m×m ,是一个邻接矩阵,k是边的类别数目,eps,t ∈ A 表示如果某两个节点之间的边属于类型p的边,那么其值就为1,否则为0
作者融合了四种边表示类型。首先以最基础的AST节点作为图的节点,然后加上了AST边的属性,控制流图的边属性,数据流图的边属性,Natural code sequence(作者自己定义的,按照编程逻辑顺序的边属性)。每个节点有两个属性code和type,code是指节点所包含的代码的向量表示,type是此节点的类型的label 编码。然后,将这两种表示拼接在一起作为节点的向量表示。(在这里有个疑问?①这里的节点的code部分是在所有的source code file中进行Word2vec,即训练集和测试集都包含了。那么如果遇到新的部分,不在这些数据集中的code怎么处理;② 这个type是有几种类型;③这个直接将两种向量拼接在一起,怎么拼接的?)
作者用Gated Graph Recurrent layer。这里强调一个数据,之前说的节点的特征向量xj,还有个节点状态向量hj。将这些向量转换成node state vector.怎么做的呢?node state vector 的维度是z≥d(d是特征向量的维度),node state vector的前面部分是特征向量xj,其后面部分由零补成。 hj1 = [xjT , 0]T ,
具体实施:
-
数据。 从Linux kernel,QEMU,Wireshark,FFmpeg中。主要是从这些项目的commits进行数据提取的。具体可以参考(Automated identifification of security issues from commit messages and bug reports,fse17)
-
将提取的函数转换成图 。
用开源工具Joern来生成AST和CFG,并过滤了那些有明显错误的函数和不能生成的AST CFG的函数。
在DFG上进行了修改。由于原始DFG是根据变量的依赖关系来进行标记的,造成了edge 的类型急剧增长,因此,将这些类型进行汇总,用三种类型来进行表示。
LastRead(DFG_R)the immediate last read of each occurrence of the variable(表示变量每次出现的最近一个读取)
LastWrite(DFG_W)the immediate last write of each occurrence of the variable()
ComputedForm(DFG_C)在赋值操作中,等号左边变量与等号右边变量之间的关系
其实并不太理解,想知道原DFG中的边的类型是怎么确定的?
-
网络构建。文章说在嵌入层,初始节点的维数是100,这个是Word2vec的维数。那么之前说每个节点除了code部分还有个type部分,那个type部分是多少,怎么确定的?作者没说
gated graph recurrent layer 中,隐藏状态的维数是200,time step是6
Devign 代码逻辑
主要可以分为三大块,
生成代码属性图create task
首先将生成的原始的数据文件json格式进行数据整理。原始json格式是每个函数有4个key,分别是project、commit_id、target、func,然后将json文件转换为dataframe的格式。 之后对dataframe进行去重清理。然后将project和commit_id这两个columns去掉,只保留func和target。
然后将清理后的json文件中的每个函数的源码写入每个C文件中,因为joern只能处理C/C++文件,而在json中的func源码格式是string格式,所以要对这些函数源码进行批量处理。
之后调用子进程 调用joern来解析每个函数的源码文件 生成代码属性图 func{index}.bin
。然后创建了每个代码属性图的索引。
subprocess.run()
这里用到这个来调用子进程。
https://www.liujiangblog.com/course/python/55
接下来就根据索引的信息对生成的bin文件进行解析,运行解析的脚本来提取相关的信息。然后对这些信息也同样创建了索引。信息存储的格式 运行完runScript("graph-for-funcs.sc").toString() |> func{index}info.json
这些就将函数的代码属性图的信息节点和边的信息提取出来了。
下面是调整数据的格式,将每个函数的属性图信息CPG,索引index,函数源码func、标签target全部整合到一个dataframe中,然后进行序列化pickle存储。
将代码属性图进行嵌入 Embed task
将pickle存储的信息读取出来转化成dataframe。然后对其中func 的column即函数源码进行 token解析。解析完后将column的名由func改为token。
然后对cpg中的节点进行处理。新建一个node的column。这里的node信息是对cpg进行解析,只保留那些有code的node和line_number属性的node。
之后将node的code 进行词嵌入,用之前train好的Word vector。然后再拼接上node的类型label就是一个节点的特征向量,之后将这个特征向量转换成tensor。
最后将node的edge进行嵌入,
图神经网络在进行学习过程中主要有两个处理一个是中间的 aggregation 和最后的 readout 。Aggregation是指进行节点状态的更新。在网络的每层,每个节点也是有不同的特征向量feature vector(类似于CNN中的feature map)。Readout是将所有节点的特征向量整合成一个图的特征向量。主要有 spatial-based model 和
图中是很多节点的,和LSTM一样,每层
DeepGraphLibrary
NN4G (Neural Network for Graph)
DCNN(Diffusion-Convolution Neural Network)
DGC(Diffusion Graph Convolution)
MoNET(Mixture Model Network)
GraphSAGE
GAT(Graph Attention Networks )
GIN(Graph Isomorphism Network)
T(Mixture Model Network)
GraphSAGE
GAT(Graph Attention Networks )
GIN(Graph Isomorphism Network)