劉天一 周延森 崔見泉
(國際關系學院信息科技學院 北京 100091)
Android作為智能手機主流操作系統,其惡意軟件數量在移動惡意軟件中所占比重超過50%且快速上升。攻擊者將重新打包的應用程序作為其惡意行為的傳播媒介,降低了其本應自行開發的成本與難度,同時也利用了原合法軟件的受歡迎度和可信度。文獻[1-2]表明Android應用市場中5%~15%的應用是被重新打包過的。
國內外針對Android應用重打包的研究目前多集中在相似度比對上。Kim等[3]提出的RomaDroid工具使用最長公共子序列(LCS)算法來測量兩個應用程序之間的相似性;Hu等[4]提出了一種基于UI結構相似性的克隆程序檢測方法;Wu等[5]提出的MSimDroid 方法基于多維相似性,包括整個應用程序相似度、資源相似度、代碼相似度、聯合策略進行相似度計算;汪潤等[6]提出了一種基于深度學習的Android重打包應用檢測方法,并利用 Siamese LSTM 網絡學習程序的語義特征表示,實現重打包應用的檢測;沈月東[7]提出的Android重打包行為分析技術,通過進行非第三方庫代碼部分的API調用的統計和聚類,以應用對的形式檢測出重打包和被重打包的應用;熊鷹[8]提出的基于用戶角度的重打包檢查方法,通過用戶端特征提取以及服務端相似應用匹配實現重打包檢測。
基于相似度的重打包檢測方式面臨的最大問題是需要有足夠的數據集來對比分析,如未能與原合法應用程序匹配則難以判定,且基于相似度的軟件水印、軟件胎記多數只能作為知識產權侵權行為被發現后的追責依據,并不能從根本上解決剽竊、重打包攻擊等問題。同時,隨著軟件分析技術的發展,僅依靠相似度的重打包檢測為攻擊者繞過或欺騙檢測所設定的門檻與難度也在隨之降低。
1) Android逆向。Android應用程序通常由Java語言開發編寫,編譯成.class文件,轉換為一個可以在Android平臺的Dalvik虛擬機上運行的.dex文件,最后將字節碼.dex文件、描述權限信息等內容的AndroidManifest.xml文件、資源文件打包在一個.apk文件中。作為解釋型語言,Java高度抽象的特性也意味著其易被反編譯,隨之衍生出的逆向工具也在很大程度上降低了Android應用重打包行為的工作量。
其逆向流程如圖1所示,其中,Apktool是被最廣泛使用的開源APK逆向工程軟件,可以將Dalvik字節碼反編譯成.smali代碼,然后再生成App的重打包版本;Jadx或商用軟件JEB可以對.smali代碼進行直接處理與調試,并能展示出與源代碼幾乎相同的Java代碼;dex2jar可以借助baksmali等反匯編方式生成.jar文件進而解壓得到Java代碼。

圖1 dex文件逆向
2) Android重打包。Android應用程序的開發周期普遍較長,原軟件開發者付出了大量成本。然而,重打包App的成本普遍較低,難度也較小,圖2展示了Android應用程序重打包的基本流程。

圖2 Android應用程序重打包流程
應用程序開發者發布App,用戶通過Google Play或第三方應用市場下載軟件到移動設備,由于“下載”行為不存在身份鑒別,攻擊者同樣能夠以合法用戶身份從應用市場下載.apk文件到本地。通過自動化反編譯或人工分析,從.apk文件中能夠獲取到可讀性較強的.smali代碼、Manifest文件與資源文件等,并經由逆向工具進一步獲得接近于原程序的Java代碼。基于以上文件,攻擊者通過修改.dex代碼、lib庫或向其他資源文件添加惡意代碼片段或針對廣告進行增添或替換,將修改后的文件再通過Apktool等工具重新打包成.apk文件,使用官方的Android開源項目私鑰將重打包軟件簽名合法化,上傳到應用市場,誘導用戶下載使用。
重打包后的應用會保留一些特性,如與原App有一定程度上的代碼相似性、與原App有著不同的開發者簽名。應用市場多以此為依據,結合惡意行為分析和短時間段內的模擬運行,判別一個App是否安全和能否被發布。目前重打包的防御措施多集中于提升攻擊者的攻擊難度以及重打包行為發生后的判定上。
自解密代碼SDC(Self Decryption Code)是在程序特定分支中依賴于分支內常量通過加密或Hash等方式對代碼塊進行處理,保障語義等價的前提下重寫原分支,替換后僅可以通過動態運行實現自動解密恢復,文獻[9]論證了其可靠性的基礎理論依據。
在借鑒文獻[10-11]的基礎上,本文所設計的SDC結構如圖3所示。首先對條件分支中表達式的常量(記為w)使用不可逆的處理(如單向Hash)得到一個新常量es,以此實現對原常量w的隱藏。之后將常量w與實時計算生成的校驗碼c一同作為密鑰對分支中全部代碼和劃分后的部分水印信息進行加密操作,并用加密得到的亂碼形式代碼替換源代碼。

圖3 SDC結構
當運行到該分支時,程序會實時計算校驗碼并執行解密操作從而完成自動解密,還原源代碼和這部分的水印信息。其中變量v是程序運行到這一分支時變量中所存儲的值,理論上應與w相等,因而用同樣隨機串對變量v的值進行同樣處理,會得到一個與es相等的值,以上做到了對含有常量w的原表達式的等價轉換。
由于原常量w已經通過es的替換實現了不可逆的隱藏,且由原常量w生成es的過程存在著一個無法預測的隨機值,再加上Hash算法的單向性,從而提高了從es到w的還原難度,作為密鑰組成部分的w就成為了只有原開發者知道的信息。因此,預測常量w的方法一種是根據程序上下文語義結合數據流分析等方式合理推斷,但由于通過SDC算法轉換程序最后的呈現大部分是無實際意義的亂碼,難以完成單純的靜態分析;另一種是在動態運行過程中從變量v進行突破。
軟件水印是將特定數據w作為水印嵌入程序P中,得到一個其水印難以被輕易檢測和移除的新程序Pw。水印的目的不是阻止應用程序被非法使用,而是證明其所使用的軟件和算法的所有權,從而輔助知識產權權益保護、打擊盜版。水印分為靜態和動態、明顯可見和隱藏不可見,文獻[7]利用SDC構造的水印即屬于無須加以隱藏的動態軟件水印。
本文針對Android應用重打包檢測在軟件分析領域所面臨的挑戰,分析其檢測方式在目前可預計的規避策略,從而設計開發出更為可靠的重打包防御方案。
由于多數Android重打包檢測研究并未公開代碼和數據集,本文首先使用合法應用程序集借助混淆、自解密代碼等技術構造特定數據樣本,并簡要實現了基于代碼相似度的檢測算法,復現了WuFan、AndroidSOO等開源重打包檢測工具的檢測過程。
實驗具體流程如圖4所示。針對不同類型的重打包防御方式,論文相應地設計了不同的繞過檢測或妨礙防御的策略,以此來對重打包檢測算法進行有針對性的測試及分析。

圖4 實驗設計
本實驗數據集分為合法App、簡單處理的重打包App、利用混淆等處理意圖繞過檢測的重打包App三部分。其中,本文默認從Google官方應用市場下載得到的應用均為合法應用(實際上可能會存在約1.2%的重打包應用),對其進行簡單的逆向、修改和重打包后即構成了第二部分數據集,而構造第三部分數據樣本時的處理如下:
1) 混淆相關處理。本文首先對重打包程序進行基礎混淆操作,包括:① 名字改編,即將域名、方法名、類名、包名等有實際意義的標志符替換成無意義的相對較短的字符串。② 在不影響程序語義的前提下修改修飾符。③ 加入無效代碼對方法的實現結構進行調整。④ 方法參數轉換。⑤ 常量計算替換。
2) 自解密代碼構造。本文通過自解密代碼技術為意圖繞過重打包檢測的數據集構造提供進一步的輔助。SDC[10-11]作為一種有效的重打包防御方式,但本文認為其主要思想同樣也可以成為攻擊者對抗重打包檢測的技術之一。
本文在Java代碼層面,借助第二節中SDC的自加密-自解密框架和信息不對稱理論,實現了一個簡易版本的自解密代碼轉換器,其中,利用的單向函數為MD5,對稱加解密算法為DES,隨機串的添加在本文所編寫的md5enc方法中實現。
以程序1為例,其在Java代碼層面經過混淆、自解密代碼轉換等處理后得到的等價代碼如程序2所示,可以看出二者直觀結構呈現不同,但二者功能上并不存在差異,編譯運行后得到同樣的運行結果。
程序1原始代碼
while(k { if(x[k]= =1) R=(s*y)%n else R=s; s=R*R%n; L=R; k++; } return L; 程序2經過混淆、自解密代碼轉換等處理后的代碼 int next=0; for ( ; ; ) { switch(md5enc(next)) { case “4548cce2e2d7fbdea1afc51c7c6ad26”: k=Integer.parseInt(desdec(String.format("%08d",next),"nISR6pPU35Y=")); s=Integer.parseInt(desdec(String.format("%08d",next),"B/4RM7/980M=")); next=Integer.parseInt(desdec(String.format("%08d",next),"B/4RM7/980M=")); break; case "aab3238922bcc25a6f606eb525ffdc56": s=R*R%n; L=R; k++; next=Integer.parseInt(desdec(String.format("%08d",next),"4km57CcZvD8=")); break; …… case "9bf31c7ff062936a96d3c8bd1f8f2ff3": return L; 另一方面,對于較為復雜的程序,本實驗利用開源的混淆工具,從編譯器層面而非直觀的代碼層面進行混淆等處理。 檢測算法的主要思想是在開發者簽名不同的前提下對于一個從非官方渠道獲取的未知來源的App,通過在已知是合法、非重打包的眾多數據集中逐一兩兩進行相似性比對,計算其相似度。相似度越高(即越接近1.0)則說明這個未知來源的App是重打包的可能性更大,相似度最高值所對應的合法App被認定為其重打包的對象。 本文利用前文所構造的數據樣本對基于相似度的重打包檢測算法進行對抗測試,具體步驟為: 1) 從可靠性較高的應用市場隨機選取.apk文件(記作app-ori)下載到本地。 2) 借助Apktool工具對.apk文件進行解包與反編譯,如圖5所示。 圖5 對.apk文件進行反編譯與重打包 3) 使用逆向工具得到Java代碼。 4) 添加或修改代碼片段得到文件re1。 5) 對re1采用前文所述混淆等方法進行轉換,用于妨礙重打包檢測,得到re2。 6) 使用Apktool分別對re1、re2重打包生成.apk文件app-re1、app-re2。 7) 將生成的兩個.apk文件分別放入重打包檢測系統中檢測,分別記錄各系統關于是否為重打包應用所做出的判定。 8) 通過Android Studio平臺模擬器驗證應用程序本身功能完整性是否被破壞。 9) 對檢測算法的表現進行評估與分析。 上述相似度重打包檢測步驟如圖6所示。 圖6 相似度重打包檢測流程 實驗主機為:CPU Intel Core i5 @2.30 GHz和8 GB的RAM。由于一個完整的Android應用規模較大,包含上萬個文件,盡管本文復現算法時已盡可能簡化了檢測過程,基于相似度的檢測算法仍需數小時的判定時間。基于此我們僅在小規模測試集中實驗,針對實驗的分析主要基于代碼層面。 圖7展示了重打包文件與原.apk文件的相似度得分(即Similarity),若作者簽名不同而相似度很高則可以判定其是重打包應用。 圖7 計算兩個.apk文件的相似度 本實驗默認app-ori為合法應用,將其作為基準分別計算app-re1和app-re2與該應用的相似度,從而對二者是否為重打包程序進行判斷。通過對比針對同一app-ori[i]的兩個不同重打包版本app-re1[i]與app-re2[i]在檢測中表現出來的差異,以及進一步統計檢測系統在不同情況下的漏報率,可以推測出本文在構造特定重打包行為時所采取的混淆、自解密代碼轉換等技術對重打包檢測算法所造成的影響。 實驗結果如表1所示,本文構造數據樣本時混淆等處理降低了重打包應用與原應用的相似度,使其低于重打包攻擊行為的判定閾值,從而在一定程度上欺騙了檢測系統。本文所復現的檢測算法沒有針對代碼以外的信息進行處理,將兩個包括作者簽名在內完全相同的.apk文件(其相似度高達1.0)判定為重打包,而Wu Fan可以對.apk文件的簽名做出識別,將其正確判定為作者相同,即“非重打包”,如圖7所示。但現實中Android應用市場在正式發布應用前都至少會對其簽名進行最基本的驗證與校對,驗證時即可獲知作者信息,因此對持有相同作者信息的App重打包判定可暫不作考慮。 表1 檢測性能對比 針對于僅完成了重打包的.apk文件,基于相似度的檢測算法均能以很高的準確率檢測出其重打包行為(本實驗在重打包過程中僅采取較為簡單的人工修改或添加,且判定閾值設置較低,真實情況不一定會達到如表1所示百分之百正確率和零漏報率)。針對本實驗處理后的重打包測試樣本,其與原文件的相似度數值呈明顯降低。實驗結果顯示混淆、自解密代碼轉換等方法使得多數重打包.apk與原.apk文件的相似度降至基于代碼相似度算法的判定閾值之下,從而存在很大概率可成功繞過此類型的重打包檢測。 上文分析了軟件分析技術為目前被廣泛應用的三種重打包檢測方法所帶來的影響,基于此,本文綜合了以SDC等技術為依據的檢測或防御算法,在此基礎上提出一種改進的重打包防御框架,如圖8所示。 圖8 重打包攻擊防御系統框架 Android應用開發者在編寫完程序代碼后: 1) 將源代碼進行自動化程序分析,其環境與軟件測試保持一致即可,在這個過程中:① 對程序結構進行一定的轉換與優化,使之便于后續的水印嵌入和SDC生成,同時也起到混淆的作用,從而降低程序的可讀性;② 對可利用的分支語句進行標記,如程序規模較小則利用不透明謂詞添加可利用的分支。 2) 構造水印信息并進行切分和壓縮等處理。 3) 結合自解密與自防御算法,將水印嵌入程序,同時對代碼進行加密處理,生成自解密代碼。 4) 將代碼與資源等文件打包、簽名和上傳到應用市場待審核。 隨后,權威Android應用市場會對App進行初步檢測,在模擬環境下進行運行測試。在測試過程中運行到SDC時,正常情況下程序會自動進行解密還原,若無法進行解密則顯然會因為亂碼從而導致程序運行崩潰,此時權威應用市場即可根據程序運行錯誤的提示判定該App有缺陷或有被重打包的可能,拒絕發布該應用。而通過了初步檢測以及模擬運行測試的App會被發布到Android應用商店供用戶下載。 用戶從應用商店等多種渠道下載App到智能移動設備上,若該應用為合法應用,程序會逐步自動解密還原,用戶可以在沒有額外附加感受的前提下正常使用;若該應用是被重打包過的,程序存在很大的概率會在運行到某處時由于自解密失敗而崩潰。此時該程序便無法繼續運行,在一定程度上阻止了該重打包應用繼續危害用戶設備的可能,程序的崩潰也為移動設備使用者發出了該應用可能存在問題的警示,用戶可以采取卸載程序以及舉報該程序等行為。Android應用市場收到用戶的反饋后會對該可疑應用進行進一步篩查和更細致的審計。若該App僅為運行錯誤則提示更新修復,若該App確實存在惡意行為則下架該應用并對發布者進行一系列懲罰。如果該應用為惡意的且已經對移動設備使用者造成了損失,則需要進一步借助水印中所攜帶的信息來判定該應用是否為重打包以及責任歸屬問題。 由于自防御代碼[2]意圖以程序崩潰作為重打包的代價從而阻止重打包攻擊,而自解密代碼則是借助SDC嵌入軟件水印[7],我們希望可以通過優化水印的構造方式來降低嵌入的成本,從而將二者結合,既可以實現讓重打包App自動暴露以達到防御效果,又可以在重打包攻擊發生后通過水印所攜帶的作者信息、發布信息等進行版權保護或惡意行為的責任判定。同時在此基礎上結合其他重打包檢測與防御系統的優勢設計出一個更為可靠的防御框架。 經過處理后的SDC既可以在水印與載體代碼之間建立內在依賴,將二者加密為一個SDC段,從而更好地將軟件水印融合到程序之中,并提升攻擊者移除或篡改水印的成本;又可以利用程序完整性校驗碼等構造密鑰以實現重打包應用的自動化防御;在此基礎上引入的加密算法,作為一種重要的混淆技術,也在一定程度上提升了程序的復雜性,使得攻擊者閱讀代碼和重構代碼更加困難。 隨著軟件分析領域的發展,程序綜合等技術使得條件分支語句也就是初始SDC的各個“入口”是可以以自動化分析的形式找到并基于概率求解的,這使得攻擊者以低于重開發的成本重打包一個被SDC保護的Android應用成為了可能。因此,我們的框架在SDC生成前加入一個步驟,先對源程序進行程序分析以及類似于混淆技術的代碼轉換處理,以此來增加攻擊者自動化求解的難度。 本框架的優勢之一是讓Android應用程序開發者、移動設備使用者、Android應用市場三方全都參與到重打包的防御中來。開發者可以以自身的操作對代碼加以保護從而從根本上阻礙他人的剽竊行為,而不是將版權保護寄托于檢測能力參差不齊的第三方應用市場、在他人重打包攻擊行為發生后才進行耗時耗力的追責;用戶也可以通過程序的運行崩潰感知重打包行為,從而阻止惡意應用繼續存在于移動設備之上。 軟件分析技術的發展既使攻擊者繞過檢測、對抗防御、降低攻擊成本成為了可能,同時也為重打包防御提供了提升的空間。本文分析了目前常見的重打包檢測算法,構造了特定數據樣本及繞過檢測的策略進行測試,并基于此設計一個綜合的重打包防御框架。本文的不足之處在于,沒有對提出的方案進行完整的實現與測試評估,僅通過第二節中實驗所得出的結論來輔助驗證改進設計的合理性,且僅在代碼層面而非編譯器層面實現了SDC。2.3 實驗及結果分析




3 Android重打包攻擊防御的改進
3.1 系統框架

3.2 改進分析
4 結 語