范志鹏, 李 军, 刘宇强, 钮 焱
(湖北工业大学计算机学院, 武汉 430068)
随着互联网的发展以及大数据、云服务等计算机技术的广泛应用,同时也带来了新环境下的网络安全问题。恶意软件也变得更加复杂多样化。根据报告[1]显示, 2018年全球就有54个国家的超过50万台路由器和设备被黑客组织用来控制电脑。由于恶意代码检测的局限性,部分恶意代码产生的变种代码给恶意代码的检测带来了极大的困难。Greengard[2]研究表明大多数恶意代码都是由已知的恶意代码变种而来,变种代码之间的差异性只有不到2%。因此,认清这些恶意代码类别可以帮助研究人员更好地掌握恶意代码变种规律,同时可以提供准确的防范机制。
为了确定恶意代码功能属性并对其进行分类,研究人员探索了许多对恶意代码检测和识别的方法[3-4],但面对大量使用混淆技术的恶意代码来说,传统的分析方法都存在一定的局限性[5]。静态分析容易受到混淆技术干扰,动态分析只有在满足恶意代码触发条件时才能检测出恶意行为。为了提高检测效率,克服现有分歧技术的特点,通过将恶意代码可视化与神经网络训练相结合的方法进行研究已经成为恶意代码检测的新的研究方向。
近年来,通过这种方法对恶意代码检测有很多有意义的研究成果。Ranveer等[6]提出通过提取指纹特征来进行恶意代码分类检测,建立特征库对于恶意行为进行分类。但由于分类模糊,随着样本数量增多,不及时更新特征库就会延误检测。Gove等[7]以视觉的方式对恶意代码库中大型属性集进行比较,能更直观地看出同类别恶意代码的共通之处,便于解决恶意代码中混淆技术难题。Hashemi等[8]利用恶意文件的微观模式观测不同文件的攻击行为和功能,在不丢失边缘数据的同时对恶意文件进行检测。任卓君等[9]提出利用N-gram特征进行恶意代码可视化,有效减少了冗余信息改变全局图像特征的问题。王国栋等[10]对恶意代码4个家族4 418个样本采用深度学习方法分类,证实了通过图像方法来进行恶意代码分类能够有效判定恶意代码家族类别。孙博文等[11]通过将原始灰度图像作为输入,构建三维图像进行训练,比直接训练原始灰度图像取得了更好的效果。
本文的基于改进的灰度纹理指纹的恶意代码分类方法是将恶意软件代码理解为图像并提取指纹特征,利用深度学习算法来提升检测的准确率。主要贡献是以下几个部分:①将恶意代码建模为灰度图,由二进制特征值转化为像素特征值,并通过二维和三维的灰度共生矩阵(gray-level co-occurrence matrix,GLCM)提取灰度图的指纹特征(指纹纹理图);②本方法与直接对二进制文件进行静态检测,避免了直接执行带来的危害后果,也能够很好地克服加密、变形后的恶意代码识别问题,③结合汇编指令的长度属性取不同的步长作为不同的特征训练集,并改进GLCM算法对图像特征降维; ④使用深度学习中卷积神经网络(convolutional neural networks, CNN)算法实现恶意代码分类,并与机器学习分类算法进行比较。
对于恶意代码检测目前主要有两个方向[[12-13]:一种是基于恶意代码二进制文件的静态检测方法,将恶意代码反汇编后的文件和文件组织构建样本特征;另一种是基于恶意代码行为的动态检测,在恶意代码运行时分析具体行为来构造索引进行检测分类。对于静态检测,Bayer等[14]提出通过函数静态调用图提取每个恶意样本的细粒度特征,该方法创新于用图片来作为两个恶意代码之间的对比,但没有数据支撑。在此之后Conti等[15]首次提出了对于恶意代码图像化的想法;2011年Nataraj等[12]提出了完整的将恶意代码转化成图像的方案,此方案中对特定的数据集取得了98%的准确率。此方法一经推出,立刻引发研究人员的广泛关注。恶意代码二进制文件由于都是操作指令,可以转化为形成具有一定频率的纹理图像。刘舒等[16]研究发现,当图像的灰度级较低时,利用灰度共生矩阵可以很好地提取图像的纹理特征,便于图像的进一步研究。Kancherla等[17]提出用强度和纹理特征来对恶意代码进行分类检测,取得了95%的准确率,但算法使用的是支持向量机(support vector machine, SVM)算法,并且样本并没有使用公开数据集。韩晓光等[18]在恶意代码图像纹理聚类和选择上做出创新性进展,通过灰度共生矩阵选择6个贡献最大的特征值来创建纹理特征库,通过对比特征库来进行识别。Samira等[19]研究表明,在图像识别方面,深度学习算法比传统的机器学习算法更加优秀。在2015年微软举办的恶意代码分类比赛中,其中获得冠军的团队[20]就是使用了将恶意代码转化为图像的方法进行分类,最终以较大优势夺得冠军,本文数据集也来源于此次大赛。
动态检测则利用虚拟化技术使恶意代码在模拟环境下充分执行,通过对比执行前后的环境和验证其恶意行为来进行判断分类。Rieck等[21]首次利用动态行为特征,使用K邻近(K-nearest neighbor, KNN)算法达到了88%的准确率。随着虚拟化技术的不断进步,动态检测准确率也在不断提高。Tang等[22]提出了提取API调用序列的动态分析法,然后使用颜色映射规则表示恶意软件行为的特征图像,通过卷积神经网络达到了较高的训练效果。Zhang等[23]提出了利用静态分析的方法可以将操作序列码转化为N-gram序列,此方法对于勒索代码达到了最好的91%准确率。中国还有许多将动态分析与静态分析结合分析的研究。张晨斌等[24]利用深度学习caffe框架在安卓平台上搭建了一个恶意软件分类平台,该平台能够在线检测和分类恶意代码,通过静态分析匹配恶意代码的特征码和信息摘要算法(message-digest algorithm, MDA)(由文件产生的固定密码散列函数),在无法匹配时采用分离恶意代码中的dex文件,利用深度学习算法进行训练。刘全飞等[25]利用云平台技术对恶意代码的动态检测,在云平台中每个使用者都可以上传自己评价标准,通过结合所有权重来实现信息的动态维护,从而实现自主防护。孙博文[26]实现了一种基于恶意代码应用程序编程接口(application programming interface, API)的变种检测方法,先将恶意代码的API转换为词向量,再通过改进的深度学习算法来进行检测,该方法对于迁移检测有着很好的检测效果,在恶意代码变种检测上有了一定的进展。
综上所述,目前恶意代码分类检测已经取得了较多的研究成果,但无论是静态检测还是动态检测都具有一定的局限性,静态特征无法适应新变种的出现,动态检测容易受到缓延迟技术的影响[27],调用大量无关API占用系统资源,使检测超出系统设置的执行时间,从而规避检测。现提出基于静态代码分析的方法,将恶意代码的二进制文件理解为图像,提取纹理指纹并规范化,该方法不需要动态地执行过程,可以克服动态分析的主要局限,也有很强的泛化性。
鉴于目前图像识别算法成熟的优势性,主要将恶意代码二进制文件理解为图像并进行分类检测。恶意代码主要是经过系统编译过的二进制指令,也可以转换为基础的汇编指令,由于单个恶意代码大小比常规图像识别中的图像要大很多,且恶意代码当中本来就有一定的干扰代码混入其中,因此需要将恶意代码进行一定的分割降维处理,在分割上采用了在纹理分割上十分优秀的灰度共生矩阵完成[28],同时以不同的步长分割出的恶意代码作为对照组加入到原始数据集中进行学习,达到混淆特征的目的,随后使用CNN方法来完成对恶意代码的训练分类。总体方法思路如图1所示。
图1 恶意代码识别分类流程Fig.1 Malware recognition classification flowchart
灰度共生矩阵是研究图像像素的空间相关特性的常用方法。利用灰度纹理特征来表示大规模的图像纹理数据集可以以最小的资源占比来归纳所有的图像,Gotlieb等[29]在研究共生矩阵中研究出的一种归纳特征提取的方法,该方法后被证实对于细微纹理归纳时有良好的效果。灰度共生矩阵主要是对图像上保持一定距离的像素点之间的灰度情况进行统计,根据图像中距离为d、方位关系度数为θ的两个像素点构建联合概率分布p(g1,g2|d,θ),其中g1、g2表示矩阵内两点的坐标。对于联合概率分布由于对角线通常进行了归一化:
(1)
式(1)中:N为灰度常数。
通常以3个角度的联合统计数据就能够归纳出原始图像的所有特征,通过选择其中影响最大的几个特征作为特征值,可以在关键信息丢失率最低的情况下进行降维处理。刘天时等[30]证明了将GLCM算法中提取出的特征代入到不同方向的权值因子,可以提高纹理图像的识别准确率,并且GLCM算法能够找出其相关性过大的部分进行分割,除了保存关键信息外,也能够很好的剔除掉干扰混淆的部分。
对于GLCM算法中的特征值,Haralick等[31]提取了14种特征,但部分特征值线性相关性强,统计意义不大。为了降低分析模型的复杂度,同时也从人的主观感受出发,通常是以粗糙度、对比度、方向度、线性度、规则度和粗细度来概括出灰度图的整体特征,最常见的特征为能量、熵、对比度、相关性。
能量(angular second moment)表示图像的变化程度,能量越大表示图像越无规律可循,通常也用来表示为图像的噪声,计算方法将GLCM算法矩阵当中所有值进行平方后求和,具体计算公式为
(2)
熵(entropy)中二维数组数字差异变化越大,表现出的图像越复杂,具体公式为
(3)
为了尽量地保持信息率,在深度学习CNN中,用每个小图像块的熵值来代替了CNN过程中的卷积步骤。
每个恶意软件文件的二进制代码长度不一,经过文本可视化后,可以看到恶意软件代码可以列为由众多的1字节16进制数构成的一维向量,数据集中最长的长度为405 248×16 B,最短向量的长度为8 950×16 B。若直接理解为图像,显然图像大小不一,带来后续训练和检测的困难,因此,需要提取每个恶意软件图像的指纹特征,并形成统一大小的特征指纹图像。考虑到代码的顺序结构执行特征,只采用了水平方向的步长,而不考虑其他方向。
首先选择步长为1、2、3,建立灰度共生矩阵。原因如下:在操作系统以及汇编指令手册的分析中可以知道,计算机代码中大部分由1字节、2字节、3字节指令构成,如分类1:没有操作数的指令,指令长度为1字节 ;分类2:操作数只涉及寄存器的指令,长度为2字节;分类3:操作数涉及内存地址的指令,长度为3字节等。因此,在灰度共生矩阵中采用了1字节、2字节和3字节的灰度共生矩阵。首先分别以1字节、2字节、3字节为单位切割恶意软件代码行向量并做统计。通常灰度共生矩阵考虑的是距离为d的1字节同时出现的统计,在文献[18,24]均为1字节矩阵。该矩阵行列坐标为0~255,统计每个字节中对应的数值出现个数。对于2字节灰度矩阵,则行代表第一字节,列代表第二字节,如EB 3C代表(EB行,3C列),每出现1次该代码,则该位置值加1,直至循环遍历整个恶意软件代码。其中,1字节和2字节矩阵均可形成256×256的标准输入矩阵,1字节灰度共生矩阵为主对角对称矩阵。
恶意软件中的单个操作码与普通代码并无太大差异,而较长的操作码具有预测现象发生的能力。为了减少这种信息的丢失,以3字节切割,继续生成3字节的灰度共生矩阵(256×256×256)。对于每个恶意软件样本,均生成了3个指纹纹理图像,为了统一为256×256维度,改进了单字节的GLCM,特别提出了二维和三维的GLCM,并对三维的 GLCM 进行了线性降维主成分分析 (principal components analysis, PCA)方法处理。
降维是机器学习中非常重要的一种方法,保障数据在训练的过程有着合理的稀疏性。程序代码每3个字节分节对应着(x,y,z)3个维度,每个维度为(0~255),构成了三维矩阵A,任2个维度之间如(x,y)的协方差表示了2组数据的相关性,具体公式为
(4)
设数据集p={x,y,z},相应的,依次计算其他二维协方差,从而构建出三维矩阵的协方差矩阵为
(5)
式(5)为三维协方差矩阵,对角线为样本每一维的本身方差,将其所有数据进行去中心化操作,如对于x:
(6)
由式(6)中心化后,式(5)可以简化为:
(7)
m=3,对式(7)做特征值分解,求出特征值w1、w2、w3和相应的特征向量,得到式(8),对特征值做对角化处理并排序,取最大的2个特征值,并列出所对应的特征向量,具体公式如下:
(8)
这时找到了矩阵E,满足ETCE是一个对角矩阵,E中向量由单位化的特征向量构成。因E对应Λ中特征值,因特征向量从上到下排列,则用E的前2行组成的矩阵乘以原始数据矩阵x,就得到了需要的降维后的数据矩阵y。并且对角元素按从大到小依次排列,那么p的前k行就是要寻找的基,用p的前k行组成的矩阵乘以x就使得x从N维降到了K维并满足上述优化条件。将特征向量对应的特征值按照大小从上到下进行排列,取前di行组成矩阵p,最终得到降维后的数据为B=pA。
通过PCA方法,将256×256×256矩阵降至为256×256,并尽量保持了原始的信息量,这样,每个恶意代码样本就得到了3个共生灰度矩阵,并将每个样本图像增加为3个,作为增强型数据,扩大了样本量,为后续的CNN网络训练提供了很好的训练集。以样本文件0aKlH1MRxLmv34QGhEJP.bytes为例,通过可视化得到了图2所示的3个指纹纹理图像。
图2 样本文件指纹纹理图像Fig.2 Sample file fingerprint texture image
使用 keras-learn作为机器学习库。Keras是一个高级神经网络API,用Python编写,能够运行在TensorFlow、CNTK或Theano之上, 该学习库将深度学习模型理解为一个独立的、完全可配置的模块的序列或图,神经层、成本函数、优化器、初始化方案、激活函数和正则化方案都是独立的模块,可以组合起来创建新的模型。由于用于监督和非超级组合问题传统的卷积神经网络在进行卷积池化的过程中会损失一定的信息,对于识别物体来说,损失的信息可以通过关键信息来弥补,但会造成识别准确率一定程度的降低,对于纹理图像来说,单纯的卷积操作通常将3×3或5×5的矩形块由某种均值或最大值代替,而代码往往是线性执行的,更强调顺序性。因此对于常规的池化操作来进行卷积操作会造成一定的信息率丢失,因此,对该卷积层采用了灰度共生矩阵的信息熵来代替。构建的CNN模型中,采用了1层卷积+1层熵值。将灰度共生矩阵进一步划分成5×5的小矩阵块,并对每个小矩阵块求熵,熵的计算过程采用了式(3)的方法。该方法在原始CNN模型上做出了改进,将灰度共生矩阵每个小矩形块熵作为池化方式,为了进一步降维,在第2层中采用了传统的卷积操作,选择3×3矩形块,在尽量避免池化过程丢失信息的同时,数据的规模也得到了缩小。
通过使用keras-learn,可以调整算法的参数。经过在不同算法中使用不同参数的多次测试,最终选择了以下参数。输入图像维数为(256,256,1),第2层卷积核为(3,3),activation函数设为tanh,dropout率为0.2,全连接层为10,学习的最大深度为5,学习率为0.005。考虑到部分恶意软件代码非常大,例如,样本集中最大的文件达到14.2 M,预处理和输入图像(256×256)都较耗费内存,不适合整体读入训练,因此采用了分批训练的方式,每次读入10个图像。
为了检验基于恶意代码图像纹理特征提取的效果,继续采用传统的机器学习算法来验证该特征提取方式的有效性。主要包括随机森林(random forest, RF)、K最近邻[32]。随机森林算法是一种能够对大量数据进行准确分类的新型分类技术[33],KNN聚类是一种基于相似性将数据对象分为多个簇的分块聚类方法。分别对直接的原始数据和GLCM特征提取后的数据进行分类比较。
采用的数据集为微软2015年恶意代码分类大赛中指定数据集,BIG2015数据集包含9个恶意家族的21 741个样本,其中10 868个样本为带标签的训练集,其他为不带标签的测试集。训练集中,每一个样本包含一个20字符的哈希ID和一个整数值的家族标签,分别为Ramnit、Lollipop、Kelihos ver3、Vundo、Simda、Tracur、Kelihos、ver1、Obfuscator.ACY和Gatak。每个恶意样本包含两个文件,分别为十六进制表示、去除PE头的二进制文件和反汇编工具IDA生成的包含机器码、汇编指令等的元数据文件。在通过切割代码后,经过上一节GLCM算法来自不同步长的矩后,对形成的不同图像做训练对比。实验使用的操作系统为CentenOS 7.0 64位, Tensorflow框架。
模型的训练时间与内存、CPU直接相关,而在检测时主要的时间耗费在预处理的计算上,预处理所需的时间与恶意软件代码长度有关,随着代码长度的增加而增加,而训练时间却可以忽略不计。如表1所示,每个文件由于要预处理3个灰度共生矩阵,故随着恶意代码大小而检测时间增加明显。
表1 检测时间比较Table 1 Detection time comparison
为了比较特征提取效果,同时对比了机器学习研究领域较为传统的典型分类算法,RAW代表直接处理原始数据,GLCM为采用灰度共生矩阵数据分类。具体检测结果如表2所示,可以看出,基于GLCM的CNN模型方法具有更高的准确率。采用了GLCM特征提取后的分类方法效果均比以前有了显著的提高,其中,GLCM-RF随机森林方法准确率达到了96%,较未采用图像特征提取的RF方法提高了约10%,CNN方法提高了约4%。
表2 各分类算法结果的比较Table 2 Comparison of results of different classification algorithms
另一方面,为了比较第1节相关研究中的分类算法,对于恶意代码文件,也将样本文件直接理解为一个灰度图片,但是这个灰度图片随着代码长度不同而大小不一,为了能够应用深度学习,采用了统一的尺寸512×512作为输入。对于小于该尺寸的代码,在代码后面补0,而超过该尺寸的代码,直接截取前面512×512个字节(绝大部分文件未超过此长度)。实验发现,直接训练也取得了不错的准确率(表2中RAW-CNN)。考虑到特征提取的时耗,还采用了直接提取恶意代码文件的前64 K字节作为数据集来进行比较,通过分析统计数据可以看出,该训练过程很早就出现了过拟合现象,虽然达到了100%的训练正确率,但在实际泛化识别过程中,识别率降为了89%。
图3所示为上文所述数据集分别采用原始数据的图像灰度图和灰度共生矩阵在训练过程中准确率(RAW/GLCM/64 k)和损失率随迭代次数变化的曲线图。通过比较可以看出,模型GLCM+CNN相比于直接的灰度图像CNN 模型在训练的收敛速度和损失率上有着明显的优势。基于灰度纹理指纹的恶意代码分类训练集准确率为99.2%,在测试集中检测准确率为96.2%。
图3 原始数据/改进灰度指纹图像/64K原始数据的CNN模型训练过程比较Fig.3 A comparison of the training process of original data/improved gray fingerprint image/64K original data
研究了针对恶意代码分类中图像特征提取的优劣,提出一种基于改进的GLCM恶意代码分类方法,使用代码的增强的灰度共生矩阵作为对象特征,通过机器学习算法训练和检测恶意代码图像,实现了从图像纹理角度对恶意代码家族进行分类。实验表明,基于灰度纹理特征的恶意代码分类方法效果优于传统的卷积神经网络、随机森林、K邻近算法,提高了识别准确率,并且泛化效果更好。