Background
Representational Model
在深度学习领域,"Representation Learning"是一种学习数据表示的方法,目的是对复杂的原始数据化繁为简,把原始数据的无效或冗余信息剔除,把有效信息进行提炼,形成特征(feature)。
Motivation
随着Android应用的数量迅速增长,以及相关问题(如生产力和安全问题)的快速增加,有必要有效地解决Android生态系统的问题;例如,一种解决多个问题的方案。然而,大多数最先进的方法都是针对特定问题建立模型,如恶意软件检测(例如Drebin [27] 和 DexRay [28])或恶意代码定位(例如MKL-Droid [13] 和 Droidetec [11]),或软件缺陷预测(例如smali2vec [14] 和 SLDeep [29])
与其为每个问题设计一个单独的解决方案,不如探索一种可能性,即拥有一个能够捕捉和表示应用程序代码的相关特征和属性的通用模型,这个模型可以用于多种任务。一些现有的表示模型可以推广到多种问题,但是它们要么针对源代码的低粒度(例如CodeBERT [15]),要么针对整个Android应用程序(例如apk2vec [16])。CodeBERT需要原生源代码(即用编程语言编写的代码),而这对于Android应用程序来说往往是不可用的。虽然可以将Java代码反编译,但这并不总是完整的,而且经常与真实的源代码有很大差异。此外,CodeBERT的设计也没有克服Android应用程序的输入元素数量(BERT为512)的限制(即应用程序通常包含超过百万个令牌)。
此外,大多数现有的Android表示方法都针对整个应用程序级别(例如apk2vec [16]),这使得难以探索问题的细节。因此,如果一个表示模型可以处理应用程序的字节码,并支持细粒度级别的多种任务,那将是一个重大的进步。我们提出的方法DexBERT不需要源代码,并且经过验证可以适应类级别的任务。同时,我们设计了一种聚合方法来克服BERT类模型中512个输入元素的限制。对于DexBERT用户来说,他们不需要再次预训练,只需要使用我们提供的模型来为他们自己的APK生成特征。然后,他们可以做任何他们想做的类级别任务。因此,它的可重用性可以避免为不同任务训练单独的模型,从而节省大量时间和精力。
Approach
Model Overview
DexBERT专注于从Android应用程序的Dalvik字节码中提取特征,并针对细粒度的Android任务(即类级别)。我们的方法与apk2vec [16](一种基于静态分析的多视图图嵌入框架,用于应用级别的Android任务)和CodeBERT(一种用于编程语言(PL)和自然语言(NL)任务的双模态预训练模型)明显不同。
具体来说,DexBERT将从Dalvik字节码反汇编得到的Smali代码作为输入,使用Bert学习提取相应的embeddings。由于DexBERT支持各种类级别的任务(而原始的BERT仅限于相对较小的输入),因此需要将得到的embeddings聚合起来形成class Embedding并用作后续的任务。
在第III-B1节介绍了DexBERT的流程。我们在第III-B2节介绍了DexBERT预训练的机制。在第III-B3节,我们介绍了自动编码器,它的目的是在保留关键信息的同时降低学习表示的维度。
DexBert
Smali代码是从Dalvik字节码反汇编得到的一系列指令,是一种汇编语言。类似于原始的BERT,我们在多个预训练任务上预训练我们的模型,以迫使DexBERT捕获可以用于各种下游任务的通用表示。
具体来说,关于每个Smali指令中的每个class,作者将其视为一个文本片段,能够创建指令对作为输入序列。类似于BERT,Bert的输入包含一个句子对 (句子 A 和句子 B),也可以是单个句子,但是要通过[SEP]分隔。
在每对中,两条指令用一个保留的标记[SEP]分隔,而且随机选择的几个标记(或“单词”)被遮盖。对于遮盖语言模型,原始BERT的两个预训练任务之一,目标是正确地预测被遮盖的标记。第二个原始BERT预训练任务,下一句预测,这里变成了下一条指令预测,利用了指令对。本质上,这个任务的目标是预测,在给定一对指令时,第二条指令是否跟在第一条指令后面。
在这里,DexBert的论文模型同样用到了BERT文章作者提出的两个预训练任务:Masked LM和Next Sentence Prediction, 借用一下https://zhuanlan.zhihu.com/p/318495113给出的关于Bert的图表。
Pre-training
预训练对于帮助DexBERT学习生成有意义的嵌入是非常重要的。为了确保学习到的嵌入具有通用性,预训练应该同时在多个任务上进行。如前所述,作者采用并改进了原始BERT的两个预训练任务:①掩码语言模型(即掩码词预测)和②下一句预测作为主要的预训练任务。
预训练对于帮助DexBERT学习生成有意义的嵌入是非常重要的。为了确保学习到的嵌入具有通用性,预训练应该同时在多个任务上进行。如前所述,我们采用并改进了原始BERT的两个预训练任务:①掩码语言模型(即掩码词预测)和②下一句预测作为主要的预训练任务。
Masked LM的任务描述为:给定一句话,随机抹去这句话中的一个或几个词,要求根据剩余词汇预测被抹去的几个词分别是什么,如下图所示。(可以类比一下完型填空)
NextSentence Prediction任务描述为:给定一篇文章中的两句话,判断第二句话在文本中是否紧跟在第一句话之后,可以理解为段落重排序。
BERT模型通过对Masked LM任务和Next Sentence Prediction任务进行联合4训练,使模型输出的每个字/词的向量表示都能尽可能全面、准确地刻画输入文本(单句或语句对)的整体信息,为后续的微调任务提供更好的模型参数初始值。
在每次预训练迭代中,指令序列作为输入送入BERT模型,该模型生成相应的序列嵌入(如图2左框所示)。
然后,序列嵌入被作为预训练任务的输入。每个任务都是一个简单的神经网络,只有一个全连接层。如下图所示,通过将每个任务头的输出与自动生成的真值(即随机掩码的词或二元标签,表示第二个语句是否确实跟在第一个语句后面)进行比较,计算损失值。根据反向传播算法[30],调整神经元之间连接的模型权重,以最小化总损失值(即所有预训练任务的损失值之和)。注意,预训练任务只是为了帮助BERT模型学习输入序列的有意义的特征,在实际应用中没有什么用处。
Auto-Encoder
以下文段的翻译如下:尽管这两个预训练任务在Smali指令上表现良好,但每个序列生成的表示的维数(即512×768,其定义为每个输入序列N中的令牌数和学习的嵌入向量H的维数的乘积)相当大。由于Smali类中通常有数百或数千个需要嵌入的语句,因此在部署到下游任务之前应该减少学习嵌入的维数,同时保留其关键信息。在BERT-like模型的常见实践中,通常使用学习嵌入的第一个状态向量(大小为768)来实现此目的。在这种情况下,作者添加了第三个预训练任务,即自动编码器,其目标是找到更小、更高效的表示。
一个更小的representation是必要的,主要是因为APKs包含的token数量比典型的文本文档和代码文件要多得多。我们提供了一个关于三种不同数据格式(文本文档(Paired CMU Book Summary [31]),代码文件(Devign [32])和APKs(DexRay [28])的token序列长度的比较分析,每个数据集中的BERT令牌数量用[Mean]±[Deviation]表示。具体来说,Paired CMU Book Summary有1148.62±933.97个令牌,Devign数据集包含615.46±41 917.54个roken,而DexRay数据集包含相当多的929.39K±11.50M个token。这些APKs的token数量差异很大,因此需要努力为给定的Smali指令令牌序列实现尽可能紧凑的embedding。
自动编码器[33]是一种人工神经网络,可以学习无标签数据的高效小尺寸嵌入。它通常用于通过训练网络忽略“噪声”来进行维数降低。自动编码器的基本结构通常由一个用于嵌入学习的编码器和一个用于输入重建的解码器组成(如图2的左框所示)。在训练过程中,通过尝试从嵌入中重建输入来验证和改进嵌入,从而试图构建输入的最小完整表示。
我们的方法中,编码器由两个全连接层组成,分别有512和128个神经元。对称地,解码器由两个全连接层组成,分别有128和512个神经元。从BERT中学习的序列嵌入(大小为512×768)既是编码器的输入,也是预训练过程中解码器的输出目标。经过对比实验,我们选择了大小为128的隐藏嵌入作为原始指令序列的最终表示。我们在第VI-A节中提供了不同嵌入大小的分析。与原始BERT嵌入相比,最终序列嵌入的维数减小了3072倍,从512×768变为128。因此,在图2中,由编码器产生的指令序列1的嵌入向量的大小是128。
=》Auto-Encoder的作用
自编码器是一种特殊的神经网络架构,他的输入和输出是架构是相同的。自编码器是通过无监督的方式来训练来获取输入数据在较低维度的表达。在神经网络的后段,这些低纬度的信息表达再被重构回高维的数据表达。
Class-level Prediction Model
为了验证学习到的DexBERT表示的有效性,我们将其应用于三个类级别的Android分析任务。为了执行这些类级别的任务,我们需要每个类的高效表示,因此我们需要一种方法将每个类的指令序列的嵌入聚合成一个单一的嵌入。我们在第III-C1节中介绍了这种方法。然后,我们在第III-C2节中介绍了预测模型的细节。
1) Instruction Embedding的聚合
从DexBERT学习到的表示是针对指令序列的。通常,每个Smali类由许多方法组成,每个方法包含一定数量(通常很多)的语句。每个类中的序列向量数量是不确定的,而类级别预测模型(神经网络)的输入形状应该是固定的。具体来说,在每个类中,有许多大小为128的序列嵌入向量,它们需要被合并成一个单一的向量。因此,需要进行嵌入聚合来获得最终的类级别表示。
我们解决长指令序列问题的主要原因有三个,即将Smali类分割成片段,并将学习到的片段嵌入聚合成一个类嵌入。首先,Smali指令是在Android运行时环境中执行特定操作的单独命令。¹[1]尽管它们经常以序列的形式出现,但每个Smali指令基本上是独立运行的,不一定具有自然语言句子中单词之间的相互依赖性。其次,聚合指令嵌入的类表示保留了类的整体结构和功能的感觉,同时具有上下文感知性。最后,虽然分割长序列可能会造成一些上下文的丢失,但我们认为在计算效率和潜在的上下文损失之间的权衡是合理的。为了给这种权衡提供一个量化的度量,让我们考虑一下所需的GPU内存。对于BERT模型,将输入长度限制加倍将需要初始GPU内存的四倍,这是大多数标准设备无法满足的需求,尤其是对于更长的序列。然而,如果我们对采用的数据集中的长序列进行平均2.69次分割,就可以避免高昂的内存成本而不会造成显著的性能损失,正如我们的实验所示。
虽然我们可以利用另一步表示学习来设计一个策略来聚合多个表示,但我们选择了一种计算成本较低的方法。为了适应不同Smali类中向量数量的变化,如图3所示,我们提出了一种将这些大小为128的序列嵌入向量聚合成一个大小为128的单一向量的方法,即通过执行简单的逐元素平均、逐元素加法或随机选择。另一种我们研究的方法是计算机视觉中向量重塑的一般方法:连接和双线性调整。具体来说,我们首先将嵌入向量连接成一个长向量,然后用双线性插值算法[34]对其进行调整。我们在第V-E节中研究了这四种方法,并表明这些简单的方法是有效的。
双线性插值是用原图像中4(2*2)个点计算新图像中1个点,效果略逊于双三次插值,速度比双三次插值快,属于一种平衡美,在很多框架中属于默认算法。
2)Prediction Model
如图3右侧框所示,经过嵌入聚合后,我们最终得到了每个Smali类的一个嵌入向量。最后一步是将学习到的嵌入应用到下游任务中。通常,这可以通过将嵌入输入到另一个可以针对特定任务进行训练的独立神经网络来完成。在原始的BERT中,他们只在每个下游任务的预训练模型后面添加了一个额外的层。
在我们的方法中,我们设计了一个简单的模型结构,只有三个全连接层的神经网络作为任务特定的模型,并且在针对特定任务进行调整时冻结了预训练的DexBERT模型的参数。通过只调整任务特定模型的参数,下游任务的训练计算成本显著降低。具体来说,任务特定模型的参数数量是10.4K,与预训练的DexBERT模型的459.35M相比几乎可以忽略不计。
任务特定模型的输入是类嵌入的聚合向量,如图3所示。针对恶意代码定位的任务特定模型预测给定类是否包含恶意代码。同样地,对于缺陷检测,任务特定模型预测给定类是否包含缺陷代码。对于组件类型分类,任务特定模型预测给定类属于哪种组件类型。每个任务特定设置的细节在第IV-C节中介绍。
Study Design
Dataset
1)Dataset for Pre-training
我们的目标是为各种Android分析任务提供一个通用的表示。为了获得一个能够反映Android应用多样性的有代表性的样本,我们选择利用一个最近的Android恶意软件检测工作的数据集。从用于评估DexRay [28]的数据集中随机选择了一千个应用——恶意或良性——,该工作收集了超过158000个来自AndroZoo数据集[35]的应用。为了尽可能多地包含多样性,而不让指令总数爆炸,我们进行了类去重。去除重复类后,我们选择的APK结果产生了超过3500万条Smali指令,从中我们获得了5.56亿个token。这与原始BERT使用的预训练数据集之一BooksCorpus [36]的规模相当,它包含了8亿个token。
尽管DexBERT的预训练数据集比原始BERT小,但它的充分性得到了两个因素的支持。首先,Smali作为一种汇编语言,具有比自然语言和高级编程语言更简单的结构和更小的token集合,这意味着较小的数据集就足以捕捉其基本特征。其次,数据集的效率是基于DexBERT在下游任务中的表现来评估的,这些任务使用的APK来自于与预训练数据集不同的来源。DexBERT在这些任务中相对于基线模型的优越性能证实了预训练数据集的充分性。
我们根据数据集中的Smali指令生成了一个包含10 000个token的WordPiece [37]词汇表,这只有原始BERT词汇表的三分之一大小。WordPiece模型采用了一种子词分词方法来管理庞大的词汇表和处理罕见和未知的单词。它将单词分解为更小的单位,有效地解决了未登录词的问题。
子词分词是什么=》subword tokenization method
WordPiece是一种子词分词算法,用于将单词分解为更小的子单元,以有效地处理罕见和未知的单词。它是BERT模型中用于分词的算法之一。WordPiece模型使用语言模型来挑选子词,选择能够提升语言模型概率最大的相邻子词加入词表。与BPE算法类似,WordPiece算法也是每次从词表中选出两个子词合并成新的子词。与BPE的最大区别在于,如何选择两个子词进行合并:BPE选择频数最高的相邻子词合并,而WordPiece选择能够提升语言模型概率最大的相邻子词加入词表。
2)Dataset for Malicious Code Localization 恶意代码定位数据集
恶意代码定位是一种分析Android应用中的恶意代码的位置和功能的任务。为了评估不同的恶意代码定位方法,我们需要一个包含标注的恶意代码片段的数据集。我们从AndroZoo数据集[35]中收集了1000个恶意应用和1000个良性应用,使用DexRay[28]工具对它们进行反编译,得到Smali指令。然后,我们使用一个基于深度学习的恶意代码检测模型[29]对每个Smali指令进行二分类,得到一个0-1序列,表示每个指令是否属于恶意代码。我们将这个序列作为数据集的标签,提供给恶意代码定位方法使用。我们的数据集包含了2亿多条Smali指令和相应的标签,覆盖了多种类型的恶意代码,如广告、窃取信息、远程控制等。我们的数据集可以用于评估和改进恶意代码定位方法的性能和鲁棒性。
RQ2涉及恶意代码定位,即查找给定恶意软件的哪些部分包含恶意代码。至少有两项现有工作已经针对Android恶意软件解决了这个具有挑战性的问题,并获得了带有地面真实标签的合适数据集。在Mystique [38]中,Meng等人构建了一个包含10,000个自动生成的恶意软件的数据集,每个类别都有恶意/良性标签。然而,这些生成的APK中几乎所有的代码都是恶意的或来自常用库(如android.support),因此可能不代表现有应用程序的多样性,也不代表Android应用程序的多样性。最近,在MKLDroid中,Narayanan等人从Mystique数据集中随机选择了3000个应用程序,并将恶意部分附加到来自Google Play的现有真实良性应用程序中,从而产生了一个名为MYST的数据集。尽管离真实世界场景还有一段距离,但MYST数据集中重新打包的恶意软件包含恶意和良性类别,可以支持类级别的恶意代码定位任务。因此,我们决定依赖MYST数据集来进行与RQ2相关的实验。请注意,据我们所知,没有针对Android恶意代码定位任务存在完全标记的真实世界恶意软件数据集。请注意,在我们的工作中,我们选择MKLDroid作为基准工作,使我们能够直接将DexBERT与MKLDroid进行比较。
尽管获取标记的恶意软件存在挑战,但我们仍然决心评估DexBERT在真实场景中的性能。最终,我们成功地构建了一个数据集,虽然不是很广泛,但包含了标记的真实世界恶意类,从而扩大了我们的评估范围。具体来说,我们在Difuzer [39]数据集中找到了46个应用程序,其中一个特定的恶意行为,即逻辑炸弹,已经被手动标记了位置。这使得我们能够获得恶意类的标签,并从而评估DexBERT在真实世界应用程序中定位恶意代码的能力。此外,Difuzer的作者还提供了他们后续工作中的更多应用程序,我们成功地下载并处理了88个apk。
由于Difuzer数据集中的每个APK只有一个被标记为包含逻辑炸弹的类,而其他类的恶意或良性性质是未知的,所以我们只能利用这88个真实世界APK中的88个恶意类进行我们的扩展评估。为了促进更全面的评估过程,我们构建了一个包含额外APK的数据集。训练集包括三个来源:50个带有逻辑炸弹的Difuzer APK,50个来自DexRay数据集[28]的良性APK,以及100个来自MYST数据集的APK,以增加数据集的大小。请注意,我们随机选择了一部分良性类,以防止数据不平衡,因为初始的良性类数量远大于恶意类数量。结果,我们获得了1929个良性类和425个恶意类,其中包括50个来自Difuzer APK的类,用于微调分类器。评估集的目标是在真实世界APK上测试DexBERT,它仅由来自Difuzer的剩余38个带有逻辑炸弹的APK和来自DexRay的50个良性APK组成。我们最终得到了95个良性类(每个良性apk几乎有两个)和38个包含逻辑炸弹的恶意类。请注意,所有上述设计都旨在使构建的数据适合深度学习模型训练,同时确保训练集和评估集之间没有重叠。
3)应用缺陷检测的数据集
:作为另一个重要的类级别的安卓分析任务,应用缺陷检测是RQ3的主题。Dong等人提出了smali2vec,一种基于深度神经网络的方法来检测应用缺陷,并发布了一个包含超过92K个Smali类文件的数据集,这些文件是从十个安卓应用项目的五十多个版本中收集的。¹[1]为了方便标注,他们根据三个项目选择标准从GitHub上收集了这些APK:1)版本数大于20;2)包大小大于500 KB;3)提交和贡献者数量众多。有缺陷的Smali文件被定位并用Checkmarx [40]标注,这是一个广泛使用的商业静态源代码分析工具。²[2]最后,数据集中的每个Smali类都有一个标签,表示它是有缺陷还是无缺陷。我们选择smali2vec作为我们应用缺陷检测的数据集,以便与他们专门为缺陷检测构建的smali2vec方法进行比较。
4)用于组件类型分类的数据集
为了进一步评估 DexBERT 的通用性,我们引入了一个第三个类级任务,称为组件类型分类。这个任务与前两个任务有明显的不同,旨在全面评估 DexBERT 在不同场景下的适用性。在 Android 框架中,存在四种主要的组件,即活动、服务、广播接收器和内容提供器。 Activities, Services, Broadcast Receivers, and Content Providers。这些是 Android 应用程序的基本构建块,并在应用程序的清单文件(AndroidManifest.xml)中声明。因此,我们可以很容易地获得这四种类型的组件类的标签,并为这个任务制定一个高质量的数据集。请注意,这个任务只是为了展示 DexBERT 的通用性;它是由于这个任务与其他两个下游任务的性质不同以及获得真实数据的便捷性和速度而选择的。我们从 AndroZoo 仓库 [35] 随机选择了 1000 个真实的 APK,从中提取了 3406 个具有准确标签的组件类。我们使用了 75% 的数据进行训练,剩下的 25% 用于测试。
Empirical Setup
1)预训练 Pre-training
基于典型的 BERT 设计,我们在一定程度上简化了 DexBERT 的模型结构,以降低计算成本。¹[1]事实上,虽然位置感知前馈网络中的中间层维度最初被定义为 H × 4,其中 H 默认设置为 768,如第 III-B3 节所述,我们将这个维度减小到 H × 3,即从 3072 减小到 2304。多头注意力层中的隐藏层和头的数量被设置为 8 而不是 12。通过这些简化,模型的浮点运算次数(FLOPs,表示模型的计算复杂度)减少了 43.9%,从 44.05G 减少到 24.72G。同时,模型参数的数量仅减少了 7.7%,从 497.45M 减少到 459.35M。因此,我们在降低计算成本的同时,尽可能地保留了模型参数的数量,目的是尽可能地保留模型的学习能力。
批量大小设置为 72,学习率设置为 1e-4。参考我们利用的实现2,我们选择了 Adam 优化器 [41]。我们对遮蔽词预测任务和下一句预测任务采用交叉熵损失函数3,对自编码器任务采用均方误差(MSE)损失函数4。特别地,MSE 损失是一个衡量输入 x 和目标 y 中每个元素之间平方 L2 范数的标准。因此,这个任务的损失值也可以被视为自编码器任务的评估指标。
DexBERT 在 5.56 亿个 token 上进行了 40 个 epoch 的预训练,花费了大约 10 天的时间,使用了 2 个 Tesla V100 GPU(每个有 32G 内存)。但是,需要注意的是,DexBERT 的用户不需要从头开始预训练模型。他们可以直接使用我们提供的预训练模型来进行自己的 Android 分析任务。
2)恶意代码定位 Malicious Code Localization
如上所述,恶意代码定位是一个困难且未被充分探索的问题。因此,目前只有少数被广泛认可的方法和基准数据集可用。据我们所知,Narayanan等人提供了第一个标记良好的数据集,该数据集接近实际的实际需求,以评估他们的多视图上下文感知方法MKLDroid [13]用于恶意代码定位。
为了公平地与这个基准工作进行比较,我们采用了相同的验证策略,即使用2000个APK进行微调,使用剩余的1000个APK进行评估。我们使用3折交叉验证来确保结果的可靠性。预测模型由3个全连接层组成,分别有128、64和32个神经元。输出层由两个神经元组成,用于预测一个类是恶意的还是良性的概率。我们利用RQ5中找到的最佳聚合方法(即逐元素加法)。在对这个任务进行微调时,我们使用交叉熵损失函数和Adam优化器。批量大小为256,我们训练预测模型40个周期。对于评估指标,我们采用精度、召回率、假阳性率(FPR)和假阴性率(FNR),与基准工作MKLDroid相同,以便于比较。我们还报告了F1-分数作为总体指标。
3)应用缺陷检测 App Defect Detection
与恶意代码定位类似,应用缺陷检测是一个相对较新的挑战,只有少数文献中的工作涉及到这个问题。特别地,Dong等人提出了一种基于深度神经网络的方法smali2vec [14],针对Android应用程序,并发布了一个包含超过92K个Smali类文件的基准数据集。¹[1]smali2vec的分类器在10层中有810,600个权重参数,每层有300个神经元。相比之下,我们的模型只包含了10,304个权重参数,跨越三个简单的层,大小分别为128、64和32。
在这项工作中,我们遵循他们的项目内缺陷预测(WPDP)策略,使用5折交叉验证来比较他们的方法和我们的方法。他们为每个项目提供了一个AUC分数,并报告了它们的平均值作为最终的评估指标。此外,我们还报告了加权平均分数,以适应项目之间的显著大小差异。对于这个任务,我们采用了与恶意代码定位任务相同的模型架构、聚合方法、损失函数和训练策略。
4)组件类型分类 Component Type Classification
对于组件类型分类任务,大多数的实验设置与恶意代码定位任务相同,只有一个不同之处,就是预测模型输出层的神经元数量。在这个任务中,分类器包含四个神经元,而不是两个,用于输出四种不同组件类型的概率。
Experimental Results
RQ1: Can DexBERT accurately model Smali bytecode?
在这个第一个研究问题中,我们评估DexBERT是否能够从Smali字节码中学习并建立一个准确的Smali字节码模型,用于Android应用。为此,我们报告了第三节中介绍的三个预训练任务的损失曲线。这些损失曲线显示在图4中,其中X轴表示训练迭代次数(即批次)。
有两个因素让我们可以自信地得出结论,DexBERT确实能够学习一个准确的Smali字节码模型。首先,所有三个预训练任务的损失都迅速下降,并且在只使用了我们预训练数据集的一小部分后就已经非常低,这表明我们的数据集对于我们的目的来说是足够大的。其次,继续进行预训练过程会导致更低的损失,并且不会产生随机波动,这表明模型学习到的并不与新的Smali字节码片段相矛盾,并且确实收敛了。
如第四节所述,MSE损失也可以被视为一个评估指标,它在图4中的第三条曲线上的损失值在训练过程后期接近于零,表明自编码器能够以最小的误差重构给定的DexBERT嵌入输入向量。因此,编码器的输出向量(即图2中的隐藏嵌入)保留了原始DexBERT表示中的关键信息,这是解码器重构表示所需要的。
可以总结如下:
RQ2: How effective is the DexBERT representation for the task of Malicious Code Localization?
在本节中,作者研究了DexBERT在恶意代码定位任务上的性能,并将其与MKLDroid基准工作[13]在其评估数据集上进行了比较。按照他们的实验设置,并微调了DexBERT,使其对给定应用程序的每个类输出一个恶意性得分,或简称为m-score。MKLDroid使用了宽度为10的波束搜索策略进行评估。在表II中,我们展示了MKLDroid论文[13]中报告的MKLDroid性能指标,并同样用了宽度为10的波束搜索策略进行DexBERT性能指标的检测。
此外,我们还进行了一个实验,其中我们不使用波束搜索来评估DexBERT,而是根据m-score是否高于0.5的阈值来预测每个类是否为恶意的或良性的。这个实验的性能指标在表II的最后一行报告。实际上,在与MKLDroid相同的条件下评估时,DexBERT显著优于MKLDroid,在MYST数据集上的F1分数为0.9981。因此,DexBERT根本不需要波束搜索,而是在独立地对每个类进行分类时就能取得出色的性能。此外,我们还将smali2vec [14]作为另一个基准模型,尽管它取得了相当好的性能,但仍然无法超越我们提出的DexBERT。
正如第IV-B2节所提到的,我们扩展了对DexBERT在真实Android应用上的评估。利用我们从Difuzer应用构建的数据集,即Difuzer Extension数据集,DexBERT在识别真实APK中的恶意类方面取得了0.9048的显著F1分数。此外,它在预测良性类方面也取得了0.9560的可观F1分数,从而消除了我们对数据不平衡可能对评估产生负面影响的担忧。
RQ3:How effective is the DexBERT representation for the task of Defect Detection?
在本节中,作者研究了DexBERT在应用缺陷检测任务上的性能,并将其与基准工作smali2vec进行了比较。smali2vec在10个Android项目上的性能如表III所示,其中# of classes表示每个项目中的Smali类的数量。
使用我们的DexBERT表示,我们微调了一个模型来预测给定类是否有缺陷。如表III所示,DexBERT在10个项目中有6个优于smali2vec,并且在加权AUC分数上达到了90.32%,比smali2vec提高了6.33个百分点。
RQ4:How effective is the DexBERT representation for the task of Component Type Classification
在本节中,作者探索了DexBERT在组件类型分类任务上的性能,旨在进一步检验其在不同应用场景下的通用适用性。我们将DexBERT的性能与其他BERT-like模型进行了对比,具体包括BERT [1],CodeBERT [15]和没有预训练的DexBERT=> without pretraining。与恶意代码定位任务的设置类似,我们微调了一个分类器来预测给定类的组件类型。考虑到其他BERT-like基线模型缺乏AutoEncoder模块来进一步降低嵌入维度,我们使用嵌入的第一个状态向量(大小为768)来进行所有的对比实验。
如表IV所示,DexBERT在预测四种组件类型的类上都表现出色。平均而言,DexBERT的性能显著优于所有基线模型,在F1分数方面大约提高了20个百分点。这再次证明了DexBERT在表示Android应用中的Smali指令方面的有效性,并且关键地验证了DexBERT的通用性。
RQ5: What are the impacts of different aggregation methods of instruction embeddings?
中文翻译:不同聚合方法对指令嵌入的影响是什么?
在本节中,我们研究了四种嵌入聚合方法(即,逐元素加法、随机选择、平均和拼接与双线性调整,参见第III-C1节)的影响。这些技术最初是用来聚合BERT [1]和其他深度学习方法 [28]中的词嵌入。从我们的角度来看,DexBERT的BERT和自编码器输出的特征本质上是相似的。BERT嵌入的每个状态向量都是对应词的高级抽象特征。同样,自编码器的每个输出向量都是对应词序列的高级抽象特征向量。因此,如果可以通过加法或其他三种技术来聚合词嵌入,那么也应该可以用类似的方式来聚合词序列嵌入。
我们基于三个下游任务进行了对比实验,以评估DexBERT对聚合方法的敏感程度。如表V所示,在恶意代码定位任务上,所有四种方法的性能指标都非常接近,没有显著差异。对于另外两个下游任务,我们注意到差异比恶意代码定位任务更大。尽管所有四种聚合方法都能达到可接受的性能,但加法是最好的表现者,在两个任务上都取得了最高的指标分数。
RQ6:Can DexBERT work with subsets of instructions?
在前面的RQ中,我们展示了DexBERT在使用整个Smali字节码时的有效性。用DexBERT表示Smali字节码可能会很耗费计算资源,因为一个应用程序(甚至一个类)可能包含非常多的指令。在这个RQ中,我们研究DexBERT是否能够使用指令子集,从而减少需要表示的代码片段的数量,以及减少聚合的需求。
我们假设API调用是携带最多语义信息的指令,因此进行了一个实验,其中我们预先过滤Smali字节码流,只保留API调用的指令。根据我们的预训练数据集的统计,API指令占总指令数的约17.27%。我们重新使用了用完整指令流(参见RQ 1)预训练的模型,但是我们只用过滤后的指令进行了专门的微调。由于缺陷检测数据集中的一些项目中有许多类没有API调用(一些具体例子包含在附录中),这将导致空的表示,所以我们只考虑恶意代码定位和组件类型分类这两个任务。
给定一个恶意软件,恶意代码定位的目标是找到其中包含恶意代码的部分。恶意代码定位在Difuzer数据集中表现为逻辑炸弹定位,逻辑炸弹是一种特定的恶意行为。组件类型分类是一个多类分类问题,目标是预测给定类属于哪种Android组件类型(活动、服务、广播接收器或内容提供器)。
如表VI所示,虽然DexBERT在使用所有指令时的性能略高,但DexBERT仅使用API调用时仍然表现得非常好。从计算上讲,只使用API调用的速度快了一个数量级。至于总执行时间,我们以恶意代码定位任务为例。使用完整指令,我们需要大约1.9小时来为所有911,724个类生成DexBERT特征。相反,只使用API调用,我们只需要大约11分钟就可以生成所有特征向量。
Discussion
在本节中,我们首先进行了一个消融实验,考察了DexBERT的嵌入大小对下游任务的影响,以及一个消融实验评估了两个预训练任务的有效性。接下来,我们比较了各种BERT-like基线在三个不同的下游任务上的性能。然后,我们分享了一些关于DexBERT的洞察,这是一种用于Android表示的新颖方法。接下来,我们讨论了一些可能对所提出方法的有效性造成威胁的因素。最后,我们讨论了一些值得进一步研究的未来工作。
Ablation Study on DexBERT Embedding Size
=》DexBERT Embedding大小的消融实验
正如第三节B3部分详细介绍的那样,Android应用场景需要较小的嵌入,因为与典型的文本文档和代码文件相比,它们的标记数量要大得多。为了在模型计算成本和性能之间找到合理的折衷,我们进行了一项消融研究,探索了DexBERT嵌入大小对三个下游任务的影响。实验包括三种不同的自动编码器(AE)隐藏嵌入大小,分别是256、128和64。此外,我们还通过直接使用原始DexBERT嵌入的第一个状态向量(大小为768),而不应用自动编码器的任何降维,来评估性能。该向量的大小为768。
表VII显示,在恶意代码定位任务中,向量大小的减小并不会导致性能的显著损失,直到大小降低到128。因此,我们得出结论,128是这个任务的最佳大小。
对于缺陷检测和组件类型分类任务,实验结果表明,较大的嵌入大小导致性能显著提高。然而,128的大小也为这两个任务提供了一个坚实的折衷方案,支持令人满意的性能,度量分数超过0.9。请注意,选择使用AUC分数进行缺陷检测是为了与该任务的主要基线smali2vec [14]使用的度量保持一致。然而,为了与其他两个任务保持一致,我们还在表VII中提供了该任务的F1分数。
Ablation Study on Pre-training Tasks
=》 预训练的消融实验
为了更好地理解预训练过程,我们进行了一项消融研究,确认了两个预训练设计,即MLM和NSP,对模型的最终改进的必要性和有效性。
在像BERT和DexBERT这样的模型中,使用MLM和NSP进行多任务学习是为了生成适用于各种任务的通用特征。去掉任何一个任务都会降低模型的表达能力。如表IX所示,虽然单独使用MLM可以达到相对较好的性能,但是两个预训练任务的结合显著提高了模型的性能,强化了它们对于有效捕捉smali字节码结构和语义的重要性。在所有三个下游任务上,特别是在缺陷检测(DD)和组件类型分类(CTC)上,MLM和NSP预训练任务的重要性得到了证明。
Comparative Study with other BERT-like Baselines
为了更好地理解预训练过程对Smali代码的必要性和有效性,作者在本节中进行了一项对比研究,评估了现有的BERT-like模型在所有三个Android下游任务上的性能,这些模型可以直接应用于这些任务,而不需要任何技术障碍。具体来说,基线模型包括BERT [1],CodeBERT [15]和没有预训练的DexBERT。由于在第V-D节中的原因,我们使用嵌入的第一个状态向量(大小为768)进行所有的对比实验。
结果显示在表VIII中。有趣的是,每个基线模型在恶意代码定位方面都表现出了非常好的效果。这可以归因于数据集是通过将恶意代码插入到真实应用中人为生成的,导致正负样本之间有明显的分隔,使得它们容易从中学习。然而,预训练的DexBERT模型以0.9999的F1分数超越了基线模型,接近完美。对于另外两个任务,缺陷检测和组件类型分类,其中数据集是从真实应用中收集的,预训练的DexBERT明显优于BERT和CodeBERT,两个任务都提高了大约20个百分点。此外,没有预训练的DexBERT在三个任务上表现出低效和不稳定,这在一定程度上是预料之中的,因为它在微调下游任务之前缺乏先验知识。总体而言,表VIII中的对比结果强烈证明了DexBERT对Smali代码进行预训练的必要性和有效性。
Insight
在这项工作中,作者发现流行的自然语言处理表示学习模型BERT可以用于Android字节码,而不需要太多的修改,只需将反汇编的Smali指令视为自然语言句子。虽然已经有研究表明BERT-like模型可以用于源代码,但我们的工作表明它也可以直接用于没有原始源代码的原始应用。
不过,自然语言和Smali代码之间还是存在一些差距需要弥合。特别是,自然语言处理问题和Android分析问题有着显著不同的应用场景。自然语言处理问题通常是在文本片段级别,其中基本单位是一个(短)段落(例如,句子翻译或文本分类)。然而,在Android应用的软件工程和安全领域,有些问题既存在于类级别,也存在于整个应用级别,即从几条指令到数百万条指令不等。因此,在将指令嵌入应用于Android分析问题时,需要进行嵌入聚合。
此外,虽然这项工作只在类级别的任务上进行了评估,但它预计也可以在其他级别(更低或更高)的任务上工作。对于更低级别的任务(例如,方法级别或语句级别),除了缺乏良好标注的数据集外,没有什么重大的技术障碍。对于更高级别的任务(例如,APK级别),则需要进一步进行嵌入聚合以支持整个应用程序的任务。
Threats to Validity
作者的实验和结论可能面临有效性的威胁。首先,用于恶意代码定位的MYST数据集是人为生成的,因此可能不能代表真实世界的应用程序的情况。为了缓解这个问题,我们扩展了我们的评估,包括了来自Difuzer [39]的真实应用程序。此外,我们的恶意代码定位模型在真实场景中的效用还可以通过将其应用于除逻辑炸弹之外的更多种类的恶意行为来进一步评估。这种扩展可以作为未来工作的一个方向,因为它需要大量的人工分析工作。
其次,用于Android应用缺陷检测的数据集是几年前创建的。Android应用随着时间的推移不断发展。DexBERT在今天的应用上表现如何还需要进一步验证。因此,有必要创建新的数据集并对Android应用缺陷检测进行更全面的评估。
Future Work
作者提出的DexBERT在三个类级别的Android分析任务上进行了验证。一个重要的方面是扩展DexBERT评估的任务范围。我们确定了一些对研究社区感兴趣的任务(如恶意软件检测、应用克隆检测、重打包识别等),这些任务可以从我们的方法中受益。
此外,我们展示了DexBERT表示可能不总是需要完整的Smali指令流。然而,我们只研究了一种过滤标准。其他的过滤方法可以进一步研究,以优化计算成本和有效性之间的权衡。
最后,用于恶意代码定位和缺陷检测等任务的评估数据集可以通过包含更多最新的应用程序来进一步完善。鉴于处理和构建新数据集所需的大量工作,我们计划在未来的另一项研究中进行这种改进。