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閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容