Python之利用机器学习检测安卓恶意软件实现(一)

前言

上一篇文章写了如何使用Python写一个简单的爬虫,批量抓取APK的下载链接。这篇文章记录下如何批量拆包APK文件并提取想要的信息。

准备工作

  • Androguard环境部署:Androguard下载
  • 在上一篇文章提到的准备工作的基础上,这篇文章需要加入Androguard作为环境。Androguard是一款开源的Android应用程序分析工具,使用Python编写。众多功能模块以Python包的形式存在。
  • 使用方法:首先将GitHub上的Androguard项目下载下来。
下载Androguard.png

下载完成后得到一个压缩包,解压后进入目录,把Androguard目录下所有的文件拷贝至Python的根目录下,合并同名文件夹即可。

  • 检查环境是否部署成功:
    打开cmd命令行,输入python进入交互状态。输入from androguard.core.bytecodes import apk, dvm如下图所示没有提示任何错误信息即可。
检查环境.png

注意:在cmd下直接调python命令行需要将Python加入到环境变量中。

基础知识

首先APK文件可以用普通解压缩的方式拆包,如下图。

解压完毕.png

熟悉安卓开发的人肯定对解压完毕后的文件很熟悉。这里主要介绍部分文件的作用。

  • 1.assets文件:这里存放一些资源文件入图片等,一半情况下解压缩完毕后是可以直接看到这些图片的。
assets.png
  • 2.lib文件:这里存放安卓开发中使用到的库文件
库文件.png
  • 3.AndroidManifest文件:这是我们这次需要关注的重点。一个安卓应用需要申请的权限信息,以及Activity等组件的注册信息都需要在AndroidMainfest.xml文件中声明。但是直接解压后的AndroidManifest文件查看确是如下这种情况:
乱码.png

没错,是乱码。这就说明仅仅使用将APK解压缩的形式去获得我们关心的信息是不可行的。

使用Python获取APK信息

到此为止,相信大家对APK的结构有了一定了解。下面以获取APP申请权限为例子使用Python完成APK的拆包提取信息。

  • 首先附上Androguard开发文档:Androguard开发API
  • Androguard是开源的,有兴趣的朋友可以去阅读源码。这里不过多赘述Androguard实现原理,我们从目的入手,直接使用Androguard。
  • 首先在新建的Python工程中引包from androguard.core.bytecodes import apk, dvm
  • 接着调用APIapp.get_permissions()
  • 没错,Androguard就是这么强大,一个API就完成了拆包提权操作。那么为了实现批量拆包提权(以及提取其他信息),我们必须自己编写一个Python脚本。
  • 思路很明了,利用Python写一个遍历文件夹中所有文件的脚本,对每个apk文件执行相应的操作即可。为了让脚本清晰,这里把调取API和遍历文件夹放在两个脚本中。
    首先附上调用Androguard中API获取各种信息的代码:
__author__ = 'Administrator'
#coding=utf-8
from androguard.core.bytecodes import apk, dvm
from androguard.core.analysis import analysis
import re
global count
count = 1

def get_permissions(path, filename):
    str = "Permission:"
    app = apk.APK(path)
    permission = app.get_permissions()
    file = permission
    print permission
    writeToTxt(str, file, filename)
    return permission

def get_apis(path, filename):
  app = apk.APK(path)
  app_dex = dvm.DalvikVMFormat(app.get_dex())
  app_x = analysis.newVMAnalysis(app_dex)
  methods = set()
  cs = [cc.get_name() for cc in app_dex.get_classes()]

  for method in app_dex.get_methods():
    g = app_x.get_method(method)
    if method.get_code() == None:
      continue

    for i in g.get_basic_blocks().get():
      for ins in i.get_instructions():
        output = ins.get_output()
        match = re.search(r'(L[^;]*;)->[^\(]*\([^\)]*\).*', output)
        if match and match.group(1) not in cs:
          methods.add(match.group())

  methods = list(methods)
  methods.sort()
  print "methods:"+"\n"
  print methods
  str = "Methods:"
  file = methods
  writeToTxt(str, file, filename)
  return methods
def get_providers(path, filename):
    app = apk.APK(path)
    providers = app.get_providers()
    print "providers:"+"\n"
    print providers
    str = "Providers:"
    file = providers
    writeToTxt(str, file, filename)
    return providers
def get_package(path, filename):
    app = apk.APK(path)
    packname = app.get_package()
    print "packageName:"+"\n"
    print packname
    str = "PackageName:"
    file = packname
    writeToTxt(str, file, filename)
    return packname
def get_activities(path, filename):
    app = apk.APK(path)
    activitys = app.get_activities()
    print "ActivityName:"+"\n"
    print activitys
    str = "Activitys:"
    file = activitys
    writeToTxt(str, file, filename)
    return activitys
def get_receivers(path, filename):
    app = apk.APK(path)
    receivers = app.get_receivers()
    print "Receivers:"+"\n"
    print receivers
    str = "Receivers:"
    file = receivers
    writeToTxt(str, file, filename)
    return receivers
def get_services(path, filename):
    app = apk.APK(path)
    services = app.get_services()
    print "Services:"+"\n"
    print services
    str = "Services:"
    file = services
    writeToTxt(str, file, filename)
    return services
def writeToTxt(str, file, filename):
    global count
    fm = open('%d'%count+'.txt', 'w')
    #fm.write(str)
    #fm.write("\n")
    for i in file:
        tmp = i.split('.')
        final = tmp[-1]
        fm.write(final)
        fm.write("\t")
    fm.close()
    count += 1

def main(path, apkname):
  get_permissions(path, apkname)
  #get_apis(path, apkname)
  #get_providers(path, apkname)
  #get_package(path, apkname)
  #get_activities(path, apkname)
  #get_receivers(path, apkname)
  #get_services(path, apkname)

if __name__ == '__main__':
    path = "D:/sample/Good"
    filename = "sampleInfo.txt"
    main(path, filename)

  • 上面代码中,witeToTex函数将调用API所得到的结果保存在txt文件中,以便查看和日后使用。get_XXXX函数就是获取apk文件中对应的信息,其中get_permissions获取apk中申请的权限,get_apis获取一些api调用信息,顾名思义,get_XXX就获取XXX。
  • 再看如何遍历,这里使用Python 的os.walk遍历目录:
    os.walk(top, topdown=True, onerror=None, followlinks=False) 可以得到一个三元tupple(dirpath, dirnames, filenames), 第一个为起始路径,第二个为起始路径下的文件夹,第三个是起始路径下的文件。dirpath代表目录的路径,dirnames包含了dirpath下所有子目录的名字。filenames 包含了非目录文件的名字。
  • 遍历存放众多APK的文件夹,对每个APK文件进行相应操作,代码如下:
__author__ = 'Administrator'
#-*- coding:GBK -*-
import os
import os.path
import sys
import subprocess
import getFeatures

rootdir = "D:/Sample/Good//"
destdir = "D:/Sample/workSample/badDone//"
command = "java -jar D://apktool.jar"
class Packages:
    def __init__(self, srcdir, desdir):
        self.sdir = srcdir
        self.ddir = desdir
    def check(self):
        print("--------------------starting unpackage!---------------------")
        for dirpath, dirnames, filenames in os.walk(rootdir):
            for filename in filenames:
                thefile = os.path.join(dirpath, filename)
                apkfile = os.path.split(thefile)[1]
                apkname = os.path.splitext(apkfile)[0]
                print apkfile
                try:
                    if os.path.splitext(thefile)[1] == ".apk":
                        # name = os.path.splitext(thefile)[0]
                        str1= '"'+thefile+'"'
                        str2= '"'+destdir + os.path.splitext(filename)[0]+'"'
                        # cmdExtract = r'%s d -f %s %s'% (command, str2, str1)
                        getFeatures.main(thefile, apkname)
                        print "******************well done******************"
                except IOError, err:
                        print err
                        sys.exit()

if __name__ == "__main__":
    dir=Packages(rootdir, 'e:/')
    dir.check()
  • 上面这个脚本引入文章中第一个脚本作为模块,共同实现批量拆包提取特征并输出到txt文件中的功能。这里用正则表达式对提取出的权限特征进行处理,去掉冗余部分,仅保留关键字段,并把每个apk文件对应的权限特征输出到各自的txt文本中。
程序运行.png
  • 这里APK用以编号,以方便后面查找对比。输出的最终结果如下图:
处理前.png
输出的txt.png
  • 将权限信息取冗余后,写入到txt文件中,以tab键进行分离,方便后面使用。
txt中权限.png

总结

到此为止,我们就把安卓中的权限信息提取出来了。这为后面使用机器学习方式对安卓应用进行检测提供了基本的数据。在接下来的文章中将会进一步介绍如何使用Python实现机器学习的方式检测安卓恶意应用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容