李萍
(廣東省輕工業(yè)技師學(xué)院,廣州 513000)
Android應(yīng)用防篡改機(jī)制的研究
李萍
(廣東省輕工業(yè)技師學(xué)院,廣州 513000)
面對開發(fā)者所編寫的Android應(yīng)用被第三方惡意破解、篡改、盜版的現(xiàn)狀,為了找出如何保護(hù)Android應(yīng)用的機(jī)制,先從篡改者的攻擊手段入手,分析應(yīng)用篡改的基本原理,結(jié)合Android系統(tǒng)自身的相關(guān)機(jī)制,針對性地提出如何保護(hù)應(yīng)用的防御手段和檢測手段,同時也說明這些技術(shù)手段的局限性以及引起局限性的根本原因,最終提出了針對一般破解者的防御策略。
Android應(yīng)用;防篡改;機(jī)制
當(dāng)前Android系統(tǒng)占據(jù)了智能系統(tǒng)市場的主要份額,但其盜版問題日益嚴(yán)重,影響了開發(fā)者的收益,推動了惡意木馬的傳播,惡化了整個應(yīng)用的生態(tài)圈。本文著重分析Android應(yīng)用被篡改的主要手段和機(jī)制,結(jié)合之前已有的保護(hù)手段,進(jìn)一步研究更加有效的應(yīng)用保護(hù)機(jī)制。
分析篡改機(jī)制之前,首先需要對Android應(yīng)用的打包機(jī)制和包結(jié)構(gòu)做一些簡單的說明。
(一)Android打包機(jī)制說明
Android的安裝包稱為APK(android package file)的縮寫。APK文件是標(biāo)準(zhǔn)的Zip文件,構(gòu)造方式和JAR文件類似,包含一個Android應(yīng)用運(yùn)行所需的執(zhí)行文件、動態(tài)鏈接庫、資源文件、證書、清單文件,即:
1.AndroidManifest.xml:清單文件
2.Lib目錄:存放動態(tài)鏈接庫(so)文件
3.META-INF:簽名信息的存放目錄
4.res:資源存放目錄(布局、圖片、字符串)
5.Classes.dex:DEX格式的可執(zhí)行文件
6.Resources.arsc:編譯后的二進(jìn)制資源文件
Android的應(yīng)用開發(fā)主要使用兩種語言:Java和C/C++,前者用于構(gòu)造應(yīng)用的主體,后者也是Android中NDK(native develop kit)所使用的語言,主要用于生成動態(tài)鏈接庫(so)。此外還有AIDL(Android Interface definition language),用于編寫進(jìn)程間通信用的接口文件。
Android應(yīng)用打包過程就是將以上相關(guān)代碼和文件編譯整合的過程[1]:
1.通過aapt工具打包資源文件,生成R.java
2.編譯AIDL生成java文件
3.編譯所有Java代碼,生成class文件
4.通過dx工具轉(zhuǎn)換class文件為一個dex文件
5.將資源、清單、dex、so統(tǒng)一打包為apk文件
6.通過jarsigner選擇證書對apk簽名
7.使用zipalign對apk做對齊操作
可以看到,APK文件結(jié)構(gòu)是公開、易于分析修改,對于資源文件完全沒有保護(hù),因此也就為篡改應(yīng)用打開了方便之門。
(二)篡改應(yīng)用的手段
針對APK文件的篡改,通常有以下做法:
1.替換資源:由于APK文件中對于資源文件未做任何保護(hù),篡改者可以輕易獲取所有資源文件,找到對應(yīng)的圖片、文字等信息,將其替換,從而使得應(yīng)用改頭換面。
2.修改實(shí)現(xiàn):對Dex文件通過反編譯等手段,定位到關(guān)鍵業(yè)務(wù)代碼,修改判斷條件分支,使原有邏輯失效。這種一般用于游戲應(yīng)用破解,繞開注冊檢查、計(jì)費(fèi)檢查等,生成所謂破解版,使開發(fā)者利益受損。
3.代碼注入:通過靜態(tài)注入代碼等手段,修改和替換原有業(yè)務(wù)邏輯。常見的篡改方式有:替換原有廣告為自己的,加入惡意扣費(fèi)代碼、木馬數(shù)據(jù)、遠(yuǎn)程下載數(shù)據(jù),竊取隱私數(shù)據(jù)。這種篡改的危害很大,不但開發(fā)者收益受損,還威脅到使用者的信息安全。這里篡改的核心技術(shù)手段就是對Dex文件的反編譯和修改,而第三方工具的提供,使得這項(xiàng)工作的難度大為降低,甚至可以自動進(jìn)行。
(三)通過反編譯手段靜態(tài)分析應(yīng)用
常見的反編譯工具主要有:
1.Apktool:Google官方提供的一款反編譯和打包工具,以java實(shí)現(xiàn),通過jar包提供使用。該工具可以將APK直接反編譯為smali文件,還可以將修改后的文件重新打包為APK。
2.Dex2Jar:Dex2Jar是針對APK文件中的可執(zhí)行文件classes.dex進(jìn)行反編譯,并生成為jar文件的工具。它的優(yōu)勢是,直接將dalvik字節(jié)碼轉(zhuǎn)換為更具有可讀性的java字節(jié)碼,然后就可以通過第三方j(luò)ava字節(jié)碼的反編譯工具來閱讀和理解。
反編譯命令:
反編譯完成后,可以使用jd-gui等java反編譯工具來直接查看閱讀代碼。
3.Baksmali/Smali:用于將classes.dex反編譯為smali文件,以及將smali文件反編譯為classes.dex文件。
反編譯命令:
重編譯命令:
(四)動態(tài)分析應(yīng)用
反編譯獲取的smali文件或者jar文件在應(yīng)用邏輯復(fù)雜的情況下,很難快速定位和分析,因此篡改者往往會運(yùn)行應(yīng)用,通過以下手段來動態(tài)分析:
1.日志分析:通過adb logcat可以查看應(yīng)用的輸出日志,如果應(yīng)用未輸出日志,則可以通過代碼注入的方式在所需分析的smali文件中加入打印日志語句來獲取所需信息。
2.動態(tài)調(diào)試:使用IDA Pro、gdb等工具動態(tài)加載應(yīng)用,并動態(tài)調(diào)試(設(shè)置斷點(diǎn)、單步跟蹤、查看寄存器數(shù)據(jù)等)。
根據(jù)Android官方文檔說明,如果需要調(diào)試Android應(yīng)用,需要滿足以下兩個條件之一:AndroidManifest.xml中的Application標(biāo)簽節(jié)點(diǎn)具備屬性:android:debuggable=”true”或系統(tǒng)default.prop文件中的ro.debuggable的值為1。見圖1。
目前Android對開發(fā)者提供了基本的保護(hù)手段:代碼混淆。它是Java代碼的傳統(tǒng)保護(hù)機(jī)制,不但可以降低代碼在反編譯后的可讀性,還可以減少應(yīng)用的大小,提高運(yùn)行效率,可以說是一舉多得。Android開發(fā)環(huán)境從2.3版本后集成了Proguard作為混淆工具,打開開關(guān)即可完成默認(rèn)配置的混淆效果[2],見圖2。
此外,第三方也提供了一些加強(qiáng)版的混淆工具(如DexGuard、Allatori),不但可以對函數(shù)名、類名、變量名做混淆,還可以對其中的字符串做混淆,將調(diào)用改為反射調(diào)用,對資源加密等。但這些工具一方面要收取不菲的費(fèi)用,另一方面,仍然只是降低了可讀性,并未完全保護(hù)應(yīng)用。見圖3。
鑒于Android自身的保護(hù)機(jī)制的不完善,這里進(jìn)一步提出其他防篡改的機(jī)制:
(一)檢測機(jī)制:
1.校驗(yàn)簽名:檢查Android的簽名機(jī)制是檢測應(yīng)用有無被篡改的最有效手段。由于簽名證書的安全性,私鑰不會公開,第三方也無法獲取私鑰,從而無法偽造證書簽名,只能使用其他證書進(jìn)行簽名。因此,只要在運(yùn)行時校驗(yàn)當(dāng)前應(yīng)用的簽名證書是否是原始證書即可,當(dāng)然原始證書的信息(公鑰信息)也可以保存在服務(wù)器端,通過遠(yuǎn)程驗(yàn)證方式來進(jìn)一步確保其安全性。
APK的簽名信息保存在META-INF目錄的RSA文件中。校驗(yàn)簽名的思路是:應(yīng)用啟動后,從安裝后的APK文件中讀取RSA文件,并從中拿到證書信息,然后與正確的證書信息比對,以下代碼是讀取RSA文件簽名的代碼示例:
2.校驗(yàn)應(yīng)用指紋:通過校驗(yàn)APK的HASH值來確保應(yīng)用未被非法修改。從系統(tǒng)路徑找到應(yīng)用對應(yīng)的APK,通過PackageManager可以得到APK的路徑,對APK文件計(jì)算HASH值,如對APK全文做MD5計(jì)算,將結(jié)果送到后臺進(jìn)行比對,比對成功后,繼續(xù)業(yè)務(wù)邏輯。
3.檢測運(yùn)行環(huán)境是否處于虛擬機(jī):篡改者的一種策略是在PC上的Android模擬器中運(yùn)行被攻擊應(yīng)用,由于模擬器的環(huán)境可以任意修改,使得篡改者可以擁有更多的權(quán)限和信息。那么可以在應(yīng)用啟動時,加入相關(guān)的檢測邏輯,一旦檢測到當(dāng)前環(huán)境處于模擬環(huán)境,則立刻退出應(yīng)用。由于Android模擬器運(yùn)行時主要依賴QEMU這個工具,所以可以檢查當(dāng)前進(jìn)程或者系統(tǒng)變量是否包含相關(guān)信息。
以下的偽代碼是通過獲取系統(tǒng)的屬性ro.kernel. qemu來判斷當(dāng)前是否是模擬器。
(二)靜態(tài)防御機(jī)制:
1.破壞反編譯機(jī)制:其思路是,針對常見的反編譯工具,構(gòu)造使其不能正常工作的代碼,導(dǎo)致其反編譯失敗。通過測試大量反編譯APK文件,可以找出能夠讓反編譯工具無法正常工作的場景,然后根據(jù)此時產(chǎn)生的錯誤信息,找到線索來重現(xiàn)異常,并將這種機(jī)制放在自身代碼中。但這種做法有一定的局限性:即尋找反編譯工具的漏洞過程比較漫長,且結(jié)果不確定;對于開發(fā)者的要求較高;反編譯工具會不停地演化升級,原有的破壞機(jī)制逐漸失效,需要尋找新的破壞機(jī)制。
2.NDK機(jī)制:NDK是android提供的一套Native語言開發(fā)工具包,也就是使用C/C++編寫業(yè)務(wù)代碼的開發(fā)包。開發(fā)者使用NDK編寫代碼,生成so為擴(kuò)展名的動態(tài)鏈接庫,然后在Java層通過JNI調(diào)用so文件中的函數(shù)方法。
NDK機(jī)制的保護(hù)力度比代碼混淆要高得多,但它的缺點(diǎn)也很明顯:即增加開發(fā)成本:開發(fā)人員必須要學(xué)習(xí)C/C++語言,并編寫相關(guān)的實(shí)現(xiàn);保護(hù)力度有限:只能針對核心業(yè)務(wù)邏輯(與界面無關(guān)),比如加解密、敏感數(shù)據(jù)、核心算法等進(jìn)行保護(hù)。見圖4。
(三)動態(tài)防御機(jī)制:
1.防止動態(tài)調(diào)試機(jī)制:Gdb等調(diào)試工具的原理是通過系統(tǒng)調(diào)用ptrace來注入到進(jìn)程中,從而實(shí)現(xiàn)動態(tài)調(diào)試。為了防止動態(tài)調(diào)試,在應(yīng)用啟動時立刻Ptrace自身,這樣如gdb等工具就無法成功ptrace應(yīng)用,從而無法調(diào)試和動態(tài)注入。防御的相關(guān)實(shí)現(xiàn)需要放在so文件的JNI_OnLoad方法中,應(yīng)用啟動后立刻加載so文件,一旦加載,該邏輯立刻執(zhí)行。
2.加殼機(jī)制:對于一個Android應(yīng)用來說,主業(yè)務(wù)邏輯是保存在classes.dex中,可以將真實(shí)的classes. dex文件事先加密保存,而在運(yùn)行之后,解密DEX文件,然后動態(tài)加載入內(nèi)存運(yùn)行。這種做法會使得篡改者針對應(yīng)用的靜態(tài)分析手段失效。為了保證安全性,主要的業(yè)務(wù)邏輯均需要以NDK編寫,并在JNI_OnLoad方法中實(shí)現(xiàn)。
具體實(shí)現(xiàn)上,加殼流程(見圖5)如下:
*編寫StubApplication,從Application類繼承,代碼主要完成脫殼的操作
*修改原應(yīng)用的清單文件,將其聲明的Application入口改為StubApplication將原應(yīng)用的classes.dex文件通過加密后放在assets目錄下,如果需要對資源加密,可以做類似處理
*將Stub相關(guān)文件實(shí)現(xiàn)編譯為smali或者so
*重新打包
脫殼時首先解密文件,然后通過Android框架提供的動態(tài)加載類DexClassLoader[3],解密后的dex文件同時還需要通過反射機(jī)制修改當(dāng)前內(nèi)存中相關(guān)變量,主要是將當(dāng)前應(yīng)用的ClassLoader替換為DexClassLoader。此外,還需要將Application對象替換為原Application對象。
Dex文件的加殼機(jī)制相對以上的其他防御機(jī)制來說是更有效的手段,第三方很難使用靜態(tài)分析的手段來破解應(yīng)用邏輯。但由于Dex文件在應(yīng)用運(yùn)行時被Dalvik虛擬機(jī)加載到內(nèi)存執(zhí)行,因此攻擊者可以通過運(yùn)行Dump內(nèi)存的手段,將含有Dex文件的內(nèi)存數(shù)據(jù)全部存儲到文件中,然后通過找到Dex文件的Header以及文件長度偏移量,利用dd等工具將Dex文件從中摳取出來,從而獲得了未加密的原始Dex文件。具體的破解步驟如下:
*在設(shè)備中運(yùn)行目標(biāo)應(yīng)用
*在設(shè)備上運(yùn)行g(shù)db,并指向目標(biāo)應(yīng)用的進(jìn)程ID:gdb-pid=xxx
*通過gcore dump出整個進(jìn)程內(nèi)存,轉(zhuǎn)儲為一個二進(jìn)制文件
*在PC上使用工具查看該文件,并查找Dex文件頭部(匹配字符串:dex?035)
*使用dd來摳取數(shù)據(jù):
(四)虛擬機(jī)保護(hù)機(jī)制
由于Android的自身機(jī)制決定可以通過動態(tài)注入的方式來獲取原始Dex文件,所以理論上可以通過修改Dalvik虛擬機(jī)生成自己私有的虛擬機(jī)模式,在虛擬機(jī)這一層來做Dex文件的加解密,可以在內(nèi)存中保護(hù)Dex文件,甚至可以使得Dex文件動態(tài)組裝、動態(tài)修改,使得攻擊者無法通過dump或者注入的方式獲取真實(shí)的Dex文件。這種機(jī)制理論上是最安全的保護(hù)機(jī)制,但其問題也很明顯,即對Android的兼容性,由于Android 5.0開始,ART取代了Dalvik虛擬機(jī)模式,即APK在安裝后就會被預(yù)先編譯成本地可執(zhí)行的機(jī)器碼,而不再采用解釋執(zhí)行的虛擬機(jī)模式,從而提高了運(yùn)行效率。而ART模式也決定了通過對Dex文件動態(tài)組裝的虛擬機(jī)保護(hù)模式無法走通。
Android系統(tǒng)具有開放性和強(qiáng)大的擴(kuò)展性,但其安全性尤其是對應(yīng)用的保護(hù)方面差強(qiáng)人意。開發(fā)者通過混合使用本文中靜態(tài)防御、動態(tài)防御、檢測機(jī)制,可以提高破解、篡改者的技術(shù)門檻和篡改成本。但由于Android自身的機(jī)制決定,現(xiàn)有的保護(hù)手段都存在對應(yīng)的破解方法。一方面,應(yīng)用的保護(hù)機(jī)制越來越深入底層,才能應(yīng)對各種各樣的破解方法,但另一方面,底層機(jī)制的改動會降低應(yīng)用對機(jī)型適配和兼容能力,目前來說,這是一個魚和熊掌不可得兼的局面。如果需要打破這一局面,還是需要谷歌本身重視對應(yīng)用的保護(hù),在底層提供更多的保護(hù)機(jī)制給應(yīng)用開發(fā)者。
[1]豐生強(qiáng).Android軟件安全與逆向分析[M].人民郵電出版社,2013.
[2][美]Anmol Misra.Android系統(tǒng)安全與攻防[M]機(jī)械工業(yè)出版社,2014.
[3]柯元旦.Android內(nèi)核剖析[M]電子工業(yè)出版社,2011.
編輯 朱榮華
TN91
A
2095-8528(2015)05-067-04
2015-04-26
李萍(1975-),女,廣東省輕工業(yè)技師學(xué)院計(jì)算機(jī)科學(xué)與技術(shù)講師,研究方向?yàn)锳ndroid平臺的應(yīng)用安全與保護(hù)機(jī)制。