问题描述
Android 市场的开放性导致了恶意软件(Malware)的盛行。据 360 安全中心报告,每天都能截获数万个 Android 恶意软件,使得 Android Malware Detection 成为研究人员热议的话题。传统的 Android 恶意软件检测方法主要依赖于基于规则或签名的检测机制,其中使用 yara 实现相对简单。但这种基于签名的检测方法是信息密集型的,需要持续收集新的签名,而基于规则的实现则极为复杂,极易导致误报或让狡猾的恶意软件逃过检测。
随着机器学习的流行,越来越多的研究人员开始尝试利用机器学习来实现恶意软件的检测。核心思路是从 Android 的 APK 文件中提取信息,用于训练模型,随后预测其他 APK 文件是否为恶意软件。根据信息提取方法的不同,主要分为两类:一类是通过静态分析,从 APK 中提取 permissions、intents、receivers 等组件,以及通过反编译提取代码调用,利用这些信息进行模型训练;另一类是通过实际安装运行 APK,拦截网络请求和监听系统 API 调用来获取数据,作为模型训练的基础。
在探讨此问题时,由于“Incinerator”项目的动态检测功能尚未完全实现,我们暂时缺乏研究动态分析的条件,因此选择采用静态分析方法进行研究。
当前主流方案
基于静态分析的机器学习训练方案主要包括以下几类:
- 权限提取训练:
- 从 AndroidManifest.xml 中提取 permissions 信息进行模型训练。
- 综合信息提取训练:
从 AndroidManifest.xml 中提取 permissions、intents、receivers 等信息,并通过反编译从 APK 中基于规则抽取 Android 系统 API 调用等信息进行模型训练。
- 整体 APK 训练:
将整个 APK 文件作为机器学习训练的输入,包括将 APK 文件的二进制字节流作为输入,或通过反编译抽取 opcode 作为训练输入。
据文献报道,这些方案可实现 90% 以上的准确率。尤其是方案 3,准确率在 92%-93% 之间,而方案 1 和 2 在多数研究中可达到 95% 以上的准确率。
我们试图重现文献中的方案,首先着手基于 permissions 的方案进行验证。
数据源:
恶意软件集合:
a. 来自威胁情报公司 abuse.ch 的 Malware APK 集合 2000 个(简称 MB)
b. VirusShare 2020/2021/2022 的 Malware 集合(简称 VS2020/VS2021/VS2022)
良性软件集合:
a. 从应用宝下载的 APK 10000 个
b. 从 APKPURE 下载的 APK 10000 个
训练方法
通过静态分析从 APK 的 AndroidManifest.xml 中抽取 AOSP (Android Open Source Project) permissions,并通过 One-hot Encoding 的方式输入模型进行训练。模型选择采用传统的机器学习二分类模型如随机森林、SVM 等进行训练。经测试,随机森林的效果最佳,准确率可达 98%。
我们选择应用宝的 APK 作为良性样本,VS2022 作为恶意软件样本,进行训练。训练数据如下:
模型 | Precision | Recall | FPR |
随机森林 | 0.983 | 0.983 | 0.056 |
SVM | 0.981 | 0.977 | 0.063 |
然后我们对其他数据集进行测试验证:
数据集 | Precision | Recall | FPR |
APKPure | 0.0 | NAN | 0.59 |
MB | 1.0 | 0.95 | NAN |
VS2020 | 1.0 | 0.96 | NAN |
VS2021 | 1.0 | 0.94 | NAN |
在进行 APKPure 数据集的验证时,发现模型的假阳性率异常高,超过了 50%,这表明模型在不同数据集的交叉验证上表现不佳。同时,在 MB、VS2020、VS2021 数据集上得到的高准确率由于高假阳性率而变得无意义。
为了深入理解模型的预测表现,我们选择使用 LinearSVM(线性支持向量机)来解释模型的预测结果,并尝试探讨可能出现的问题:
在训练过程中,共有 265 个权限被用于训练模型。我们重点分析了对于 Malware 预测结果影响最大的 30 个权限:
0 1.9507425950717683 android.permission.READ_SMS
1 1.6805547441380115 android.permission.SEND_SMS
2 1.5291784053142392 android.permission.RECEIVE_SMS
3 1.281383891333467 android.permission.WRITE_SMS
4 1.1385944832617678 android.permission.GET_DETAILED_TASKS
5 1.0870145778775504 android.permission.MANAGE_USERS
6 0.9822953162458009 android.permission.SET_TIME_ZONE
7 0.9815855293627985 android.permission.REQUEST_DELETE_PACKAGES
8 0.8705538278525148 android.permission.ACCOUNT_MANAGER
9 0.7701851337780519 android.permission.ACCESS_CACHE_FILESYSTEM
10 0.7493889020376178 android.permission.PERSISTENT_ACTIVITY
11 0.742267985802697 android.permission.SET_PREFERRED_APPLICATIONS
12 0.6575763216374741 android.permission.USE_SIP
13 0.6423455602781643 android.permission.MODIFY_PHONE_STATE
14 0.5733719308777389 android.permission.READ_CALL_LOG
15 0.5713221448442122 android.permission.WRITE_SECURE_SETTINGS
16 0.5177117115666185 android.permission.CLEAR_APP_CACHE
17 0.5013751180995185 android.permission.WRITE_SYNC_SETTINGS
18 0.47540432455574055 android.permission.INJECT_EVENTS
19 0.450576746748121 android.permission.BIND_ACCESSIBILITY_SERVICE
20 0.4497437629117625 android.permission.READ_SYNC_STATS
21 0.40721040702182304 com.android.alarm.permission.SET_ALARM
22 0.3958974436391258 android.permission.GET_PACKAGE_SIZE
23 0.35828369132005317 android.permission.TRANSMIT_IR
24 0.3538089622374305 android.permission.CHANGE_COMPONENT_ENABLED_STATE
25 0.3303834311984685 android.permission.STATUS_BAR
26 0.3277728921018696 android.permission.WRITE_USER_DICTIONARY
27 0.31322691738916597 android.permission.SET_DEBUG_APP
28 0.28600828593282673 android.permission.INSTALL_PACKAGES
29 0.27804088205285526 android.permission.SHUTDOWN
导致 Benign 结果最重要的 30 个权限:
1 -1.0280830288092226 android.permission.FORCE_STOP_PACKAGES
2 -1.0244749163270055 android.permission.DELETE_CACHE_FILES
3 -0.9235183435775582 android.permission.READ_PRIVILEGED_PHONE_STATE
4 -0.7975588094210508 android.permission.USE_BIOMETRIC
5 -0.7691538868495551 android.permission.READ_CELL_BROADCASTS
6 -0.7288571523071693 android.permission.REQUEST_INSTALL_PACKAGES
7 -0.7278186994140812 android.permission.WRITE_CALL_LOG
8 -0.7029898754031535 android.permission.READ_SEARCH_INDEXABLES
9 -0.6832562629713737 android.permission.ACCESS_NOTIFICATION_POLICY
10 -0.6442707037030093 android.permission.BIND_NOTIFICATION_LISTENER_SERVICE
11 -0.6229441323892875 android.permission.CAPTURE_AUDIO_OUTPUT
12 -0.5951302503005503 android.permission.REORDER_TASKS
13 -0.552113274404841 android.permission.FACTORY_TEST
14 -0.5512329811397917 android.permission.CAMERA
15 -0.5415431826751977 android.permission.PACKAGE_USAGE_STATS
16 -0.5373788445105623 android.permission.READ_SYNC_SETTINGS
17 -0.5300427083556158 android.permission.ACCESS_WIFI_STATE
18 -0.48952375397337794 android.permission.READ_PHONE_NUMBERS
19 -0.4822239255635727 android.permission.STOP_APP_SWITCHES
20 -0.4525220364959383 android.permission.WRITE_MEDIA_STORAGE
21 -0.4133049145725493 com.android.browser.permission.WRITE_HISTORY_BOOKMARKS
22 -0.3902532535519829 android.permission.CAPTURE_VIDEO_OUTPUT
23 -0.34681147328619505 android.permission.READ_FRAME_BUFFER
24 -0.34134222449779317 android.permission.WRITE_GSERVICES
25 -0.3335042039412585 android.permission.BIND_APPWIDGET
26 -0.3263774109427998 android.permission.AUTHENTICATE_ACCOUNTS
27 -0.3136298914538836 android.permission.NFC
28 -0.3000955825422318 android.permission.READ_EXTERNAL_STORAGE
29 -0.2846046321402758 android.permission.CALL_PRIVILEGED
30 -0.28338090002182315 android.permission.READ_CALENDAR
在表格中,第二列显示了通过 SVM 计算得到的权重值。由于在标签设定中,Malware 被标记为 1,而 Benign 被标记为 0,且训练数据的格式是 0,1,1,0,...0,1,1,0,...这样的布尔值,因此,当权重为正时,该权重在计算 Malware 的预测结果时具有较高的重要性;权重值越大,其重要性越高。相反,当权重为负时,该权重在计算 Benign 的预测结果时具有较高的重要性;权重值越小,其重要性越高。
通过分析这些权限及其功能,我们发现 Malware 相关的权限通常比 Benign 相关的权限具有更高的危害性。在一定程度上,这种模型的设计是合理的。例如,模型成功识别了与 SMS 相关的权限主要与 Malware 相关,并赋予了较高的权重,这意味着,基本上,一个 APP 如果包含 SMS 权限,就非常可疑。实际上,普通的 APP 不应该请求此类权限,因为短信管理通常是系统 APP 的职责。
然而,这里存在一个问题:权限的存在是因为 Android 系统认为某些行为可能不妥,需要用户确认。所以,理论上,所有需要请求的权限都有可能对用户造成损害。因此,没有请求权限应该被视为一个加分项。但在二分类机器学习的情境下,模型会做出区分,因为 Benign 类别的存在意味着一定会有一部分权限被视为支持 Benign 的证据。
现在我们来分析为什么会出现如此高的假阳性率: 我们使用 LinearSVC 来解释模型的预测结果,并对一些具有假阳性的权限信息进行分析:
0.1773649887447295 android.permission.WAKE_LOCK
0.01285824377030036 android.permission.INTERNET
-0.1357928094523775 android.permission.ACCESS_NETWORK_STATE
0.43102404170044467 com.android.alarm.permission.SET_ALARM
0.1773649887447295 android.permission.WAKE_LOCK
0.14741402851800423 android.permission.SYSTEM_ALERT_WINDOW
0.02740438240042149 android.permission.FOREGROUND_SERVICE
0.01285824377030036 android.permission.INTERNET
-0.1357928094523775 android.permission.ACCESS_NETWORK_STATE
-0.15043626374678254 android.permission.WRITE_EXTERNAL_STORAGE
-0.1975995718519041 android.permission.CHANGE_WIFI_STATE
-0.20461138790573433 android.permission.VIBRATE
-0.511067438637911 android.permission.ACCESS_WIFI_STATE
0.1773649887447295 android.permission.WAKE_LOCK
0.02740438240042149 android.permission.FOREGROUND_SERVICE
0.01285824377030036 android.permission.INTERNET
-0.1357928094523775 android.permission.ACCESS_NETWORK_STATE
-0.33867385510052594 android.permission.READ_EXTERNAL_STORAGE
-0.511067438637911 android.permission.ACCESS_WIFI_STATE
而真阳的权限信息:
0.32757400447767016 android.permission.INSTALL_PACKAGES
0.2870058866311678 android.permission.READ_PHONE_STATE
0.1773649887447295 android.permission.WAKE_LOCK
0.1545767541451571 android.permission.FLASHLIGHT
0.14613075920332474 android.permission.BLUETOOTH_ADMIN
0.140268653568319 android.permission.GET_ACCOUNTS
0.08641386050999389 android.permission.MOUNT_UNMOUNT_FILESYSTEMS
0.06460516872049353 android.permission.ACCESS_COARSE_LOCATION
0.01285824377030036 android.permission.INTERNET
-0.009804892771664459 android.permission.ACCESS_FINE_LOCATION
-0.12321341834571817 android.permission.READ_LOGS
-0.1357928094523775 android.permission.ACCESS_NETWORK_STATE
-0.15043626374678254 android.permission.WRITE_EXTERNAL_STORAGE
-0.15994619600450963 android.permission.CHANGE_NETWORK_STATE
-0.16005902734200772 android.permission.WRITE_SETTINGS
-0.1975995718519041 android.permission.CHANGE_WIFI_STATE
-0.20461138790573433 android.permission.VIBRATE
-0.23536025455979454 android.permission.CALL_PHONE
-0.24802834827531783 android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
-0.30018060973660377 android.permission.BLUETOOTH
-0.33867385510052594 android.permission.READ_EXTERNAL_STORAGE
-0.511067438637911 android.permission.ACCESS_WIFI_STATE
-0.5625902678304402 android.permission.CAMERA
-0.7242676191415552 android.permission.REQUEST_INSTALL_PACKAGES
通过分析,我们发现了一个模式:拥有较少权限的 APK 往往会被误判,而权限较多的 APK 基本能得到正确的预测。深入探究后,我们理解到这种现象的出现主要是由于 APKPure 样本中大多数 APK 的权限数量较少,而我们的训练模型主要基于权限较多的应用宝 APK 样本。因此,预测误差的产生在一定程度上是由样本差异导致的。
为了解决这个问题,一个直接的方法是将 APKPure 的数据也纳入训练过程,以增强模型的泛化能力和预测准确性。
我们采取了以下措施:从 APKPure 样本中随机抽取一半,即 5000 个 APK,同时从应用宝样本中随机抽取一半,约 5000 个 APK,一同用于模型的训练。然后,我们使用这个新训练得到的模型来预测未参与训练的样本。结果显示,新模型的预测准确率得到了显著提高。
模型 | Precision | Recall | FPR |
随机森林 | 0.994 | 0.967 | 0.008 |
SVM | 0.994 | 0.967 | 0.008 |
然后我们对其他数据集进行测试验证:
数据集 | Precision | Recall | FPR |
APKPure 未参与训练的样本 | 0.0 | NAN | 0.018 |
MB | 1.0 | 0.878 | NAN |
VS2020 | 1.0 | 0.92 | NAN |
VS2021 | 1.0 | 0.89 | NAN |
假阳性率已降至可接受的水平。这个实验揭示了一个重要的现象:在训练集上获得理想的结果相对容易,但在现实世界中准确预测却可能面临挑战。无人能保证所收集的样本完美地反映了现实世界的情况,而我们的目标是识别那些真正与恶意软件(Malware)相关的特征。因此,我们决定尝试探索其他可能的解决方案。
1. 基于 Intents 和 Receivers 的训练
随后,我们扩展了特征集,加入了从 AndroidManifest.xml 中提取的 intents 和 receivers 信息进行训练,然而,这并没有提高模型的准确率。
2. 基于系统 API 调用的训练
我们进一步尝试提取 APK 中的所有系统 API 调用,将其转换为适合卷积神经网络(CNN)的格式,并通过 CNN 来训练模型。在训练集上,模型达到了令人满意的 97% 的准确率,但在数据集交叉验证时,表现仍然不尽如人意。
在这过程中,我们遇到了几个问题:、
- API 调用频率的不明显差异: 最初,我们通过反编译提取了所有出现过的 API 调用,却发现这些 API 的调用频率并没有明显差异。例如,我们原本认为 accessibilityservice 的调用明显与恶意软件相关,却发现在良性软件中也频繁出现。后来我们了解到,这主要是因为大多数 APK 都依赖于 android 这个库,而该库中包含了大量的系统 API 调用。由于 Malware 和 Benign APK 都依赖于大量的第三方库,这些库中存在大量的系统 API 调用,使得我们难以从系统 API 调用的统计结果中区分 Malware 和 Benign。即便我们使用了 incinerator 的 SCA 分析功能来检测和剔除这些第三方库,结果仍然不尽如人意。
- 第三方库的干扰: 我们发现,很少有研究考虑到第三方库的干扰,并提出剔除第三方库的具体方案。如果不剔除这些库,基于静态分析的方法几乎毫无意义,因为静态抽取会抽取出大量未被调用的 API,而这在 Malware 和 Benign APK 中没有明显区别。
- 反编译和脱壳问题: 由于这种方法涉及从 APK 中抽取系统 API 调用,需要进行反编译。然而,许多 Malware 都加壳处理,而脱壳是一个复杂的对抗技术。我们查阅的资料中,很少提到这一点。脱壳对于非专业团队来说可能太过困难,但至少应该从数据集中筛选出没有壳的 APK。如果不进行脱壳,直接抽取的话,只能得到极少数的 dexloader 等系统 API 调用,这大大影响了训练效果。
3. 回归基于 Permissions 的模型
鉴于前述的尝试未能取得预期效果,我们重新回到基于 Permissions 的模型,寻求通过其他方法提升交叉验证的准确率。我们进行了以下尝试:
- 通过 Select 模型选择 Permissions 采用此法的目的是寻找 Malware 实际所利用的 Permissions。然而,实际测试结果显示,训练准确率下降,验证准确率也下降,且交叉验证的准确率更是降低。
- 我们的实验过程如下: 使用 SelectFromModel 方法,基于 RandomForestClassifier 模型(该模型包含所有参与训练的数据)进行参数抽取。我们分别抽取了 100、50、30 个 Permissions 进行实验,并得到了如下数据:
- 选取 100 个 Permissions训练数据:
模型 | Precision | Recall | FPR |
随机森林 | 0.989 | 0.974 | 0.013 |
数据集 | Precision | Recall | FPR |
APKPure | 0.0 | NAN | 0.64 |
MB | 1.0 | 0.95 | NAN |
VS2020 | 1.0 | 0.96 | NAN |
VS2021 | 1.0 | 0.94 | NAN |
- 选取 50 个 Permissions训练数据
模型 | Precision | Recall | FPR |
随机森林 | 0.981 | 0.986 | 0.063 |
数据集 | Precision | Recall | FPR |
APKPure | 0.0 | NAN | 0.59 |
MB | 1.0 | 0.94 | NAN |
VS2020 | 1.0 | 0.96 | NAN |
VS2021 | 1.0 | 0.94 | NAN |
- 训练 30 个 Permissions训练数据
模型 | Precision | Recall | FPR |
随机森林 | 0.983 | 0.983 | 0.054 |
数据集 | Precision | Recall | FPR |
APKPure | 0.0 | NAN | 0.59 |
MB | 1.0 | 0.96 | NAN |
VS2020 | 1.0 | 0.96 | NAN |
VS2021 | 1.0 | 0.95 | NAN |
分析及新的尝试
从前述数据中可见,减少 Permissions 的数量并未能改善假阳性率或提高准确率。
- 利用自编码器(Auto Encoder)进行降维
- 为了进一步尝试改善模型表现,我们转向了自编码器(Auto Encoder)技术,期望通过对 Permissions 的分组和降维来提高准确率。自编码器是一种能够学习数据编码的神经网络,通常被用于降维或特征学习。我们的想法是通过自编码器将 Permissions 的高维数据转换为低维数据,同时保留与 Malware 识别相关的重要信息。
- 然而,尽管我们尝试了自编码器的降维方法,交叉验证的结果仍然不尽如人意,假阳性率依然较高。
模型 | Precision | Recall | FPR |
随机森林 | 0.977 | 0.980 | 0.074 |
数据集 | Precision | Recall | FPR |
APKPure | 0.0 | NAN | 0.64 |
MB | 1.0 | 0.95 | NAN |
VS2020 | 1.0 | 0.95 | NAN |
VS2021 | 1.0 | 0.92 | NAN |
通过业务逻辑选择 Permissions
随后,我们尝试通过业务规则来挑选适当的 Permissions。我们的方法是这样的:
- 我们统计了所有 Malware 中每个 Permission 的出现频率 mp 和所有 Benign 中每个 Permission 的出现频率 bp。
- 然后计算了 bp/mp
然而,这种方法也未能提高训练准确率和验证准确率。例如,android.permission.INTERNET 这样的权限在 Malware 和 Benign 中出现的概率非常接近,大约都在 97% 左右,这样的权限参与训练并没有太大的意义。类似地,android.permission.WAKE_LOCK 在 Malware 和 Benign 中出现的概率也非常接近,大约在 80% 左右。
我们还尝试了其他研究论文中提到的一些方法。经过测试,我们发现无论采取何种方法来筛选 Permissions,筛选后的训练准确率都不如不筛选、直接使用所有 Permissions 进行训练的准确率高。这个发现与许多将 Permissions 筛选作为主要研究目的的论文的结论相左。
结论
经过多次尝试,我们暂时未能训练出一个在单一数据集上训练,而在其他数据集上也具有理想准确率的模型。因此,我们决定将应用宝和 APKPure 的数据合并作为 Benign APK 的训练集,同时将其他几个 Malware 数据集也合并作为 Malware APK 的训练集,以提高样本的平均均衡度。
当然,我们也发现了一些可能的优化方向:
- 我们注意到 Malware 和 Benign 的 APK 签名存在一定的模式,如果能够验证这些模式,可以将其纳入现有模型中。
- 在手动分析样本时,我们发现许多 Malware APK 样本在静态分析阶段无法判断为恶意,因为它们的权限没有任何可疑信息。例如,许多 dropper、downloader 等类型的恶意 APK,在权限上与 Benign APK 没有明显区别。因此,人工筛选恶意 APK 可能有助于提高训练准确率。
- 同时,将动态检测的信息纳入训练模型也是一个值得尝试的方向。我们计划在后续的研究中加入动态信息以提升模型的表现。
原文链接:https://www.liansecurity.com/#/main/news/TfrG0IoBQKl-d7iA6Wuh/detail