目标:
给出区分一个未知好坏的APK,判断其是否是恶意apk。
方法:
传统的机器学习——朴素贝叶斯分类
环境:
python3 + numpy + androguard
主要步骤:
- 解析原始数据:使用androguard从apk文件中得到所有的权限数据和服务数据,并根据好坏分别保存到txt文件中,数据都保存为字符串形式。
- 转成数字数据:将字符串形式的数据装换成数字数据另存到csv文件中。
- 训练并测试数据:使用朴素贝叶斯分类方法,训练得到每个属性分别在(好类/坏类)中占的权重,再对带评估的apk分别进行P(该apk属于正常)和P(该apk属于恶意)的计算,哪个概率更大,则分为哪类。
- 保存结果:保存权重,得到判别模型。
具体细节:
- 在解析原始数据的过程中,用到了第三方的接口,很方便的提取出了每个apk包含的权限和服务,碰到无法解析的apk,记为未知apk,暂不做考虑,值得注意的是,只要是权限和服务两者之一无法解析的apk就视为未知apk,以保证数据的长度一致。同时对接口的到的数据进行简单的处理,权限使用字符串“permission”切割,保存最后一部分,服务使用“.”分割,也是保存最后一部分。
- 在解析原始数据的过程中,以每个apk为单位,得到了多个属性,且权限和服务分别保存,并统计所有apk中涉及到的全部权限和服务数据,并做成列表:
// 恶意apk的权限内容(bad.txt)
VirusShare_004f2f58a31e2375f2393c2f5bdc01ef:INTERNET,READ_PHONE_STATE,ACCESS_WIFI_STATE,ACCESS_NETWORK_STATE,WRITE_EXTERNAL_STORAGE,
...
// 恶意apk的服务内容(badapi.txt)
VirusShare_0054505d3d2eb2d2ec3f1a301d0c9c70:f,LMS,LMSK,
...
// 正常apk的权限内容(well.txt)
normal_apk_10_0:INTERNET,READ_PHONE_STATE,ACCESS_NETWORK_STATE,ACCESS_WIFI_STATE,WRITE_EXTERNAL_STORAGE,ACCESS_COARSE_LOCATION,ACCESS_COARSE_UPDATES,MOUNT_UNMOUNT_FILESYSTEMS,
...
// 正常apk的服务内容(wellapi.txt)
normal_apk_10_20:DownloadService,GameVpnService,DownloadService,PushService,DaemonService,
...
// 所有权限字段(all_permission.txt)
RECORD_VIDEO
NFC
...
READ_STEPS
READ_PHONE_STATE
// 所有服务字段(all_service.txt)
SyncAdapterService
UploadFtnTileService
...
LiveAlarmService
KeepLiveService
- 在转成数字数据过程中,以权限为例,将所有的权限字段作为属性,每个apk在其拥有的权限下记为1,得到权限矩阵(正常和恶意的分开处理,并把所有数据分为两部分:用作训练的apk数据和用作测试的apk数据)。同理可处理服务属性,值得注意的是,要保证训练apk和测试apk的划分一致。
- 根据训练数据,计算每个属性在正常apk中的概率和在恶意apk中所占的概率(即所占权重)。需要注意的是因为概率计算是连乘,所以需要避免0的出现,因此使用拉普拉斯校准,对每个属性值都加上一个很小的值(尽量小到在误差之内)。
- P(属于好) = P(好|总体) * P(权限属性1|好) ... P(权限属性n|好) * P(服务属性1|好) ... P(服务属性m|好),同理计算出P(属于坏),比较两个值得大小确定apk是否属于恶意。值得注意的是,因为概率的值都较小,且相互之间只需要进行大小比较,为了防止下溢出,所以用log函数对相乘进行处理:log(ab) = log(a) + log(b)。
# 拉普拉斯校准:x+1是处理特征数出现为0次的情况,会影响概率计算。
# 得到所有特征值为1的概率,当特征为0时,取1-plist_bad[x]或1-plist_well[x]即可
plist_bad = list(map(lambda x:(x+0.0000000000001)/len(list_bad),sum_bad))
- 对评估结果进行处理是,要区分“好的被分成坏的”和“坏的被分成好的”的情况。
总结:
在实际操作过程中,因为对于机器学习经验不足,在数据处理和数据构建过程中做了很多重复的工作,所以记下此篇文章记录经验。首先因为不明确哪类方法效果更好,所以可能在寻找合适的算法时频繁更换算法方面会有重复处理构建数据集的问题,因此在构建原始数据集时会出现疑惑:哪些数据是我需要的?我要得到什么样的数据类型?哪些数据会随着算法改动而变化?在获取原始数据时,尽量保存所有特征(目的是算法调整尽量不影响到数据处理)。数据处理过程中最麻烦的是重复调整,所以可以将数据处理分为:浅处理和深处理两个过程。浅处理的目标是尽量保证数据的初始状态;深处理的目标是尽量是数据适合算法计算。浅处理是在确定目标后就可以开始的工作,深处理是在明确使用的算法后进行的,大多数情况下,更换算法的过程需要调整的是深处理后的数据,而浅处理的数据依然可以使用。
源码地址:
https://github.com/JovanWang/Postgraduate/tree/master/apkclassify
网友评论