恶意软件检测(2)Dynamic Malware Analysis with Feature Engineering and Feature Learning

Dynamic Malware Analysis with Feature Engineering and Feature Learning

  • 项目:https://github.com/joddiy/DynamicMalwareAnalysis
  • 文章:https://arxiv.org/abs/1907.07352

摘要

动态恶意软件分析在隔离的环境中执行程序,并监控其运行时行为(如系统API调用),以检测恶意软件。该技术已被证明对各种代码混淆技术和新发布的(“零日”)恶意软件有效。然而,现有的工作通常只考虑API名称而忽略参数或者需要复杂的特征工程操作和专家知识来处理参数。在本文中,我们提出了一种新的、低成本的特征提取方法,以及一种有效的深度神经网络体系结构,用于准确、快速地检测恶意软件。具体而言,特征表示方法利用特征哈希技巧对与API名称关联的API调用参数进行编码。深度神经网络体系结构应用多个选通CNN(卷积神经网络)来转换每个API调用的提取特征。通过双向LSTM(长-短期内存网络)进一步处理输出,以了解API调用之间的顺序相关性。实验表明,我们的解决方案在大型真实数据集上的性能明显优于基线。从烧蚀研究中获得了有关特征工程和建筑设计的宝贵见解。

一、说明

网络安全给全世界带来了巨大的经济成本。美国政府的一份报告(CEA 2018)估计,2016年美国经济中恶意网络活动的成本在570亿美元至1090亿美元之间。恶意软件(或恶意软件)是快速发展的主要网络安全威胁之一。据报道,每年发现超过1.2亿个新的恶意软件样本(AV-TEST 2017)。因此,开发恶意软件检测技术是迫切而必要的。

数十年来,研究人员一直致力于恶意软件检测。主流解决方案包括静态分析和动态分析。静态分析方法扫描软件的二进制字节流以创建签名,如可打印字符串、n-gram、指令等(Kruegel等人,2005)。然而,基于签名的静态分析可能容易受到代码混淆的影响(Rhode、Burnap和Jones,2018;Gibert等人,2018),或者不足以检测新的(“zeroday”)恶意软件(Vinod等人,2009)。相反,动态分析算法在隔离的环境(例如沙盒)中执行每个软件,以收集其运行时行为信息。通过使用行为信息,动态分析的检测率更高,比静态分析更稳健(Damodaran et al.2017)。在本文中,我们主要关注动态分析。

在行为信息中,系统API调用序列是最常用的数据源,因为它捕获了软件执行的所有操作(包括网络访问、文件操作等)。序列中的每个API调用都包含两个重要部分,即API名称和参数。每个API可能有零个或多个参数,每个参数都表示为名称-值对。为了处理行为信息,提出了许多特征工程方法。例如,如果我们将API名称视为一个字符串,则可以提取最多N个(例如1000个)频繁的N-gram特征(N=1,2.....) 从序列中。然而,从异构类型的参数(包括字符串、整数、地址等)中提取特征并非易事。最近,研究人员将深度学习模型应用于动态分析。卷积神经网络(CNN)和递归神经网络(RNN)等深度学习模型可以直接从序列数据中学习特征,而无需进行特征工程。尽管如此,计算机视觉和自然语言处理等传统深度学习应用程序的数据是同质的,例如图像(或文本)。使用深度学习模型处理异构API参数仍然具有挑战性。因此,大多数现有方法都忽略了这些参数。有几种利用API参数的方法(Tian et al.2010;Fang et al.2017;Agrawal et al.2018)。然而,这些方法要么将所有参数视为字符串(Tian et al.2010;Agrawal et al.2018),要么只考虑参数的统计信息(Ahmed et al.2009;Tian et al.2010;Islam et al.2013)。因此,它们无法充分利用来自不同类型参数的异构信息

在本文中,我们提出了一种新的特征工程方法和一种新的恶意软件检测深度学习体系结构。特别是,对于不同类型的参数,我们的特征工程方法利用哈希方法分别提取异构特征从API名称、类别和参数中提取的特征将进一步串联并输入到深度学习模型中。我们使用多个选通CNN模型(Dauphin et al.2017)从每个API调用的高维哈希特征中学习抽象的低维特征。来自选通CNN模型的输出由双向LSTM处理,以提取所有API调用的顺序相关性。

我们的解决方案比所有基线都有很大的优势。通过广泛的烧蚀研究,我们发现特征工程和模型架构设计对于实现高泛化性能至关重要。本文的主要贡献包括:

  • 我们为系统API参数提出了一种新的特征表示。从我们的数据集中提取的特征将发布供公众访问。
  • 我们设计了一种深度神经网络结构来处理提取的特征,它将多个门控CNN和一个双向LSTM相结合。它以巨大的利润超过了所有现有的解决方案。
  • 我们在一个大型真实数据集1上进行了广泛的实验。通过消融研究,发现了有关特征和模型架构的宝贵见解。

二、相关工作

在本节中,我们将从特征工程和深度学习的角度回顾动态恶意软件分析。

2.1 API调用的功能工程

(Trinius等人,2009)介绍了一种称为恶意软件指令集(MIST)的特征表示。MIST使用多个级别的功能来表示系统调用。第一级表示API调用的类别和名称。以下级别是为每个API调用手动指定的,以表示它们的参数。然而,对于不同的API,同一级别的特性可能表示不同类型的信息。这种不一致性给使用机器学习模型学习模式带来了挑战。

(Qiao等人,2013)扩展了MIST,提出了一种称为基于字节的行为指令集(BBIS)的表示。他们声称,只有MIST的第一级(API调用的类别和名称)是有效的。此外,他们还提出了一种算法CARL来处理连续重复的API调用

统计特征是训练机器学习模型的常用方法。提取API调用名称及其参数中的字符串,以计算频率和分布,作为中的特征(Tian et al.2010;Islam et al.2010;2013)。(Ahmed et al.2009)还使用统计特征来捕获空间和时间信息。从参数中提取空间信息,如均值、方差和熵。时间信息来自ngram API调用,包括两个n-gram API调用之间的相关性和转换可能性。

(Salehi、Ghiasi和Sami 2012)提出了一种将API调用与其参数关联起来的特性表示。它将每个参数与其API调用的名称连接起来,形成一个新的序列,然而,这种方法会导致一个非常长的特征向量,并且可能会丢失API调用序列的模式。

(Hansen等人,2016)提出了另外两种特征表示法。这些表示包括前200个API调用及其“参数”。但是,此“参数”仅指示此API调用是否与后一个API调用连接,而忽略原始参数。

2.2 Deep Learning Based Approaches

(David and Netanyahu 2015)将沙盒报告视为一个完整的文本字符串,然后用任何特殊字符拆分所有字符串。他们计算每个字符串的频率,并使用20000位向量来表示最频繁的20000个字符串。他们的模型是一个深度信念网络(DBN),由八层组成(从20000个大小的向量到30个大小的向量)。利用交叉熵损失对模型进行训练。在一个包含600个测试样本的小数据集上,它们的准确率达到98.6%。

(Pascanu et al.2015)提出了两个阶段的方法,即特征学习阶段和分类阶段。在第一阶段,他们使用RNN根据之前的API调用序列预测下一个可能的API调用。在分类阶段,他们冻结RNN,并将输出输入最大池层,以转换特征进行分类。在75000个样本的数据集上,它们的召回率达到71.71%,假阳性率为0.1%。

(Kolosnjaji et al.2016)提出了一种将CNN与LSTM相结合的方法。他们的方法堆叠两个CNN层,每个CNN层使用一个3大小的内核来模拟3-gram方法。在CNN之后,附加一个具有100大小隐藏向量的LSTM来处理时间序列。以前的论文通常忽略了论点。

(Huang和Stokes 2016)使用了一种包含三个部分的特征表示,即参数中存在可运行代码、API调用名称与其中一个参数的组合(手动选择)以及3-gram的API调用序列。通过随机投影(random projection),此特征表示从50000减少到4000。(Agrawal et al.2018)提出了一种特征表示方法,该方法使用来自API调用名称的一个one-hot和参数字符串的前N个频繁N-gram。该模型使用了几个堆叠的LSTM,其性能优于(Kolosnjaji等人,2016)。他们还声称,多个LSTM不能提高性能。

三、系统框架

为了收集运行时API调用,我们实现了图1所示的系统。该系统由体育档案采集、行为信息采集、特征提取和模型训练三部分组成。

image-20220526165948643

3.1 PE文件收集

我们系统的工作流程从可移植可执行文件(PE)集合开始。在本文中,我们重点检测Windows系统中可移植可执行文件(PE)格式的恶意软件,这是最流行的恶意软件文件格式(AV-TEST 2017)。此收集部分已由新加坡SecureAge Technology本地反病毒公司实施。此外,该公司还维护了一个包含12个防病毒引擎的平台,用于对PE文件进行分类。对分类结果进行聚合,以获得每个PE文件的标签,用于模型培训。一旦模型经过培训,它将作为第13个防病毒引擎添加到平台中。收集之后,将维护一个执行队列,以提交PE文件以供执行。它监视存储使用情况并决定是否执行更多PE文件。

3.2 行为信息收集

https://cuckoosandbox.org/

json在线解析:http://www.jsons.cn/jsoncheck/

布谷鸟是一款开源软件,用于运行PE文件和收集执行日志。它在虚拟机内执行PE文件,并使用API挂钩监视API调用跟踪(即行为信息)。此外,布谷鸟模拟了一些用户行为,例如单击按钮、键入一些文本等。在我们的系统中,我们在每台服务器上维护了数十台虚拟机。所有虚拟机都安装了64位Windows 7系统和一些日常使用的软件。我们利用虚拟机的快照功能在执行后回滚它。所有生成的日志都存储在本地的布谷鸟服务器上

3.3 特征提取和模型训练

沙盒生成的执行日志包含PE文件的详细运行时信息,PE文件的大小从几KB到数百GB不等。我们设计了一个可以并行运行的特征工程解决方案以有效地从原始执行日志中提取特征。提取特征后,我们在带有GPU的模型服务器上训练我们的深度学习模型,以进行恶意软件分类。

4、方法

#### cuckoo json:

  • behavior

    • summary

      • file_recreated
      • file_failed
      • dll_loaded
      • guid
      • file_opened
      • file_created
      • file_written
    • generic

      • process_path: 进程启动路径
      • process_name: 进程执行程序名
      • pid: 进程id
      • first_seen: 进程启动时间戳
      • ppid: 父进程id
    • apistatsAPI名称的调用次数信息

    • processes

      • command_line

      • calls

        { "api": "NtCreateFile", "category": "file", "return_value": 0, "stacktrace": [ ], "flags": { "desired_access": "FILE_READ_ATTRIBUTES|READ_CONTROL|SYNCHRONIZE", "share_access": "FILE_SHARE_READ", "file_attributes": "", "create_disposition": "FILE_OPEN", "create_options": "FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT", "status_info": "FILE_OPENED" }, "arguments": { "desired_access": "0x00120080", "share_access": 1, "filepath_r": "\??\C:\Users\xn\AppData\Local\Temp\0e823db8b1beaca62207e2a82a9cd691c7af44cd14b876cb9f823f29750dd008", "filepath": "C:\Users\xn\AppData\Local\Temp\0e823db8b1beaca62207e2a82a9cd691c7af44cd14b876cb9f823f29750dd008", "file_attributes": 0, "create_disposition": 1, "file_handle": "0x000004ac", "status_info": 1, "create_options": 96 }, "tid": 3564, "status": 1, "time": 1622640835.384851 },

      • modules: 样本运行时调用的系统文件信息, 包括被调用文件名/路径/基地址及其大小

      • time: 运行时间

    • processtree

      • children: 子进程列表

4.1 特征工程

  • FeatureHasher: https://scikit-learn.org/dev/modules/generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher

  • Feature Hashing for Large Scale Multitask Learning (2013)

以前的大多数工作(Qiao et al.2013;Pascanu et al.2015;Kolosnjaji et al.2016)都忽略了API调用的参数,只考虑了API名称和类别。因此,一些重要(鉴别)信息丢失(Agrawal et al.2018)。例如,如果忽略文件路径参数,则两个写操作(API调用)的功能将完全相同。但是,当目标文件由程序本身创建时,写入操作可能是良性的,但如果目标文件是系统文件,则写入操作可能是恶意的。一些考虑到论点的著作(Trinius et al.2009;Agrawal et al.2018;Huang and Stokes 2016)未能利用不同类型论点的异质信息。我们建议采用(Weinberger et al.2009)中的哈希方法,分别对API的名称、类别和参数进行编码

如下表所示,我们的特征表示由不同类型的信息组成。API名称有8维,API类别有4维。API参数部分有90个维,16个用于整数参数,74个用于字符串参数。对于字符串参数,将处理几种特定类型的字符串(文件路径、DLL等)。此外,从所可打印字符串中提取了10个统计特征。将所有这些特征串联起来,形成102维特征向量

image-20220526170451620

  • API名称和类别

单词拆分?fastext?删除循环调用?

布谷鸟沙盒总共跟踪312个API调用,它们属于17个类别。每个API名称由多个单词组成,每个单词的第一个字母大写,例如“GetFileSize”。我们将API名称拆分为单词,然后应用下面的特性哈希技巧处理这些单词。对于API类别,由于该类别通常是单个单词,例如“network”,我们将该单词拆分为字符并应用特征哈希技巧。此外,我们计算API名称、类别和参数的MD5值,以删除任何连续重复的API调用

我们使用方程1中的特征哈希(Weinberger et al.2009)将字符串序列编码为固定长度的向量。随机变量x表示元素序列,其中每个元素要么是字符串,要么是字符。M表示维度数量,即8表示API名称,4表示API类别。第i个bin的值通过以下公式计算:

image-20220526172933876

其中,h是将元素(例如xj)映射到自然数m的哈希函数∈ {1,…,M}作为bin索引;ξ是另一个将元素映射到{+-1} 。也就是说,对于x的每个元素xj,其bin索引h(xj)为i,我们将ξ(xj)添加到bin中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class APIName(FeatureType):
''' api_name hash info '''
name = 'api_name'
dim = 8
def __init__(self):
super(FeatureType, self).__init__()
self._name = re.compile('^[a-z]+|[A-Z][^A-Z]*')
def raw_features(self, input_dict):
"""
input_dict: string
"""
tmp = self._name.findall(input_dict)
hasher = FeatureHasher(self.dim, input_type="string").transform([tmp]).toarray()[0]
return hasher
def process_raw_features(self, raw_obj):
return raw_obj

class APICategory(FeatureType):
''' api_category hash info '''
name = 'api_category'
dim = 4
def __init__(self):
super(FeatureType, self).__init__()
def raw_features(self, input_dict):
hasher = FeatureHasher(self.dim, input_type="string").transform([input_dict]).toarray()[0]
return hasher
def process_raw_features(self, raw_obj):
return raw_obj
  • API参数

image-20230319160222991

至于API参数,只有两种类型的值,即整数字符串。整数的单个值没有意义。需要参数名称才能获取值的含义。相同的整数值可能表示具有不同参数名称的完全不同语义。例如,名为“port”的数字22与名为“size”的数字不同。我们采用前面的特征哈希方法对整数的参数名称及其值进行编码,如等式2所示。我们使用参数名称来定位哈希容器。特别是,我们使用名称哈希值为i的所有参数通过求和更新第i个bin。对于每个这样的参数,我们计算对bin的贡献,如等式2所示,其中ξ(\(x_{name_j}\))是参数名称上的哈希函数,\(x_{value_j}\)是整数参数的值。由于整数可能在某个范围内稀疏分布,因此我们使用对数对值进行规格化,以压缩该范围。

image-20220526174316254

其中,h和ξ是与等式1中相同的哈希函数。对于API参数字符串,它们的值比整数更复杂。某些以“0x”开头的字符串包含某些对象的地址。还有一些可能包含文件路径、IP地址、URL或纯文本。此外,一些API参数甚至可能包含整个文件的内容。字符串的多样性使得处理它们具有挑战性。根据之前的工作(Tian et al.2010;Islam et al.2010;2013;Ahmed et al.2009),最重要的字符串是关于文件路径、DLL、注册表项、URL和IP地址的值。因此,我们使用方程1中的特征哈希方法【string】来提取这些字符串的特征。

为了捕获字符串中包含的层次信息,我们将整个字符串解析为几个子字符串,并分别对它们进行处理。例如,我们使用“C:\”来标识文件路径。所有这些子串都通过方程1进行处理

Path对于像“C:\a\b\C”这样的路径,将生成四个子字符串,即“C:”、“C:\a”、“C:\a\b”和“C:\a\b\C”。

dll:以“.dll”结尾的字符串

注册表:项通常以“HKEY”开头

IP:由点分隔的四个数字(范围从0到255)组成的字符串

URL:我们仅从URL的主机名生成子字符串。例如,对于“https://security.ai.cs.org/,将生成以下子字符串“org”、“cs.org”、“ai.cs.org”和“security.ai.cs.org”。

DLL、注册表项和IP也采用相同的处理方法dll是以“.dll”结尾的字符串。注册表项通常以“HKEY”开头。IP是由点分隔的四个数字(范围从0到255)组成的字符串。URL略有不同,我们仅从URL的主机名生成子字符串。例如,对于“https://security.ai.cs.org/,将生成以下子字符串“org”、“cs.org”、“ai.cs.org”和“security.ai.cs.org”。这样,域和组织信息将对该功能贡献更多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class PRUIInfo(FeatureType):
''' Path, Registry, Urls, IPs hash info '''
name = 'prui'
dim = 16 + 8 + 12 + 16 + 12

def __init__(self):
super(FeatureType, self).__init__()
self._paths = re.compile('^c:\\\\', re.IGNORECASE)
self._dlls = re.compile('.+\.dll$', re.IGNORECASE)
self._urls = re.compile('^https?://(.+?)[/|\s|:]', re.IGNORECASE)
self._registry = re.compile('^HKEY_')
self._ips = re.compile('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')

def raw_features(self, input_dict):
paths = np.zeros((16,), dtype=np.float32)
dlls = np.zeros((8,), dtype=np.float32)
registry = np.zeros((12,), dtype=np.float32)
urls = np.zeros((16,), dtype=np.float32)
ips = np.zeros((12,), dtype=np.float32)
for str_name, str_value in input_dict.items():
if self._dlls.match(str_value):
tmp = re.split('//|\\\\|\.', str_value)[:-1]
tmp = ['\\'.join(tmp[:i]) for i in range(1, len(tmp) + 1)]
dlls += FeatureHasher(8, input_type="string").transform([tmp]).toarray()[0]
if self._paths.match(str_value):
tmp = re.split('//|\\\\|\.', str_value)[:-1]
tmp = ['\\'.join(tmp[:i]) for i in range(1, len(tmp) + 1)]
paths += FeatureHasher(16, input_type="string").transform([tmp]).toarray()[0]
elif self._registry.match(str_value):
tmp = str_value.split('\\')[:6]
tmp = ['\\'.join(tmp[:i]) for i in range(1, len(tmp) + 1)]
registry += FeatureHasher(12, input_type="string").transform([tmp]).toarray()[0]
elif self._urls.match(str_value):
tmp = self._urls.split(str_value + "/")[1]
tmp = tmp.split('.')[::-1]
tmp = ['.'.join(tmp[:i][::-1]) for i in range(1, len(tmp) + 1)]
urls += FeatureHasher(16, input_type="string").transform([tmp]).toarray()[0]
elif self._ips.match(str_value):
tmp = str_value.split('.')
tmp = ['.'.join(tmp[:i]) for i in range(1, len(tmp) + 1)]
ips += FeatureHasher(12, input_type="string").transform([tmp]).toarray()[0]
return np.hstack([paths, dlls, registry, urls, ips]).astype(np.float32)

def process_raw_features(self, raw_obj):
return raw_obj

统计信息

对于许多其他类型的字符串,根据之前的工作(Ahmed et al.2009;Tian et al.2010;Islam et al.2010),我们从所有可打印字符串中提取统计信息。可打印字符串由0x20到0x7f的字符组成。因此,包括所有路径、注册表项、URL、IP和其他一些可打印字符串

  • 以“MZ”开头的一类字符串通常是包含整个PE文件的缓冲区,通常出现在恶意PE文件中,如线程注入(Liu et al.2011)。因此,我们额外计算“MZ”字符串的出现次数。
  • 10维向量用于记录字符串的数量、平均长度、字符数、所有可打印字符串的字符熵,以及路径、DLL、URL、注册表项、IP和“MZ”字符串的数量。我们没有处理其他参数,如虚拟地址、结构等,与上述类型的参数相比,这些参数相对不太重要。

虽然所提出的特征工程方法很容易使用额外的bins应用于它们,但我们期待着进行更有针对性的研究来探索这些论点。

4.2 模型结构

我们提出了一种深度神经网络架构,它利用了所提出的特征工程步骤中的特征。图2概述了我们提出的深度学习模型。

image-20220526184024769

  • 输入模块

在特征工程之后,我们得到大小为(N,d)的输入向量,其中N是API调用序列的长度d(102位)是每个提取的API特征的维数。我们首先通过批量规范化层(BN)对输入进行规范化(Ioffe和Szegedy 2015)。该批次标准化层通过减去批次平均值并除以批次标准偏差来标准化输入值。它保证了特征向量的某些维数不会太大而影响训练;实验验证了该方法的正则化效果。

  • 门控CNNs模块

输入模块后应用了多个门控-CNN(Dauphin et al.2017)。门控-CNN允许选择重要和相关的信息,使其在语言任务上与循环模型相比,但消耗更少的资源和时间。对于每个选通的CNN,输入分别馈入两个卷积层。设XA表示第一卷积层的输出,XB表示第二卷积层的输出;它们由image-20220526184352710组成,它涉及到元素乘法运算。这里,σ是sigmoid函数。σ(XB)被视为控制从XA传递到模型中下一层的信息的门按照(Shen et al.2014)中的想法,一维卷积滤波器被用作n-gram检测器。如图2所示,我们使用两个选通CNN,其过滤器大小分别为2和3。所有卷积层的滤波器个数为128,步长为1。

  • BI-LSTM模块

来自门CNN的所有输出连接在一起。对这些输出应用批处理规范化层,以减少过拟合。我们使用双向LSTM来学习序列模式每个LSTM的单元数为100。LSTM是一种递归神经网络架构,其中设计了几个门来控制信息传输状态,以便能够捕获长期上下文信息(Pichotta和Mooney 2016)。双向LSTM是两个LSTM叠加在一起,但方向输入不同。与单向LSTM相比,双向LSTM能够同时整合过去和未来状态的信息。双向LSTM在恶意软件检测方面已被证明是有效的(Agrawal et al.2018)。

  • 分类模块

在Bi LSTM模块中学习序列模式后,应用全局最大池层从隐藏向量中提取抽象特征。全局最大池层不是使用Bi LSTM的最终激活,而是依赖于整个序列中观察到的每个信号,这有助于保留整个序列中学习到的相关信息。在全局最大池层之后,我们使用单元数为64的密集层将中间向量的维数减少到64。将ReLU激活应用于该致密层。然后,我们使用速率为0.5的衰减层(dropout)来减少过度拟合。最后,单位数为1的致密层将维数减少到1。在致密层之后附加一个Sigmoid激活以输出概率。我们的模型使用与每个输入向量相关的标签进行监督。为了测量用于训练模型的损失。

image-20220526185129696

此外,我们采用的优化方法是Adam,学习率为0.001。

Dynamic Malware Analysis - 代码结构

model.py

  • ClassifyGenerator: Generates data for Keras
  • Model: 模型结构定义、模型训练
  • Cuckoo2DMDS:
  • DMDS