朱洪軍 陳耀光 華保健 陳 灝
1(中國科學技術大學軟件學院 安徽 合肥 230051)2(中國科學技術大學蘇州研究院 江蘇 蘇州 215123)
?
一種Android應用加固方案
朱洪軍1,2陳耀光1華保健1,2陳 灝1
1(中國科學技術大學軟件學院 安徽 合肥 230051)2(中國科學技術大學蘇州研究院 江蘇 蘇州 215123)
Android應用安全問題日益突出,大量Android應用遭受逆向、非法復制及惡意代碼注入等攻擊。對Android應用安全機制進行研究,在分析靜態(tài)逆向和動態(tài)逆向攻擊原理的基礎上,提出一種移動應用加固保護方案。方案綜合運用加殼、反調試、簽名校驗及反編譯等應用加固技術,對目標應用進行加固;經(jīng)測試,該加固方案能夠很好地對抗常見的靜態(tài)分析和動態(tài)分析等逆向攻擊。
加固 反調試 Android安全 加殼
2014年5月,中國工業(yè)和信息化部電信研究院發(fā)布《移動互聯(lián)網(wǎng)白皮書》[1]。文獻[1]指出:Android(安卓)在中國市場的主導優(yōu)勢更為凸顯。2013年四季度 Android 以新增市場94.6%的絕對領先優(yōu)勢主導國內(nèi)市場。同時,Android安全問題也日益嚴重,另據(jù)手機安全公司統(tǒng)計,2013年受惡意吸費代碼感染的終端數(shù)量高達1400萬,用戶直接經(jīng)濟損失超過7000萬元。
基于Android平臺的應用程序代碼經(jīng)過編譯器編譯生成Android應用壓縮包APK,APK極易被逆向工具,如Apktool(谷歌公司提供的一種用于APK反編譯的工具)等進行反編譯,從而開展逆向攻擊。自2.3版本發(fā)布之后,Android平臺引入了代碼混淆機制;通過代碼混淆僅增加了逆向分析的難度和工作量,應用程序核心邏輯仍然可以通過函數(shù)調用關系進行逆向破解與攻擊[2,3]。因此,未經(jīng)加固的Android應用程序無法很好地對抗惡意代碼注入、非法拷貝等攻擊。Android應用一旦遭受攻擊,就可能被植入廣告、程序后門,甚至竊取用戶隱私數(shù)據(jù),給用戶帶來嚴重損失。
文獻[2]提出了一種基于classes.dex(APK壓縮包中可執(zhí)行代碼包)文件動態(tài)加載的Android平臺加固方案,可以有效地隱藏關鍵代碼,生成目標代碼保護殼,但其并未實現(xiàn)對殼文件的有效保護。文獻[4]提出的Android加固方案是在加殼的基礎上添加了對殼程序的保護措施,例如偽加密、代碼混淆、簽名校驗等,但其提出的保護措施僅在Java層,通過簡單逆向攻擊手段,如直接修改smali代碼,就可以輕易破解。
在此基礎上,本文提出一種移動應用加固方案:通過將目標虛擬機可執(zhí)行文件dex(Dalvik VM Executes)加密之后隱藏在如圖片等資源文件中,使用非法屬性識別符ID(Identifier)、反調試及簽名校驗等技術,對目標應用程序進行加固。實驗結果表明:本加固方案可以很好地對抗反編譯、逆向分析、非法復制及重打包等逆向攻擊。
1.1 APK文件結構
APK文件是Android平臺下的可執(zhí)行文件,它本質上是一種zip壓縮文件格式,其文件結構及作用大致如表1[5,6]所示。
表1 APK文件目錄
其中classes.dex文件是Dalvik虛擬機字節(jié)碼文件,是攻擊者進行逆向分析與攻擊的目標。dex文件主要結構如圖1所示。
圖1 dex主要結構
在dex header中checksum和signature分別是對dex文件的校驗值和簽名值,系統(tǒng)在加載dex時會校對dex的簽名及檢驗值,避免加載損壞的dex,在一定程度上增加應用程序安全性。
1.2 靜態(tài)分析
靜態(tài)分析是指在不運行代碼的情況下,采用詞法分析、語法分析等各種技術手段對程序文件進行掃描從而生成程序的反匯編代碼,然后閱讀反匯編代碼來掌握程序的一種技術[7,8]。
靜態(tài)分析Android程序主要有兩種方法:一是閱讀反匯編生成的smali代碼,二是閱讀反匯編生成的Java代碼。靜態(tài)逆向分析的關鍵是要找到程序的關鍵代碼,常用的定位關鍵代碼的方法有以下幾種[7]:
(1) 特征函數(shù)法
通過查找系統(tǒng)關鍵API來定位關鍵代碼。
(2) 順序查看法
從軟件啟動代碼開始逐行分析代碼。
(3) 代碼注入法
通過smali注入代碼使得APK自動輸出關鍵數(shù)據(jù)。
(4) 棧跟蹤法
通過輸出運行時棧上的函數(shù)調用序列來分析執(zhí)行流程。
(5) Method Profiling
分析程序性能,跟蹤函數(shù)調用關系等。
在對抗靜態(tài)分析時,常用的方法是找到某些靜態(tài)分析工具自身漏洞,針對漏洞做出一些特定的反制措施。常用的靜態(tài)分析工具有Apktool、Backsmali、smali、Dex2jar、AXMLPrinter2.jar等。
1.3 動態(tài)分析
動態(tài)分析是在沒有軟件源代碼的情況下,通過調試器跟蹤分析匯編代碼。對于Android應用,動態(tài)跟蹤調試又可分為動態(tài)調試Android SDK程序和動態(tài)調試Android原生程序[7];
動態(tài)逆向分析常用的工具有以下幾種[7]:
(1) AndBug
AndBug是一款腳本式Android程序動態(tài)調試器,通過AndBug可以完成Android程序的無源碼調試。
(2) IDA Pro
在IDA Pro6.6之后版本不僅能動態(tài)調試APK中的so動態(tài)鏈接庫,還可以直接動態(tài)調試APK。
(3) Gdb
Android以Linux內(nèi)核為基礎,所以可以使用gdb配合gdbserver進行Android原生程序匯編級調試。
(4) NetBeans、Eclipse
通過apktool在APK中加入調試信息之后可以通過NetBeans或Eclipse完成smali代碼的動態(tài)調試。
在對抗動態(tài)逆向分析時,常用的方法是檢測APK是否被調試器附加,比如后文中提到的檢測/proc/pid/status文件中的TracePid來判斷是否被調試器附加。
2.1 加固方案綜述
加固方案共分為兩個階段,主要流程及各階段完成的功能如圖2所示。
圖2 加固方案主要流程
加固階段一主要完成對目標APK的加殼,對受保護的目標代碼進行隱藏;加固階段二通過加載libsecurity.so安全庫來完成殼的自我保護,采用的技術包括反調試、防止重打包(通過簽名校驗保護方式)和防止反編譯等。
在加固階段一和二中主要涉及到5種對象:
(1) 目標APK
目標APK是要被加固的apk,目標APK中的dex文件稱為目標dex文件。
(2) 加殼程序
加殼程序負責進行具體的加殼操作,完成的功能主要有:提取目標APK中的dex、lib、res等源數(shù)據(jù);加密目標dex并嵌入圖片;將加密密鑰寫入殼APK的dex末尾。
(3) 殼APK
在殼程序運行時完成兩件事,首先加載安全庫libsecurity.so,然后解密出目標dex并完成動態(tài)加載。主要的反調試功能放在安全庫libsecurity.so中用C++語言實現(xiàn),同時加入反調試,簽名校驗等安全措施。
(4) 防反編譯程序
負責在殼APK中的axml文件中插入非法id值,防止APK被apktool反編譯。
(5) 加固后的APK
經(jīng)過簽名之后生成最終加固好的APK,該APK可被正確安裝及運行,且功能和目標APK相同。
2.2 加殼方案設計
由于Dalvik字節(jié)碼容易被反編譯,攻擊者可以輕易地從反編譯出的指令代碼中找到程序的關鍵邏輯[9]。為了防止應用程序被反編譯,同時對抗靜態(tài)分析,通過加殼來隱藏真正的dex文件,可以很好地防止攻擊者直接反編譯出目標應用指令代碼。
圖3 目標dex加密流程
傳統(tǒng)加殼方案直接將加密后的目標dex放在殼dex末尾[10,11],使得殼dex本身攜帶可疑代碼,攻擊者可以輕松地識別并靜態(tài)剝離出加密后的目標dex,通過解密密鑰解密出目標dex。為了解決此問題,可以將加密后目標dex隱藏在如圖片等資源文件中,可以減弱目標可疑特征,從而對抗攻擊者的攻擊。目標dex加密流程如圖3所示。
目標dex加密時,首先生成隨機加密密鑰,再讀取目標dex并且用AES算法對其進行加密,將加密后的dex嵌入資源文件如png格式圖片中,最后再將隨機生成的密鑰寫入殼dex末尾。殼dex文件結構大致如圖4所示。
圖4 殼dex文件結構
由于殼dex嵌入了解密密鑰,結構遭到破壞,需要重新計算殼dex頭部中的checksum、signature和filesize幾個屬性值。
解密目標dex流程如圖5所示。
圖5 對目標dex解密的主要流程
解密時,首先從殼dex的末尾讀取出加密密鑰,然后在從存放目標dex的資源文件中讀加密dex,使用AES算法對其進行解密,之后得到解密后的目標dex。
殼程序運行主要流程如圖6所示。
圖6 殼程序運行流程圖
在殼程序運行時首先加載安全庫libsecurity.so,libsecurity.so中首先通過fork創(chuàng)建子進程,子進程專門用做反調試和簽名校驗。父進程則負責動態(tài)加載dex,首先將原類加載器替換成DexClassLoader加載器,然后分別從殼dex末尾和圖片中讀出密鑰和加密后的目標dex,用密鑰解密出目標dex后,動態(tài)替換殼application中的關鍵數(shù)據(jù)結構,進而完成目標APK的動態(tài)加載。 在運行期間,若子進程檢測到反調試或重打包,則直接殺死父進程退出程序。
2.3 殼自身保護方案設計
加殼可以隱藏目標APK,但是不能防止APK被動態(tài)調試。本節(jié)在加殼的基礎上加入殼自身保護技術。通過ptrace檢測/proc/pid/status和inotify監(jiān)控關鍵文件來防止動態(tài)調試;通過簽名校驗防止APK被重打包;通過在AXML中插入非法ID來防止反編譯;綜合多種保護措施共同保護殼APK的安全。
2.3.1 反調試方案設計(1) 通過檢查/proc目錄反調試
本加固方案通過定期檢測/proc/pid/status中的TracerPid來防止被調試,若檢測到調試器則殺死主進程。該反調試流程如圖7所示。
圖7 檢測/proc目錄反調試流程圖
在Linux系統(tǒng)下一個進程可以通過ptrace系統(tǒng)調用來監(jiān)控另一個進程的執(zhí)行流程,gdb等調試軟件的核心原理即是通過ptrace系統(tǒng)調用。ptrace系統(tǒng)調用的第一個參數(shù)可以指定執(zhí)行行為,比如當?shù)谝粋€參數(shù)為 PTRACE_TRACEME時表示本進程被其父進程跟蹤,在父進程中可以使用PTRACE_ATTACH附加至子進程完成調試。ptrace系統(tǒng)調用可以用于進程調試,但是它有一個限制:一個進程不能被ptrace多次。根據(jù)這個原理可知,只要在進程中主動調用ptrace就可以實現(xiàn)基本的反調試。
Android使用Linux內(nèi)核,而Linux內(nèi)核提供了一種名為/proc的文件系統(tǒng),通過/proc可以在運行時訪問和改變某些內(nèi)核內(nèi)部數(shù)據(jù)結構。 由于proc文件系統(tǒng)只存在于內(nèi)存中,所以其本質上是一個偽文件系統(tǒng)。在進程運行過程中一些內(nèi)核狀態(tài)是在不斷變化的,所以通過proc文件系統(tǒng)讀取的進程狀態(tài)也可能是不斷變化的。其中的/proc/pid/status文件就存儲了進程號為pid的進程狀態(tài),通過定時檢測/proc/pid/status中的TracerPid,若該字段不為0時表示調試進程的pid,若檢測到TracerPid不為0則直接殺死主進程。
(2) 通過inotify反調試
在Linux操作系統(tǒng)下可以通過inotify來通知用戶應用程序文件系統(tǒng)的某些變化,可以利用inotify來實現(xiàn)監(jiān)控某些文件系統(tǒng)事件,比如文件的打開、讀寫和刪除等。而/proc偽文件系統(tǒng)目錄下有一些十分關鍵的的文件可能被破解者利用,比如破解者可以通過/proc/pid/maps查看進程地址空間分布情況,進而通過dd命令直接dump出關鍵內(nèi)存區(qū)域,所以可以通過inotify來監(jiān)控這些敏感文件的讀取和打開,從而完成反調試。
通過inotify監(jiān)控/proc/pid/maps文件的關鍵代碼大致如下:
?
fd = inotify_init();
sprintf(buf, ″/proc/%d/maps″,ppid);
wd = inotify_add_watch(fd, buf, IN_ALL_EVENTS);
?
len = read(fd,readbuf,MAXLEN);
while(i < len){
struct inotify_event *event = (struct inotify_event*)&readbuf[i];
if((event->mask&IN_ACCESS) || (event->mask&IN_OPEN)){
int ret = kill(ppid,SIGKILL);
return;
}
i+=sizeof (struct inotify_event) + event->len;
}
?
2.3.2 防止重打包
早期的完整性校驗直接放在Java層進行,這時通過直接修改smali代碼可以很輕易的繞過校驗,示例如下:
const-string v1, ″com/example/checksignature″
invoke-virtual{p0,v1}, Lcom/example/checksignature/MainActivity;->getSignature(Ljava/lang/String;)I
move-result v0
const v1, 0x7b7c6261
if-eq v0, v1, :cond_0
//相等則驗證成功,否則驗證失敗
?
在破解時只需將if-eq改成if-ne即可繞過簽名驗證[12]。本文實現(xiàn)的加固方案中的完整性校驗并不放在Java層,而是通過JNI編程放在動態(tài)鏈接安全庫(libsecurity.so)中,主要原理是通過反射調用PackageManager類中的getPackageInfo()方法來獲取應用程序簽名。由于在加載安全庫libsecurity.so時做了動態(tài)反調試,所以除非破解了反調試,否則無法通過簡單的改寫代碼來繞過簽名驗證,這樣大大增加了應用的安全性。
2.3.3 防止反編譯
在Android的manifest.xml文件是Android應用中最重要的文件之一,它存儲了一個應用程序運行所需的權限、應用程序的各個組件(activity,service等)、應用程序的入口點等重要信息。但是早期的加固方案沒有對manifest做任何處理,這就導致破解者可以很輕易從manifest文件中找到一些關鍵信息。本文實現(xiàn)的加固方案對manifest文件做了一定的保護,可以有效地增加APK被破解的難度。
axml是AndroidManifest.xml對應的二進制文件,直接解壓apk包獲得的AndroidManifest文件即是amxl格式。apktool在解析axml文件時有一個漏洞,它會解析amxl中的所有屬性id,當遇到非法屬性id時就會解析失敗。所以可以通過這個漏洞在axml文件中插入擁有非法id的屬性,使得apktool等逆向工具解析失敗,無法正常反編譯。由于android系統(tǒng)不解析非法id,所以apk包還是能夠正常安裝。
當插入非法屬性id時apktool解析失敗,防止反編譯效果如圖8所示(插入非法ID值atest)。
圖8 防反編譯效果圖
在axml文件中插入非法id值之后需要對apk包進行重簽名,通過這種方法可以在一定程度上防止反編譯,但是又不影響apk包的正常安裝。
在Android應用市場(http://www.appchina.com/,截至2015年4月)隨機選取游戲類、資訊閱讀類、系統(tǒng)工具類、生活實用類等5款類型不同且大小也不同的apk(目標APK未加殼)進行加固方案測試,加固前后的應用大小變化如表2所示。
表2 加固后應用包大小變化(單位:字節(jié))
測試結果表明:經(jīng)過加固后應用程序大致增加了400~500 KB的容量。加殼后APK變大的主要增量是libsecurity.so動態(tài)庫和解殼工程。
通過對常見的逆向工具測試,加固方案效果如表3所示。
表3 加固方案對抗逆向工具評測
注:√表示加固方法對某逆向工具有效,Χ表示加固方法對該逆向工具無效
測試結果表明:不同的加固方法對不同的逆向工具有效。通過apktool漏洞可以使得apktool反編譯失??;加殼可以使得apktool、dex2jar或JEB無法反編譯出真正的dex;通過ptrace檢測/proc文件夾等反調試措施可以防止IDA Pro、NetBeans的動態(tài)調試;簽名校驗可以防止NetBeans動態(tài)調試。綜合上述,所有加固方法可以對目標APK起到有效全面的保護。
通過對Android安全機制的研究,分析常見逆向攻擊機制,設計了一種移動應用加固方案。該方案將加密后的目標dex嵌入圖片可以有效隱藏目標dex,實驗表明,加殼保護技術可以有效防止目標APK被靜態(tài)分析。使用ptrace和檢測/proc/pid/status和inotify監(jiān)控關鍵文件,可以有效完成反調試保護。此外,加固方案還加入了JNI層的簽名校驗,能有效防止重打包。加固方案的最后一個階段還利用apktool解析漏洞添加非法id值,使得殼APK無法被反編譯。通過測試,加固后的APK文件會大致增加400~500 KB的容量,對APK運行或加載效率造成較小影響。本加固方案沒有實現(xiàn)對抗dump內(nèi)存的逆向攻擊方法,攻擊者仍然可以通過內(nèi)存拷貝等方式,找到目標dex代碼。
本加固方案仍然有需要改進和完善的地方,在接下來工作中將會著重研究:1) so加殼保護。dex加殼無法防止內(nèi)存dump,但通過so加殼保護則能大大增加內(nèi)存dump的難度。2) AndroidManifest.xml配置保護。AndroidManifest.xml配置文件作為應用程序的“說明書”,當前加固方案對其的保護不足,這是另一個研究重點。
[1] 工信部.移動互聯(lián)網(wǎng)白皮書[R].北京,2014.
[2] 巫志文,李煒.基于Android平臺的軟件加固方案的設計與實現(xiàn)[J].電信工程技術與標準化,2015(1):33-37.
[3] 吳善崇,張權.Android平臺安全機制淺析[J].實驗科學與技術,2014,12(2):43-45.
[4] 徐劍,武爽,孫琦,等.面向Android應用程序的代碼保護方法研究[J].信息網(wǎng)絡安全,2014(10):11-17.
[5] 梅瑞,武學禮,文偉平.基于Android平臺的代碼保護技術研究[J].信息網(wǎng)絡安全,2013(7):10-15.
[6] 伍景珠.基于Android平臺的軟件保護方案的研究與實現(xiàn)[D].北京郵電大學,2013.
[7] 豐生強.Android軟件安全與逆向分析[M].北京:人民郵電出版社,2013.
[8] 張志遠,萬月亮,翁越龍,等.Android應用逆向分析方法研究[J].信息網(wǎng)絡安全,2013(6):65-68.
[9] 劉劼.Java反編譯技術和代碼安全[J].現(xiàn)代電子技術,2004,27(10):22-24.
[10] 姚為光.軟件加殼技術的研究[D].電子科技大學,2011.
[11] 李文.基于殼技術的軟件保護研究[D].電子科技大學,2012.
[12] 李宇翔,林柏鋼.基于Android重打包的應用程序安全策略加固系統(tǒng)設計[J].信息網(wǎng)絡安全,2014(1):43-47.
AN ANDROID APPLICATION REINFORCEMENT SCHEME
Zhu Hongjun1,2Chen Yaoguang1Hua Baojian1,2Chen Hao1
1(School of Software Engineering,University of Science and Technology of China,Hefei 230051,Anhui,China)2(Suzhou Institute for Advanced Study,University of Science and Technology of China,Suzhou 215123,Jiangsu,China)
Nowadays, the problem of Android application security is increasingly prominent. A large number of Android applications encounter the attacks such as reverse, illegal copy and malicious code injection, etc. We studied the security mechanism of Android applications, based on analysing static reverse and dynamic reverse attacks principle, we put forward a reinforcement protection scheme for mobile applications. The scheme comprehensively uses the application reinforcement technologies of shelling, anti-debugging, signature verification and anti-decompiling, etc., to reinforce target applications. Through a series of tests, it is proved that this scheme can well resist common reverse attacks of static analysis and dynamic analysis.
Reinforcement Anti-debugging Android security Shelling
2015-06-25。教育部-谷歌校企合作專業(yè)綜合改革項目([2014]14);蘇州市科技計劃應用基礎研究項目(SYG201406)。朱洪軍,講師,主研領域:軟件測試,移動應用安全。陳耀光,碩士生。華保健,講師。陳灝,碩士生。
TP309
A
10.3969/j.issn.1000-386x.2016.11.067