使用 API 语义增强先进分类器以检测演化后的 Android 恶意软件
本文介绍 2020 年 CCS 会议的一篇文章,题目是《Enhancing State-of-the-art Classifiers with API Semantics to Detect Evolved Android Malware》,DOI信息在这里。
由于恶意软件的演化,基于机器学习的 Android 恶意软件分类器随时间而明显降级、老化。文章提出 APIGraph
, 基于语义相等或相似的 API 的相似度信息,减缓分类器的老化。
摘要
机器学习分类器广泛应用于 Android 恶意软件检测,但同时,机器学习的应用也面临一个紧要的问题。由于恶意软件的演化 (evolution),基于机器学习的 Android 恶意软件分类器随时间而明显降级、老化。先前的工作提出通过使用再训练 (retraining) 或主动学习以提高老化模型的效果。但是,底层的分类器仍然是盲目的,未意识到恶意软件的演化。不出所料,这种对演化不敏感的再训练或主动学习是有代价的,即对数以万计的恶意软件样本进行标注,并付出大量人力。
在这篇文章中,作者提出一个叫做 APIGraph
的框架,基于语义相等或相似的 API 的相似度信息,减缓分类器的老化。实验表明,由于减缓了分类器的老化, APIGraph
节省了主动学习中的标记样本所需的显著人力成本。
简介
机器学习分类器广泛用于检测 Android 恶意软件,并取得了令人惊叹的表现。 尽管取得了成功,但在恶意软件检测中应用机器学习的一个新问题是恶意软件的演化(以增强功能并避免被检测到),从而导致机器学习分类模型的性能随时间推移而显著下降。2019 年由卡巴斯基发布的白皮书显示,基于机器学习的一个商用分类器的检测率,仅在 3 个月时间就由接近 100% 下降至 80% 以下,甚至于 60%。
鉴于老化问题的严重性,之前的工作已经提出了检测模型老化和提高恶意软件分类器性能的方法。但是,尽管它们能够减缓老化、提升性能,其底层模型在很大程度上仍未意识到恶意软件的演化,特别是演化后的恶意软件之间的语义。不出所料,它们需要数以万计的带有标签的新恶意软件样本,以让底层模型学习演化,这涉及到大量的人工标签工作。
在本文中,作者研究的问题是了解为什么恶意软件的演化会降低模型的性能,然后用演化语义增强现有的分类器,以减缓老化。当老化被减缓时,使用再训练、主动学习或者在线学习等方法提升模型性能需要更少的新样本(以及更少的人工标签)。对于此问题,文章的关键观察结果是:恶意软件样本在演化过程中,往往保持相同的语义,但切换到不同的实现方式,以便演化后的恶意软件能够避免被现有的分类器检测到。
通过这一观察结果,文章提出在恶意软件演化过程中捕捉语义相似性,并利用捕捉到的信息来减缓恶意软件分类器的老化。文章的见解是,如果两种行为(例如调用不同的 Android API)在语义上是相似的,那么这种相似性也会反映在 Android 的官方文档中,例如为开发者的 API 参考文档。因此,可以在不同的 Android API 中提取这种共同的、语义的信息,并将它们分组,以用于恶意软件分类器。
文章设计了一个叫做 APIGraph
的框架,根据官方文档中直接提供以及提取的信息,构建一个 Android API 关系图。图中的每个节点代表一个关键实体(entity),例如一个 API、一项异常(exception)或一项权限;每个边代表两个实体之间的关系,例如一个 API 抛出一项异常或请求一项权限。APIGraph
之后通过将每个 API 转换为嵌入(embedding)并将相似的 API 集群(cluster),从关系图中提取 API 的语义。以 API 集群形式提取的 API 语义可以进一步用于现有的 Android 恶意软件分类器,以检测演化的恶意软件,从而减缓老化。
文章对四个 Android 恶意软件分类器采用了 APIGraph
,它们是 MamaDroid、DroidEvolver、Drebin 与 Drebin-DL,并使用按照现有指导方案形成的数据集,其中包括来自 2012 至 2018 年的 32.2 万个 Android 应用。评估表明,APIGraph
与另一方案 Tesseract
中的主动学习相结合时,可以显著减少上述四种恶意软件分类器的标注工作,即根据分类器的不同,从 33.07% 到 96.30% 不等。同时,文章也测试了时间下面积(Area Under Time,AUT),这是 Tesseract
提出的一个新指标,它显示在 APIGraph
的帮助下,模型老化的速度明显减慢。
文章的贡献如下:
- 文章说明,尽管 Android 恶意软件在随着时间的推移而演化,但许多语义仍然是相同或相似的,为我们留下了在演化后检测它们的机会。
- 文章提出用关系图来表示 Android API 的相似性,并设计了一个名为
APIGraph
的系统,来构建 API 关系图,并从关系图中提取语义。 - 文章建立了一个大规模的演化数据集,时间跨度超过7年。此数据集几乎是目前最先进的工作中用于评估模型老化的三倍。
- 文章对 4 个最先进的 Android 恶意软件检测器应用了
APIGraph
的结果(即 API 集群),实验显示,人工标注的工作明显减少、这些模型的老化速度明显减慢。
概述
示例
文章采用一个真实世界、激励性的例子来说明 APIGraph
如何在演化过程中捕获不同恶意软件版本的语义。该恶意软件样本叫做 XLoader
,是一种偷取个人可识别信息(personally identifiable information,PII)与财务信息的间谍软件与银行木马。尽管 XLoader
已经在 2018 年 4 月至 2019 年末演化为 6 种存在大量实现区别的变种,它们之间的许多语义仍然是相同的。
为便于描述,文章将 XLoader
的实现进行逆向工程与简化,分为 3 个代表性的代码段(V1、V2 与 V3),如下图所示。
这 3 个版本的代码中,有两类语义保留,但是它们有 3 种不同的实现。这两类语义是:PII 的收集、将 PII 发送至恶意软件服务器。可以发现,PII 的收集,其信息源从V1、V2 到 V3,由 1 个演化为 2 个、4 个;将 PII 发送至恶意软件服务器也有 3 种不同的实现,分别是 HTTP 请求、普通 socket 与 SSL socket。
接下来,文章解释 APIGraph
如何捕捉 XLoader
三个不同版本在发送 PII 方面的语义相似性,从而帮助用 V1 训练的机器学习分类器检测进化的 V2 和 V3 。下图示例了由 APIGraph
构建的关系图的一部分,其中捕获了 Android API、权限与异常的相互作用。所有 3 个 API(即openConnection
、SocketFactory.createSocket
与ssl.SSLSocketFactory.createSocket
)均抛出 IOException
异常、使用 INTERNET
权限;其中两个 API 还共享更多的异常与权限。也就是说,这 3 个 API 在关系图中的邻域足够接近,可以被归为一个集群。因此,一个机器学习分类器,在关系图的帮助下能够捕获 V2/V3 与 V1 之间的相似性,并在演化之后将 V2 与 V3检测为恶意软件。
系统结构
下图展示了 APIGraph
总体的结构。APIGraph
建立于 API 关系图的概念之上,捕捉所有 Android API 的语义和相似性。APIGraph
分为两个主要阶段:
- 建立 API 关系图;
- 利用 API 关系图。
首先,APIGraph
通过收集与某一 API 级别相关的 Android API 文档,并提取实体(如 API 和权限)以及这些实体之间的关系,来构建一个 API 关系图。之后,APIGraph
利用 API 关系图来增强现有的恶意软件检测器。具体地,APIGraph
使用图嵌入算法将关系图中的所有实体转换为矢量。这里的直觉是,嵌入空间中两个实体的向量差异反映了关系的语义。因此,APIGraph
通过解决一个优化问题来生成所有的实体嵌入,使具有相同关系的两个实体的向量相似。然后,APIGraph
对嵌入空间中的所有 API 实体进行聚类,将语义相似的 API 聚集在一起。之后,这些 API 集群被用来增强现有的分类器,使其能够在检测过程中捕捉到使用某个 API 级别的 Android 恶意软件的语义等效演化,从而减缓老化的速度。
设计
API 关系图的定义
一个 API 关系图 $G = \langle E, R \rangle $ 定义为一个有向图,其中 $E$ 是所有节点(称为实体)的集合,$R$ 是两个节点之间所有边(称为关系)的集合。API 关系图是异质的,也就是说,有不同的实体和关系类型,如下所述。
实体类型 在 API 关系图中有四种类型的实体,它们也是 Android 中的基本概念:方法、类、包与权限。前三种实体类型是组成 Java 程序的关键代码元素,最后一种描述了 Android API 在执行过程中需要的资源。这四个实体共同提供了足够的能力来捕捉 API 之间的内部关系。
关系类型 文章按照先前工作的分类,定义了十种关系类型,它们涵盖了关于 API 的各种信息。如下表所示,这十种关系类型,也可以分为如下五类:
- 组织类别描述了不同实体之间的代码布局关系。
- 标准类别描述了方法实体的标准,反映一个方法实体如何使用类实体作为其参数、返回值或抛出的异常。
- 用法类别规定了如何使用一个 API。文章关注了两种关系:条件关系,指定一个方法实体的使用是以另一个方法实体为条件的,例如,一个 API 应该只在另一个 API 被调用后使用;替代关系,描述一个方法实体可以被另一个方法实体取代。
- 参考类别中具有一个描述两个实体之间一般关系的
refer_to
关系。例如,API 文件在描述一个方法实体时,可以用“参见……”这样的句子来引用另一个方法实体。 - 权限类别包含
uses_permission
关系,以描述方法实体可能需要的权限实体。
为构建 API 关系图,需要提取上述类型的实体和关系。在本节的其余部分,文章首先介绍 Android API 参考文档的组织,然后描述如何从这些文档中提取不同类型的实体和关系。
API 文档的收集
APIGraph
从官方网站上下载所有平台 API 和支持库的参考文档。每个 Android 版本都有相应的 API 级别,例如 Android 10的 API 级别为 29。APIGraph
抓取的是 API 级别 14 到 29 的文档,它们对应于 Android 4.0 到 Android 10,是目前主要的活跃 Android 版本。
Android API 参考文档是按层次组织的。从顶到底,依次为包、类与方法。API 文档是在类的层次上给出的。每个类都有一个单独的 HTML 文件来描述基本的类层次信息,也有这个类中所有方法的详细文档。文档可以分为两部分:
- 结构化的信息,包括类的简介和方法的原型、返回值和抛出的异常;
- 非结构化的描述,以几段文字的形式,描述API的功能、要求和指令。
实体的提取
在 API 关系图中,有四种实体类型。文章通过以下方式从文件中提取这些实体类型:
- 类实体 由于 API 文件是以类为单位组织的,
APIGraph
直接从每个类文件中提取一个类实体。 - 包实体
APIGraph
通过从完整的类名中分离出包名来提取包实体。 - 方法实体
APIGraph
将每个类的文档文件解析为文档对象模型(DOM),然后提取属于一个类的方法实体。 - 权限实体
APIGraph
解析列出所有权限的清单文件,以提取权限实体。
关系的提取
由于有些关系(如 class_of
关系)被组织在结构良好的 HTML 元素中,而有些关系(如 referred_to
关系)被嵌入在非结构化的文本中,文章采用两种方法从 API 文档中提取关系。
结构化文本中的关系解析
由关系类型表所述,6 种关系在文档中结构化地描述。APIGraph
直接通过文档解析来提取这些种类的关系。其细节是:首先,APIGraph
在提取类、方法和包实体的过程中提取 function_of
和 class_of
关系。其次,APIGraph
从每个类文件中的概况部分提取继承关系。最后,APIGraph
在每个方法的标准部分提取 use_parameter
、returns
和 throws
关系。
基于模板的非结构化文本的关系匹配
APIGraph
通过一种基于模板的方法,在自然语言处理(Natural Language Processing,NLP)技术的帮助下,提取其余 4 种关系。注意 APIGraph
也从现有工作产生的两个 API-权限映射中提取 uses_permission
关系,以补充从 API 文档中提取的关系,因为 Android API 文档中的此类信息可能不完整。一般而言,基于模板的关系提取可分为三步:
- 手动形成匹配模板;
- 模板集的迭代扩展;
- NLP 增强的模板匹配。
手动形成匹配模板
在这个步骤中,作者手动检查 1% 的 API 文档,以调查用于描述关系的模式。下表给出了几种正则表达式格式的模板,这些模板是为匹配非结构化文本中的关系而人工制定的。例如,模板“see also ENT”匹配的是当前方法实体和 ENT 实体之间的 referred_to
关系。
模板集的迭代扩展
在这个步骤中,APIGraph
采用了一种半自动的策略来迭代制定关系匹配的模板。在这个过程中,有三个子步骤,如下所述。
- 首先,随机选择 1% 的 API 并收集其文件。
- 第二,使用现有的模板集,在 NLP 技术的帮助下从这些文件中提取关系。
- 第三,在匹配之后,手动检查是否有现有模板集没有捕获的关系。如果答案是肯定的,就为它们手动制定模板,并重复第一步的操作。否则,
APIGraph
将完成模板的制定。
在上述过程的指导下,模板集在手动查看了所有 API 文档的 5% 后趋于一致。最后,文章总结了 217 个关于 4 种关系的模板。上表中列出了每个关系的模板数量。整个模板构建过程需要两位安全专家花费三天左右的时间。请注意,Android 的文档随着时间的推移是稳定的。例如,只有 1.4%(834 个)的 API 被添加,1.6%(989 个)的 API 将其描述从 API_level 28 改为 29,新添加或改变的描述都不需要额外的模板。
NLP 增强的模板匹配
APIGraph
通过两个步骤将模板与非结构化的 API 文档进行匹配。首先,APIGraph
将段落分割成句子,然后通过以下方法对每个句子进行预处理。
- 词干提取(stemming)。
APIGraph
将每个单词还原为其基本形式。例如,“requires”与“required”被还原为“require”。 - 指代消歧(co-reference resolution)。
APIGraph
采用基于声明的指代消歧,以确定每个代词对应的实体。例如,“这个方法需要权限 INTERNET”一句中的“这个方法”被解析为该句子所属的方法。 - 实体名称规范化。
APIGraph
通过跟随其原始定义的超链接,将所有多态的名称取代为其准确值。这样APIGraph
就将实体的表述规范化了。例如,名称android.Manifest.permission.INTERNET
与其常值(constant value)android.permission.INTERNET
在文档中都有使用,APIGraph
将前者替换为后者。
之后,APIGraph
将所有模板与 API 描述中的每个预处理句子进行匹配。如果发现与模板的匹配,APIGraph
就会按照模板的规定从句子中提取关系。如果一个句子不能与任何模板匹配,APIGraph
h将放弃该句子。
利用 API 关系图
为利用 API 关系图,APIGraph
将把关系图中的每个 API 转换为嵌入表示,然后将这些嵌入归入集群。受到词嵌入和图嵌入的启发,API 嵌入的概念是将关系图中的每个 API 转换为一个向量,代表其语义。文章使用的转换算法如下,其中利用了 TransE
算法。
算法描述如下:
- 第 3-5 行,
APIGraph
提取权限实体,并根据共同的权限添加新的关系。这里的直觉是,Android 中的权限保留了语义,而APIGraph
更关注权限。 - 第 6-7 行,
APIGraph
把每个 API 实体 $e \in E$ 与每个关系 $r \in R$ 分别嵌入为向量 $l_e, l_r \in \mathbb{R}_k$。 - 第 10-14 行,
APIGraph
使用TransE
算法对三元组集合 $S$ 中的每一个三元组 $(h, r, t)$,最小化 $\Vert lh + l_r - l_t \Vert_2^2$,其中 $h$ 与 $t$ 为实体,$r$ 为关系。这里的直觉是,如果两个头部实体 $h_1$ 与 $h_2$ 与同一尾实体有相同关系,则它们的嵌入 $l{h1}$ 与 $l{h_2}$ 应该是接近的。 APIGraph
使用k-Means
将 API 嵌入聚成不同的组,并通过 Elbow 方法确定聚类数量。
在 APIGraph
成功形成 API 集群后,APIGraph
采用每个集群中心的嵌入,来表示该集群中独立 API 的语义。
API 关系图的结果与实验设置
API 关系图的统计数据
由 APIGraph
生成的 API 关系图的结果是用实体和关系来描述的。以 API 级别 29 为例,下表显示了提取实体的数量,共有 67209 个实体,包括 59125 个方法,7368 个类,446 个包,以及 270 个权限。注意不同的 API 级别有不同数量的实体,因为 API 会随着时间的推移而演化。下表也列出了每种类型提取的关系数量,这些实体之间有 121,345 个提取的关系。
数据集
文章的数据集时间跨度为 7 年,包含 322,594 个 Android 应用,其中有 32,089 个恶意应用与 290,505 个 良性应用。数据集符合由 Tesseract 提出的标准,即时间上的一致性和空间上的一致性。前者确保数据集按出现时间排序、几乎均匀分布;后者确保数据集中恶意软件占比与真实世界一致,约为 10%。
候选分类器与 APIGraph 的增强
文章选择了四个最先进、具有代表性的恶意软件分类器用于评估。这四个分类器跨越了不同的机器学习算法,它们对 API 的使用也有所不同,但它们都面临着老化问题。
MamaDroid
提取 API 调用对(即调用者与被调用者),之后将它们抽象为包调用对。之后,MamaDroid
建立马尔可夫链,对不同包之间的转移进行建模,包之间的转移概率被用作学习算法中 app 的特征向量。文章获取了MamaDroid
的全部源代码,并使用与其文章同样的配置。APIGraph
将MamaDroid
的实现中使用的每个 API 调用对替换为 API 集群对,然后在马尔可夫链中使用这样的对。DroidEvolver
通过静态分析找出 app 使用的所有 API,之后建立一个 API 出现的二进制向量,作为这个 app 的特征向量。之后,DroidEvolver
维护一个由五种线性在线学习算法组成的模型池,使用加权投票算法对 app 进行分类。当池中的某个模型老化时,它将根据其他未老化的模型的结果进行增量更新。文章获取了DroidEvolver
的源代码,并与其作者联系以确保实验与其文章一致。APIGraph
将 API 出现的二进制向量替换为 API 集群出现的二进制向量。Drebin
广泛收集特征,例如硬件使用量、API 调用、权限、网络地址,供一个基于 SVM 的分类器使用。就 API 特征而言,Drebin
考虑了一组选定的约束和可疑的 API,这些 API 可以访问关键和敏感数据或资源。文章严格遵守其文章中的细节描述与配置要求,实现了Drebin
。与前相同,APIGraph
将 API 出现的二进制向量替换为 API 集群出现的二进制向量。Drebin-DL
使用与Drebin
相同的特征,但是使用深度神经网络(Deep Neural Networks,DNN)作为分类器。文章也遵循先前的工作实现了Drebin-DL
。APIGraph
作出的增强与Drebin
相同。
评估
文章的评估回答了以下四个研究问题。
- 模型可维护性分析。在维护恶意软件分类器的高性能方面,
APIGraph
节省了多少人工标注的工作? - 模型可持续性分析。
APIGraph
在延缓分类器老化方面的效果如何? - 特征空间稳定性分析。
APIGraph
在捕捉同一家族进化的恶意软件之间的相似性方面的效果如何? - API 紧密性分析。按
APIGraph
分组的集群中的 API 有多近?
模型可维护性分析
具有固定再训练阈值的主动学习
当分类器的 $F_1$ 低于阈值 $T_l$ 时,使用主动学习选出 1% 最不确定的样本重新训练分类器,直到其 F1 达到另一阈值 $T_h$。在 $T_l=0.8, T_h=0.9$ 时,实验结果如下表。
可以看出,尽管 DroidEvolver
支持在线学习,APIGraph
仍然可以节约大量人力成本。文章还将所需的样本标签数量根据累积和月度分布绘图表示,如下图。
具有不同学习率的主动学习
将每个月新引进的应用程序的比例固定为 1%、2.5%、5%、10% 和 50%,并检查每个分类器的 AUT 值。AUT 定义了每个图中的曲线下的面积,代表模型的可持续性,其公式如下:
其中,$f$ 是评价指标(如 $F_1$ 值、精确度、召回率等),$N$ 是测试时段的数量,$f(k)$ 是评价指标在 $k$ 时刻的评估值。这里最终的指标为 $AUT(F_1, 12m)$。接近 $1$ 的 $AUT$ 指标意味着更好的表现。
下表展示了四个分类器在应用 APIGraph
之前及之后的 $AUT$ 结果。可以看出,分类器应用 APIGraph
后均取得了更好的效果,且提升明显。
模型可持续性分析
文章使用某年(如 2012 年)的样本训练分类器,并测试其在下一年(如 2013 年)样本的表现。下表展示了四个分类器在应用 APIGraph
之前及之后的 $AUT$ 结果。可以看出,$AUT$ 有一定提升,因此说明 APIGraph
确能减缓老化。不同年份的 $AUT$ 值非常相似,这表明恶意软件一直在演化,直到最近的 2018 年。
在下图中,文章将使用 2012 年样本训练、2013 年样本评估的四个分类器的 $F_1$ 结果按月份划分,观察到 Drebin-DL
与 Drebin
获得了最好的效果。这可能是因为 Drebin
使用的是 API 的选定子集,对于恶意软件的演化有一定优势。
特征空间稳定性分析
文章计算同一家族的恶意软件特征空间,以说明 APIGraph
能够捕获语义信息。下图显示了以 API 和 API 集群为特征的每个恶意软件家族的特征稳定性得分的分布。可以看出,所有以 API 集群为特征的家族的特征稳定性得分都非常接近 1,比直接以 API 为特征的家族明显提升。这一观察解释了 APIGraph
可以捕获恶意软件的演化,因为恶意软件开发者倾向于使用语义相似的 API 来实现相同或相似的功能。
文章还在下图中显示了四个特定恶意软件家族的特征稳定性得分的分析。以 API 集群为特征的特征稳定性得分几乎是平的,没有随着时间的推移而有很大的下降;相比之下,以独立 API 为特征的特征稳定性得分不仅低(接近 0.75),而且还随着时间的推移而下降(有时下降到 0.3这样一个非常低的值)。这从另一个角度也表明, APIGraph
可以捕捉到恶意软件随时间的演化。
API 紧密性分析
下图展示了文章使用 t-SNE 对所有 API 嵌入投射至二维空间并可视化的效果子图。可以看出,与 PII 相关的 API,如 getDeviceId()
与 getSubscriberId()
距离较近;与网络相关的 API,如 java.net
、javax.net
与 android.net.Network
同样距离较近。