1.4.2 GNN
的训练流程
从将图输入到GNN
中到得到输出结果 主要可以分为两步:第一步是传播(propagation)过程,即节点表示随时间的更新过程;第二步是输出(output)过程,即根据最终的节点表示得到目标输出(如每个节点的类别)的过程。在这两步中,传播过程要更为重要,其设计也要受到一定的约束(要保证整个图上的状态映射是一个压缩映射(contraction map))。在展开图中,传播过程对应于从t0
到 T 的更新过程(注意,T 并不是确定的,而是对应于整个图的状态到达不动点的时刻),不同时间步的连接则由图中的连接来决定(可以是有向的,也可以是无向的
1.4.3 门控图神经网络
门控图神经网络是在图神经网络的基础上,引入了"门",如GRU
和LSTM
,旨在改善图结构信息的长期以来性,同时引入了边缘信息
1.5 各种源代码表示方法
源代码不能直接输入到图神经网络中,所以需要先将源代码转换为可表达漏洞特征的向量,但在这过程中,我们保留源代码数据中的一些语义信息(例如数据依赖性和控制依赖性),通常还需要引入一个中间表示来作为源代码和向量表示之间的过渡,这些中间表示可以让我们更加直观的了解到代码中数据的走向以及逻辑关系等,常见的表示方法有以下几种:
令牌序列表示
该方式将源代码视为纯文本,首先使用词法分析来扫描源文件,在这个过程中,字符流被分成 Token ,一般来说,编程语言中常见的 Token 是:常量(整数、小数、字符、字符串等。)、运算符(算术运算符、比较运算符、逻辑运算符)、分隔符(逗号、分号、括号等)。)、保留字、标识符(变量名、函数名、类名等。),等等
抽象语法树(AST
)
该方式是源代码的有序树表示,通常,代码分析器用它来理解程序的基本结构,并在表示的第一步检查语法错误,从根节点开始,代码被分成块、语句、声明、表达式等,最终形成叶结点的 Token
控制流图(CFG
)
该方式描述了执行过程中可能经过的路径,在CFG
中,节点代表语句和条件,。它用图的形式表示一个过程内所有基本块执行的可能流向, 也能反映一个过程的实时执行过程
程序依赖图(PDG
)
程序依赖图(Program Dependence Graph)是程序的一种图形表示,它是带有标记的有向多重图。程序依赖图能够表示程序的控制依赖和数据依赖关系,因此,它由(数据依赖图)DDG
和(控制依赖图)CDG
组成
代码属性图(CPG
)
在联合数据结构中结合了抽象语法树、控制流图和程序依赖图的特征,可以结合多种表示法的优点。AST
将源代码中的所有标记和谓词表示为一个节点,这个节点比CFG
和PDG
还要细分。因此,以AST
为主体,集成控制和数据依赖,形成代码属性图
2.论文思维导图
3.论文详解
3.1 摘要
近年来,软件程序趋于庞大和复杂,软件已经成为现代社会的基础设施,但软件安全问题也不容忽视。软件漏洞已经成为威胁计算机安全的主要因素之一。利用源代码漏洞发动攻击的案例数不胜数。与此同时,开源软件的发展使得源代码漏洞检测变得越来越重要。传统的漏洞挖掘方法存在较高的误报率和漏报率,已经不能满足复杂软件的安全分析需求。针对存在的问题,提出了一种基于混合语义的图神经网络漏洞挖掘系统hyvulDect
,该系统根据漏洞产生的原因构造了一种复合语义码属性图进行代码表示。采用门控图神经网络提取深度语义信息。由于大多数漏洞与数据流相关,我们使用污染分析提取污染传播链,使用BiLSTM
模型提取上下文的令牌级特征,最后使用分类器对融合特征进行分类。我们引入了一种双重关注机制,允许模型关注漏洞相关的代码,使其更适合于漏洞挖掘任务。实验结果表明,hyvuldect
算法在基准数据集上的准确率达到92%,优于现有方法。与基于规则的静态挖掘工具Flawfinder
、RATS
和Cppcheck
相比,它具有更好的性能,能够有效地检测出实际的CVE
源代码漏洞
3.2 贡献
背景:现有的软件趋于大型化和复杂化,项目的代码量急剧增加。单纯使用人工审计代码的成本非常高,发现触发条件复杂的漏洞是困难的;
基于传统机器学习的方法需要人工提取漏洞特征,依赖大量的专家知识。基于深度学习方法(Lin et al., 2020),将源代码视为自然语言序列,利用现有的自然语言处理方法进行特征表示,总结出漏洞的特征,用于检测和分类。这些方法可以有效地在源代码中捕获源中漏洞触发的上下文信息。然而,没有考虑源代码的结构特征,此外,许多语义信息在代码表示中丢失
图神经网络可以处理代码图表示等非欧几里得数据,但现有方法将源代码表示为AST
和CFG
,缺乏源代码的数据依赖信息,不利于漏洞检测。同时,直接使用程序源代码作为图形神经网络的输入会引入大量冗余代码,不利于模型的学习
我们提出了一个基于混合语义的图神经网络漏洞挖掘系统HyVulDect
。该系统结合了源代码图级特征和污点传播链令牌级特征用于漏洞检测。首先,对源代码进行预处理并表示为复合语义代码属性图,然后使用具有多头注意机制的门控图神经网络提取深层语义和结构信息。同时,通过污点分析方法提取源代码中的源->宿污点传播链并表示为标记,通过具有自关注机制的**BILSTM
提取语法和上下文信息**。最后,融合图级和标记级特征,使用XG- boost
分类器进行分类。该方法不仅能更全面地提取源代码中丰富的语义信息,还能关注代码上下文信息,具有更好的检测能力
贡献如下:
-
我们提出了一个基于混合语义的图神经网络漏洞挖掘系统,该系统利用具有双注意机制的门控图神经网络和BiLSTM
网络来提取源代码图级和令牌级特征。融合两个维度的深层特征可以有效地用于检测漏洞
-
我们改进了基于API
调用的程序切片算法通过补充程序切片的结构,在提取漏洞上下文信息的同时保留代码的结构信息
-
基于该设计方案的实验表明,HyVulDect
检测性能优于传统静态扫描工具。与最先进的探测器相比,Devign
、VUDDY
和BGNN4VD
的精度分别提高了27.6%、14.2%和4.9%。同时它能有效地检测存在的CVE
漏洞
3.3 实现过程
基于混合语义的图神经网络漏洞检测系统:HyVulDect
,其整体架构如下图所示:
在该系统中,主要分为了三个部分:
1、源代码图级特征提取(Source code graph-level features extraction
):首先源代码表示为包含多种语义信息的联合图CPG
,然后使用门控图神经网络提取源代码的图级特征
2、污点传播链的令牌级特征提取(Tokens-level features extraction of taint propagation chain
):通过污点分析提取源代码中的污点传播链,然后使用带有自关注机制的BiLSTM
算法来提取令牌级特征
3、分类模块(Classifier
):融合前两部分所提取的源代码特征,使用预先训练好的XG-boost
分类模型进行漏洞分类
3.3.1 源代码图级特征提取
预处理
为了简化代码,准确定位引起漏洞的代码行,我们首先要对代码进行预处理
1、确定危险函数:漏洞形成的根本原因是外部输入没有经过正确的处理,从而进入了危险函数,所以我们要对危险函数进行定位,然后根据危险函数中所传入的参数来回溯所有与之相关的代码行,然后将这些代码按照执行顺序重新组织。在处理函数的过程中,有一些用户自定义的函数和变量,为了统一化,在这里对这些自定义函数进行了函数名和变量名的修改——统一将自定义函数名改为func_N
,将自定义的变量名改为var_N
,其中N
为正整数(0,1,2,3,·····)
2、程序片的补充
关于程序切片的相关知识可以参考文章:程序切片知识点整理(程序依赖图、静态切片、动态切片)
在该步骤中,由于前面的操作提取了与漏洞相关的代码行,使得代码更加简介易于分析,但是源代码的结构也不再完整,所以该步骤主要是为了补充源代码的结构信息。
在解析源代码时,提取代码中的用户自定义函数和控制块,以补充切片代码。完成切片后,首先,从上到下扫描代码切片。如果该行代码是自定义函数,则在该行下面加上结构代码“{”,继续向下扫描,直到遇到一行不属于自定义函数的代码,在它前面加上“}”,就完成了一个函数结构的补充。在这样的过程中,所遵循的原则为:先完成函数结构,再完成控制结构。切片补充的算法伪代码如下所示:
3、形成图形数据
使用了Joern
工具来将源代码解析为图形数据,该工具是一个C/C++代码分析工具。主要功能是从源代码、控制流图和程序依赖关系、代码属性图中生成抽象语法树,并将它们存储在图形数据库neo4j
中。在这个过程中,我们对其进行了一点改进:我们发现Joern
生成的CPG
中的两个节点同时包含控制流边和它们之间的数据相关边,我们将其合并为一条新边作为CAD
。生成CPG
后,使用DGL
算法来构造图形数据,其算法如下图所示:
对于图中的节点和边特征,我们使用预先训练好的**Word2vec
**模型进行矢量化
特征提取
下图展示了详细的特征提取过程:
1、Embeddings
:该过程使用了门控图卷积层提取了一些底层特性,然后引入归一化层,使得较大的学习速率对于帝都传播更加稳定,增加了网络的泛化能力
2、Conv1
:这个过程使用sigmod
函数作为激活函数
3、Attention
:该过程引入了注意力机制,用于对相邻结点进行加权求和,并计算每个节点的隐藏状态,而多头机制用于将模型分成多个头部,形成多个子空间,使得不同的头部可以关注不同方面的信息,这有助于模型捕捉更丰富的特征信息
4、Conv2
:该过程使用了ReLu
函数作为激活函数
5、经过一层Dropout
,断开 30% 的神经网络,减小模型规模,同时提高模型的收敛速度
6、Mean Node
:叠加一层图形卷积层,提取最高层的特征得到最终特征
3.3.2 污点传播链的令牌级特征提取
污点分析可以跟踪和分析程序中的污点信息流,我们使用跟踪变量来分析污染信息流,并使用队列来记录污染变量。
预处理
该步骤和源代码的图级特征提取的预处理一样,包括其中的命名统一化,使用Word2vec
预训练模型进行矢量化,发现发现91.4%的源代码污点传播链令牌数不超过800。因此,选择了800作为所有向量的阈值
特征提取
主要方法是使用BiLSTM
模型进行令牌级特征提取,其中BiLSTM
是向前LSTM
和向后LSTM
的结合,可以学习序列化和长期依赖的特征,并捕捉序列之间的隐式依赖
1、在嵌入层将令牌序列表示为矩阵。
2、BiLSTM
层接收矩阵作为输入,学习记号之间的深层联系,并输出记号的中间表示。
3、添加关注层可以使模型更加关注与漏洞相关的令牌。关注层接收代码的隐藏表示作为输入,然后初始化三个矩阵Wq
、Wk
和Wv
,将上层输出转换为Q,K,V,从而获得代码的深层表示。
4、加入Dropout层来随机断开一些神经元以降低模型复杂度,增强模型的泛化能力并防止过拟合,并加入密集层来匹配前一层神经网络。添加归一化层以解决梯度消失和爆炸问题。接下来,
5、使用ReLu
函数激活神经元,并再次通过Dropout
层和密集层。最后得到令牌级的深度特征
3.3.3 漏洞分类
在该步骤我们将上述得到的源代码图级特征和污点传播链的令牌级特征串联起来得到最终的源代码特征。基于CPG
的图级特征包含源代码数据依赖、控制依赖和其他语义信息。基于污点分析的标记级特征包含源代码漏洞上下文语义信息和代码序列语法信息。最终获得的特征结合了代码的结构、句法和语义信息,并且可以覆盖多种类型的漏洞。
漏洞分类的过程中主要使用的是XGBoost
算法,该算法本质上是GBDT
算法,在通过特征分裂来持续生长一棵树的过程中,每一轮学习一棵树的过程都将预测值与上一轮模型的实际值之间的残差进行匹配。当训练完成得到k棵树时,要预测一个样本的得分,根据这个样本的特征,在每棵树中都会落到一个对应的叶节点上,每个叶都对应一个分数,最后将每棵树对应的分数加起来就是这个样本的预测值。