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