簡(jiǎn)容, 黎桐辛, 周淵, 李舟軍, 韓心慧
(1. 北京航空航天大學(xué) 計(jì)算機(jī)學(xué)院,北京 100191; 2. 北京大學(xué) 計(jì)算機(jī)科學(xué)技術(shù)研究所,北京 100080; 3. 國家計(jì)算機(jī)網(wǎng)絡(luò)應(yīng)急技術(shù)處理協(xié)調(diào)中心,北京 100085)
目前Android操作系統(tǒng)已經(jīng)成為全球市場(chǎng)上所占份額最高的移動(dòng)終端系統(tǒng),基于Android操作系統(tǒng)的應(yīng)用程序數(shù)量也逐年增多. 由于Android平臺(tái)的開放性,應(yīng)用程序能夠較容易的被逆向分析、修改破解、重新打包[1]. 為了防止軟件被逆向破解或攻擊利用,許多開發(fā)者采取了應(yīng)用加殼的方式[2],對(duì)程序關(guān)鍵代碼進(jìn)行加密、隱藏,極大地增加了逆向分析的難度,從而達(dá)到對(duì)程序保護(hù)的效果.
但是,以Android平臺(tái)為目標(biāo)的惡意軟件也利用了加殼技術(shù)的特性,對(duì)自身攜帶的惡意代碼進(jìn)行隱藏,用于躲避殺毒引擎的檢測(cè)和安全研究人員的分析[3-4]. 同時(shí),加殼后的應(yīng)用也無法利用靜態(tài)分析工具準(zhǔn)確檢測(cè)應(yīng)用內(nèi)部的安全隱患[5]. 因此,實(shí)現(xiàn)自動(dòng)化通用脫殼,在程序分析和惡意軟件檢測(cè)等方面有重要意義.
本文設(shè)計(jì)并實(shí)現(xiàn)了一種多層次的自動(dòng)化通用脫殼系統(tǒng),能夠應(yīng)對(duì)目前市場(chǎng)上主流加殼服務(wù),還原程序的代碼邏輯. 提出了多粒度的數(shù)據(jù)還原方案,保證數(shù)據(jù)還原的完整性和有效性. 對(duì)應(yīng)用市場(chǎng)上的加殼程序進(jìn)行安全性評(píng)估,得到了新的發(fā)現(xiàn),證明了脫殼系統(tǒng)的實(shí)際應(yīng)用價(jià)值.
本文基于Dalvik虛擬機(jī)設(shè)計(jì)并實(shí)現(xiàn)了一種多層次自動(dòng)化通用脫殼系統(tǒng). 該系統(tǒng)將應(yīng)用程序的啟動(dòng)執(zhí)行過程劃分為不同的3個(gè)主要層次,在不同層次對(duì)加殼應(yīng)用的dex文件進(jìn)行不同粒度的數(shù)據(jù)轉(zhuǎn)儲(chǔ)(Dump),并最終對(duì)dex文件的頭部信息,索引結(jié)構(gòu)區(qū),數(shù)據(jù)區(qū)進(jìn)行還原,生成完整dex文件.
圖1展示了脫殼系統(tǒng)的整體架構(gòu). 它包含了多層次狀態(tài)監(jiān)控,多粒度數(shù)據(jù)轉(zhuǎn)儲(chǔ)和Dex文件重構(gòu)3個(gè)模塊. 由于目前的加殼技術(shù)對(duì)dex文件的解密不再是一個(gè)單一階段的過程,而是隨著dex文件的加載與執(zhí)行逐步解密,因此,在不同時(shí)刻內(nèi)存中的dex文件所具備的數(shù)據(jù)也有所不同. 為此,在加殼程序運(yùn)行的每一個(gè)層次設(shè)置監(jiān)控點(diǎn),跟蹤加殼程序的執(zhí)行過程. 依照數(shù)據(jù)類型的不同,對(duì)dex文件的數(shù)據(jù)進(jìn)行不同粒度的區(qū)分,并根據(jù)監(jiān)控點(diǎn)的反饋信息,獲取當(dāng)前運(yùn)行層次下dex文件對(duì)應(yīng)的數(shù)據(jù)內(nèi)容中的有效部分. 最后,對(duì)獲取到的有效數(shù)據(jù)進(jìn)行dex文件重構(gòu),實(shí)現(xiàn)自動(dòng)化的脫殼流程.
該系統(tǒng)以加殼后的應(yīng)用程序作為輸入,通過動(dòng)態(tài)執(zhí)行加殼程序,輸出脫殼后包含完整代碼的dex文件,在脫殼過程中,不需要使用者對(duì)加殼服務(wù)有逆向經(jīng)驗(yàn)或?qū)Τ绦蜻M(jìn)行額外的人工預(yù)處理,同時(shí),由于該系統(tǒng)直接基于Dalvik虛擬機(jī)實(shí)現(xiàn),不會(huì)受到加殼服務(wù)完整性檢查和反調(diào)試措施的影響,自動(dòng)化程度較高.
圖1 脫殼系統(tǒng)整體框架Fig.1 Architecture of the unpacker system
為了監(jiān)控殼代碼的行為,本文設(shè)計(jì)了多層次的狀態(tài)監(jiān)控方案,該方案不需要對(duì)虛擬機(jī)整體運(yùn)行做跟蹤,而是在程序執(zhí)行的不同層次,選取盡可能少的監(jiān)控點(diǎn),用于反映殼代碼在執(zhí)行過程中的關(guān)鍵行為.
1.1.1 層次劃分
脫殼系統(tǒng)將程序的啟動(dòng)執(zhí)行劃分為以下3個(gè)層次.
① Dex文件加載:Dalvik虛擬機(jī)可以通過文件,或二進(jìn)制字節(jié)流的形式,將dex文件加載至內(nèi)存,并生成相應(yīng)的DexFile結(jié)構(gòu)來代表被加載的dex文件.
② 類加載:Dalvik虛擬機(jī)中使用ClassObject結(jié)構(gòu)代表已加載的類. 根據(jù)類加載方式的不同,可以分為顯式加載和隱式加載.
③ 方法執(zhí)行:當(dāng)類中的方法被調(diào)用時(shí),Dalvik虛擬機(jī)將從類加載信息中生成對(duì)應(yīng)的DexMethod結(jié)構(gòu)來代表該方法. 方法執(zhí)行的過程,即為虛擬機(jī)對(duì)字節(jié)碼解釋執(zhí)行的過程.
1.1.2 監(jiān)控點(diǎn)的選取
根據(jù)上述層次劃分,在每一層次選取監(jiān)控點(diǎn),用于獲取在該層次下殼代碼的行為信息. 在選取監(jiān)控點(diǎn)時(shí),應(yīng)當(dāng)考慮到:選取的監(jiān)控點(diǎn)數(shù)量應(yīng)該盡量少,以減小系統(tǒng)整體的性能開銷;選取的監(jiān)控點(diǎn)應(yīng)覆蓋當(dāng)前層次中所有的路徑調(diào)用情況;選取的監(jiān)控點(diǎn)不能是導(dǎo)出函數(shù)或系統(tǒng)提供的API,以防被加殼程序檢測(cè)或修改. 根據(jù)上述規(guī)則,對(duì)每一層次的監(jiān)控點(diǎn)選取如下.
① 監(jiān)控dex文件加載:為避免dex文件的重復(fù)加載,Dalvik虛擬機(jī)將已加載的dex文件保存在全局變量gDvm.userDexFiles中. 選取了addToDexFileTable函數(shù)作為dex文件加載的監(jiān)控點(diǎn). 該函數(shù)是將dex文件增加至gDvm.userDexFiles中的唯一途徑,因此通過監(jiān)控該函數(shù),能夠得到殼代碼加載dex文件的信息.
② 監(jiān)控類加載:當(dāng)一個(gè)類從未被加載過時(shí),最終將由native層的Dalvik_dalvik_system_DexFile_defineClassNative函數(shù)完成從dex文件加載指定類的任務(wù). 選取該函數(shù)作為類加載行為的監(jiān)控點(diǎn).
③ 監(jiān)控類方法執(zhí)行:當(dāng)應(yīng)用程序啟動(dòng)時(shí),Dalvik虛擬機(jī)解釋器以android.app.ActivityThread類的靜態(tài)成員函數(shù)main為入口點(diǎn)執(zhí)行,在執(zhí)行過程中遇到函數(shù)調(diào)用時(shí),會(huì)因函數(shù)屬于Java層還是Native層而出現(xiàn)4種不同的情況. 表1展示了這4種情況下虛擬機(jī)所使用的跳轉(zhuǎn)方法. 可以看到,除去Native層到Native層的調(diào)用之外,都能夠在每一個(gè)方法被調(diào)用前,監(jiān)控到該方法的調(diào)用信息. 由于Native層的代碼不屬于dex文件中由Java編譯而來的字節(jié)碼,因此可以不用處理這一類情況.
表1 Dalvik虛擬機(jī)函數(shù)調(diào)用的4種類型Tab.1 Four types of function calls in Dalvik virtual machine
在傳統(tǒng)的脫殼方案中,往往會(huì)指定一個(gè)特定的脫殼時(shí)機(jī)(通常為加殼程序的第一個(gè)Activity被創(chuàng)建時(shí)),當(dāng)這個(gè)時(shí)機(jī)到達(dá)后,脫殼程序認(rèn)為此時(shí)殼代碼已將dex文件在內(nèi)存中完全解密,并一次性轉(zhuǎn)儲(chǔ)dex文件,完成整個(gè)脫殼流程. 實(shí)際上,以這種方式得到的dex文件雖然能夠被正常反編譯,但通常會(huì)出現(xiàn)部分?jǐn)?shù)據(jù)缺失或偏移錯(cuò)誤的情況,這是因?yàn)榛谔囟〞r(shí)機(jī)后dex文件完全解密的假設(shè)本身可能是不準(zhǔn)確的. 為了解決這個(gè)問題,使用了多粒度數(shù)據(jù)轉(zhuǎn)儲(chǔ)的方案,來保證內(nèi)存數(shù)據(jù)的準(zhǔn)確性.
Dex文件由多項(xiàng)不同類型數(shù)據(jù)結(jié)構(gòu)組成,且通過加載基址加上數(shù)據(jù)偏移的方式來計(jì)算數(shù)據(jù)存放位置,因此,通常需要根據(jù)偏移值進(jìn)行多次索引,才能獲取相應(yīng)數(shù)據(jù)內(nèi)容. 例如,存放于DexHeader的stringIdsOff代表了字符串類型數(shù)據(jù)結(jié)構(gòu)DexStringId的起始偏移,通過DexStringId中stringDataOff成員的值,可以獲得MUTF-8編碼的實(shí)際字符串內(nèi)容. 除字符串信息外,dex文件還包含了類型信息、原型信息、字段信息、方法信息、類信息以及依賴信息等部分. 根據(jù)上述索引方式,可以在知道dex文件內(nèi)存基址的情況下,解析所有數(shù)據(jù)所在內(nèi)存地址,并獲取內(nèi)容. 然而,并非所有的內(nèi)容都是有效的,在何時(shí)去獲取數(shù)據(jù)內(nèi)容,取決于殼代碼逐級(jí)解密的時(shí)機(jī),例如,只有當(dāng)類中的方法被執(zhí)行時(shí),虛擬機(jī)才會(huì)去獲取方法中的字節(jié)碼,殼代碼可以選擇在此時(shí)解密出類方法的字節(jié)碼.
從1.2.1節(jié)所述的層次劃分來看,不同時(shí)刻對(duì)于dex文件中的數(shù)據(jù)獲取的準(zhǔn)確程度是不同的. 根據(jù)數(shù)據(jù)獲取的粒度不同,將數(shù)據(jù)分為以下3類. ① dex文件的基本屬性,如版本標(biāo)識(shí)和內(nèi)存映射長度;② dex文件中各項(xiàng)數(shù)據(jù)結(jié)構(gòu)以及具體數(shù)據(jù)中與類方法無關(guān)的部分;③ 類方法部分. 每一個(gè)類方法均由DexMethod結(jié)構(gòu)表示,其中包含了可被虛擬機(jī)執(zhí)行的字節(jié)碼數(shù)據(jù).
根據(jù)狀態(tài)監(jiān)控反饋的信息,該模塊將動(dòng)態(tài)的獲取不同粒度下的數(shù)據(jù)內(nèi)容. 多粒度數(shù)據(jù)轉(zhuǎn)儲(chǔ)基于這樣一個(gè)準(zhǔn)則,即數(shù)據(jù)轉(zhuǎn)儲(chǔ)發(fā)生在Dalvik虛擬機(jī)即將使用該數(shù)據(jù)之前,在數(shù)據(jù)轉(zhuǎn)儲(chǔ)到虛擬機(jī)正常使用數(shù)據(jù)的過程中,殼代碼將沒有機(jī)會(huì)對(duì)該數(shù)據(jù)進(jìn)行動(dòng)態(tài)修改.
1.2.1 Dex文件基本屬性獲取
當(dāng)監(jiān)測(cè)到dex文件的加載行為時(shí),將獲取該dex文件的基本屬性. 具體而言,通過監(jiān)測(cè)的addToDexFileTable函數(shù)獲得指向內(nèi)存中dex文件的pDexOrJar指針,并利用該指針得到dex文件對(duì)應(yīng)內(nèi)存代表的DexFile結(jié)構(gòu). 此時(shí)dex文件中的各項(xiàng)數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)的內(nèi)容不一定是有效的,因此僅獲取脫殼所需要的一些基本屬性,包括:dex文件在內(nèi)存中的映射長度,dex文件是否已被優(yōu)化為odex格式,dex文件的版本標(biāo)識(shí)和字節(jié)序標(biāo)記.
1.2.2 Dex文件數(shù)據(jù)結(jié)構(gòu)獲取
當(dāng)監(jiān)測(cè)到類加載行為時(shí),將獲取dex文件各項(xiàng)數(shù)據(jù)結(jié)構(gòu)的信息. 具體而言,通過監(jiān)測(cè)的Dalvik_dalvik_system_DexFile_defineClassNat-ive函數(shù),獲得當(dāng)前加載類所使用的ClassLoader和當(dāng)前類所在的dex文件信息,然后利用ClassLoader主動(dòng)加載該dex文件中的所有類,使得殼代碼在類中注入的靜態(tài)代碼塊得到執(zhí)行. 此時(shí),對(duì)于dex文件中不屬于類方法的數(shù)據(jù),在類被加載至內(nèi)存后將處于解密狀態(tài),獲取當(dāng)前dex文件每一類數(shù)據(jù)結(jié)構(gòu)的個(gè)數(shù)和對(duì)應(yīng)的偏移值,根據(jù)偏移值計(jì)算出數(shù)據(jù)的內(nèi)存地址,并依據(jù)數(shù)據(jù)結(jié)構(gòu)中的成員定義,獲取數(shù)據(jù)的真實(shí)內(nèi)容. 需要注意的是,雖然此時(shí)dex文件中類方法相關(guān)數(shù)據(jù)不一定處于解密狀態(tài),但仍然會(huì)在此時(shí)根據(jù)相關(guān)偏移去解析和獲取類方法數(shù)據(jù).
1.2.3 類方法的動(dòng)態(tài)更新
如1.2.2節(jié)所述,當(dāng)完成類加載操作后,類方法數(shù)據(jù)可能仍處于加密狀態(tài),這是由于部分殼代碼采取了方法替換的方式,將原有類方法替換為殼代碼,并在類方法被調(diào)用時(shí)動(dòng)態(tài)解密. 為了應(yīng)對(duì)這種情況,在類方法調(diào)用時(shí)進(jìn)行類方法的動(dòng)態(tài)更新.
當(dāng)監(jiān)測(cè)到方法調(diào)用行為時(shí),通過函數(shù)局部變量Method,獲得當(dāng)前被調(diào)用方法的函數(shù)簽名,所屬類以及其指令集,如果該方法所屬類位于已加載的非系統(tǒng)dex文件集合中,則獲取該方法包含的所有數(shù)據(jù). 由于在程序運(yùn)行期間,并非所有的方法均有機(jī)會(huì)得到執(zhí)行,可以使用Monkey、UI Automator等動(dòng)態(tài)測(cè)試工具,發(fā)送隨機(jī)事件,如鍵盤輸入、屏幕點(diǎn)擊、手勢(shì)滑動(dòng)等,提高動(dòng)態(tài)代碼覆蓋率.
重構(gòu)dex,指的是將多粒度數(shù)據(jù)轉(zhuǎn)儲(chǔ)獲得的內(nèi)存數(shù)據(jù)重新匯編成可供靜態(tài)分析工具分析的完整dex文件,并寫入外部存儲(chǔ)設(shè)備. 進(jìn)行dex重構(gòu)時(shí),通過廣度優(yōu)先遍歷的方式,依照dex文件標(biāo)準(zhǔn)規(guī)范,以dex文件頭部為根節(jié)點(diǎn),重構(gòu)dex文件中的各項(xiàng)數(shù)據(jù)結(jié)構(gòu). 由于dex文件重構(gòu)的數(shù)據(jù)完全來源于數(shù)據(jù)轉(zhuǎn)儲(chǔ)的內(nèi)容,因此dex文件重構(gòu)的時(shí)機(jī)尤為重要,如果在脫殼時(shí)僅進(jìn)行單一階段的重構(gòu),或者在殼代碼對(duì)原有數(shù)據(jù)進(jìn)行解密之前就進(jìn)行重構(gòu)操作,都將導(dǎo)致還原的dex文件不完整. 為此,設(shè)計(jì)了一套數(shù)據(jù)更新規(guī)則,保證dex文件重構(gòu)的完整性和準(zhǔn)確性.
殼代碼在內(nèi)存中釋放原有dex文件是一個(gè)逐級(jí)操作的過程. 殼代碼在對(duì)dex文件進(jìn)行動(dòng)態(tài)修改時(shí),必將產(chǎn)生相應(yīng)數(shù)據(jù)結(jié)構(gòu)屬性或內(nèi)容的變化. 重構(gòu)dex時(shí),需要考慮相關(guān)數(shù)據(jù)的變化,正確更新,得到準(zhǔn)確的dex文件.
圖2展示了一個(gè)類方法在逐級(jí)解密時(shí)的變化路線,其中實(shí)線箭頭代表殼代碼在執(zhí)行方法前,由于動(dòng)態(tài)修改操作將Native方法還原成Java方法,虛線箭頭代表殼代碼在方法執(zhí)行完畢后,重新將該方法標(biāo)記為Native方法. 雖然通過監(jiān)控方法調(diào)用,能夠感知到殼代碼的修改行為,但殼代碼的重新加密操作,使得會(huì)從內(nèi)存中獲得同一方法的不同數(shù)據(jù),在重構(gòu)dex文件時(shí),需要選擇其中的正確部分.
圖2 解密過程中類方法在內(nèi)存中的變化Fig.2 Class methods transformation during decryption
為此,通過設(shè)計(jì)單向的數(shù)據(jù)更新規(guī)則,規(guī)定了在程序運(yùn)行中可被接受的數(shù)據(jù)變化操作,當(dāng)變化操作出現(xiàn)時(shí),對(duì)dex文件中對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)進(jìn)行更新. 由于整個(gè)更新過程是單向的,因此殼代碼嘗試重新加密或破壞原本有效數(shù)據(jù)的行為將不會(huì)導(dǎo)致數(shù)據(jù)更新. 以圖2為例,僅接受一個(gè)方法從Native類型轉(zhuǎn)換成Java類型的行為,并認(rèn)為該轉(zhuǎn)換是方法的解密過程,而當(dāng)殼代碼重新將方法標(biāo)記為Native類型時(shí),將不會(huì)更新之前已獲取的方法數(shù)據(jù). 對(duì)于其他類型的數(shù)據(jù),也設(shè)計(jì)了與之類似的單向轉(zhuǎn)換規(guī)則.
為了驗(yàn)證脫殼系統(tǒng)的有效性,選取了市場(chǎng)上主流加殼廠商的加殼產(chǎn)品進(jìn)行脫殼測(cè)試. 從應(yīng)用市場(chǎng)中,選取了愛加密,阿里,百度,梆梆,360,騰訊6家廠商加殼的應(yīng)用程序各10個(gè),使用脫殼系統(tǒng)對(duì)其進(jìn)行脫殼處理.
從如下兩個(gè)標(biāo)準(zhǔn)來衡量脫殼的有效性.
① 脫殼系統(tǒng)給出的還原后dex文件,能夠使用BakSmali、JEB等反編譯工具進(jìn)行處理,以證明dex文件能夠滿足后續(xù)靜態(tài)分析的需要.
② 還原失敗的類方法在所有方法中的比例. 還原失敗的類方法,指的是在脫殼過程中,被殼代碼替換成Native方法,且未能成功還原為字節(jié)碼的類方法. 這一比例應(yīng)當(dāng)盡可能低.
最終的測(cè)試結(jié)果如表2所示. 由于加殼程序中本身存在真實(shí)的Native函數(shù),因此通過人工分析的方法,排除了這部分真實(shí)Native函數(shù),并給出了所有Native方法在總方法數(shù)的比例,以及還原失敗的類方法占總方法數(shù)的比例.
表2 加殼應(yīng)用樣本脫殼測(cè)試結(jié)果Tab.2 Unpack results of packed application samples
可以看到,針對(duì)目前主流加殼服務(wù),脫殼系統(tǒng)還原的dex文件均能用于后續(xù)靜態(tài)分析,且還原失敗類方法比例均在0.3%以下,表明本脫殼系統(tǒng)具有良好的通用性和有效性.
為了測(cè)試脫殼系統(tǒng)所帶來的額外性能開銷,在型號(hào)為Nexus 5的智能手機(jī)上,使用了CF-Bench來進(jìn)行對(duì)比試驗(yàn). 通過在安裝有脫殼系統(tǒng)和未安裝脫殼系統(tǒng)的情況下,分別運(yùn)行CF-Bench 10次并取平均值,得到最終結(jié)果如圖3所示. 可以看到,脫殼系統(tǒng)引入的額外性能開銷約為11.7%,在可以接受的范圍之內(nèi).
同時(shí),選取了drizzleDumper和DexHunter這兩項(xiàng)提供了開源代碼的脫殼方案,與本文的脫殼系統(tǒng)進(jìn)行實(shí)驗(yàn)對(duì)比. 為判斷脫殼后dex文件的完整性和準(zhǔn)確性,從互聯(lián)網(wǎng)上選取了5個(gè)開源的Android應(yīng)用程序進(jìn)行編譯,并利用加殼服務(wù)進(jìn)行加殼處理.
在使用上述脫殼工具進(jìn)行脫殼后,將能被正常反編譯,且其中包含的方法代碼與對(duì)應(yīng)開源項(xiàng)目能一一對(duì)應(yīng)的dex文件視作成功脫殼. 最終的測(cè)試結(jié)果如表3所示. drizzleDumper通過特征搜索來定位dex文件,無法處理破壞了dex文件頭部的情況;DexHunter需要人為確定脫殼目標(biāo)文件的名稱和路徑,同時(shí)對(duì)于不屬于類數(shù)據(jù)的部分進(jìn)行了連續(xù)的內(nèi)存轉(zhuǎn)儲(chǔ),使得最后的dex文件存在不能正常反編譯的情況. 因此,針對(duì)目前的加殼服務(wù),本文提出的系統(tǒng)能達(dá)到更好的脫殼效果.
目前,靜態(tài)檢測(cè)領(lǐng)域存在大量?jī)?yōu)秀的分析工具,如基于流分析的ScanDroid,基于代碼相似性的ViewDroid[6]等等. 脫殼系統(tǒng)與靜態(tài)分析工具相結(jié)合,通常被應(yīng)用到惡意代碼的檢測(cè)和分析領(lǐng)域,并取得了良好的效果. 本文從另一個(gè)角度出發(fā),利用脫殼系統(tǒng),對(duì)應(yīng)用市場(chǎng)中使用了加殼服務(wù)的程序進(jìn)行了安全性評(píng)估.
應(yīng)用程序在被加殼后,其文件結(jié)構(gòu)會(huì)發(fā)生不同程度的變化. 加殼服務(wù)通常會(huì)在APK文件中加入動(dòng)態(tài)加載庫,并通過JNI接口調(diào)用其中的函數(shù). 通過分析不同類型的加殼服務(wù),歸納了這些加殼服務(wù)自身的動(dòng)態(tài)庫名稱,如表4所示.
Janus是一個(gè)移動(dòng)應(yīng)用安全分析社區(qū)化平臺(tái)[7],它收集了主流應(yīng)用市場(chǎng)中應(yīng)用程序的信息,并提供了一種自定義的規(guī)則語言來對(duì)數(shù)據(jù)庫進(jìn)行檢索. 通過搜索檢測(cè)APK文件中是否包含上述特征動(dòng)態(tài)庫,來判斷應(yīng)用程序是否使用了加殼服務(wù),以及加殼服務(wù)的具體名稱,然后選取部分加殼程序下載分析.
歷史下載量是應(yīng)用市場(chǎng)排名算法中的一個(gè)重要影響因素. 根據(jù)特征匹配結(jié)果,隨機(jī)選取了下載量處于不同區(qū)間的加殼應(yīng)用程序共3 500個(gè)作為實(shí)驗(yàn)樣本,實(shí)驗(yàn)樣本收集于2017年5月. 為了確保下載量的準(zhǔn)確性,將應(yīng)用程序在百度、騰訊、360三家應(yīng)用市場(chǎng)中被下載次數(shù)的平均值作為最終的下載量. 表5展示了這些應(yīng)用下載量的分布情況.
表5 加殼應(yīng)用樣本下載量分布Tab.5 Download distribution of packed application samples
在軟件開發(fā)過程中,由于開發(fā)人員的疏忽,可能為應(yīng)用程序引入潛在的安全問題. 這些安全問題可能導(dǎo)致程序在某些極端邊界條件下產(chǎn)生異常運(yùn)行,也有可能被惡意攻擊者利用,造成更為嚴(yán)重的后果. 為了批量分析應(yīng)用程序中的安全問題,使用了AndroBugs[8]框架作為Android應(yīng)用程序漏洞掃描的基礎(chǔ)工具. 待掃描的應(yīng)用程序被分為以下3類.
① 加殼后的應(yīng)用:從應(yīng)用市場(chǎng)上下載的加殼程序樣本;② 脫殼后的應(yīng)用:使用脫殼系統(tǒng)還原出原有dex文件后,重新打包的應(yīng)用程序;③ 未加殼的應(yīng)用:針對(duì)每一個(gè)加殼程序樣本,選取出下載量偏差在10%以內(nèi)的不加殼應(yīng)用程序.
根據(jù)安全問題的嚴(yán)重程度,AndroBugs劃分出了4種不同的安全等級(jí):① Critical:代碼符合某些已知的安全問題特征,需要進(jìn)一步排查;② Warning:可能存在的安全隱患;③ Notice:檢測(cè)到存在某些敏感操作,提供了額外的信息以供分析;④ Info:沒有檢測(cè)到安全問題.
需要注意的是,雖然并非所有被標(biāo)記為Critical的代碼都存在被攻擊的安全漏洞,但是掃描結(jié)果的統(tǒng)計(jì)信息能夠有效地對(duì)應(yīng)用程序進(jìn)行整體安全評(píng)估.
圖4展示了對(duì)上述3類應(yīng)用程序進(jìn)行漏洞掃描后,其不同安全等級(jí)的統(tǒng)計(jì)對(duì)比信息. 從實(shí)驗(yàn)數(shù)據(jù)可以看出,加殼程序被脫殼后,暴露出了更多的安全問題. 同時(shí),下載量大致相同的應(yīng)用程序中,加殼應(yīng)用往往比未加殼應(yīng)用存在更多的安全問題. 脫殼后的加殼程序樣本Critical標(biāo)記統(tǒng)計(jì)數(shù)目是未加殼程序樣本的約1.6倍. 通過進(jìn)一步的人工分析,總結(jié)出產(chǎn)生該結(jié)果的兩個(gè)主要因素.
圖4 應(yīng)用程序漏洞掃描結(jié)果對(duì)比Fig.4 Application vulnerability scan results comparison
① 殼本身所引入的潛在風(fēng)險(xiǎn). 加殼服務(wù)不可避免的需要在原有應(yīng)用程序中引入自身代碼,為了實(shí)現(xiàn)代碼的解密和動(dòng)態(tài)加載,部分殼代碼使用了較為敏感的API,例如Runtime.getRuntime().exec來執(zhí)行特定命令,或者使用mprotect函數(shù)在內(nèi)存中映射可讀可寫可執(zhí)行的區(qū)域. 同時(shí),加殼程序會(huì)通過修改APK中的AndroidManifest.xml文件,注冊(cè)新的組件,并且獲取額外的運(yùn)行權(quán)限,以保障各項(xiàng)服務(wù)的正常運(yùn)行. 例如,為了收集運(yùn)行時(shí)產(chǎn)生的異?;蛘弑罎⑿畔?,需要增加讀取日志、外部存儲(chǔ)讀寫和網(wǎng)絡(luò)通信等權(quán)限. 額外權(quán)限的提升,使得應(yīng)用程序一旦被攻擊,也就能夠使得惡意代碼在一個(gè)較高權(quán)限的環(huán)境中運(yùn)行,增加了惡意代碼的威脅程度.
② 開發(fā)者對(duì)于加殼服務(wù)的過于信任,導(dǎo)致在采用加殼服務(wù)后,在一定程度上忽視了安全編碼的重要性. 加殼服務(wù)的核心目的在于對(duì)程序的代碼和資源進(jìn)行保護(hù),防止暴露核心敏感邏輯和二次篡改. 雖然加殼提高了對(duì)應(yīng)用程序進(jìn)行分析的難度,但是卻無法修復(fù)程序中潛在的安全問題.
以下3類是加殼程序樣本脫殼后,增長數(shù)目較多的威脅類型.
① 安全套接層SSL的不合理使用. SSL為數(shù)據(jù)在不可信網(wǎng)絡(luò)中的安全傳輸提供了保障. 許多應(yīng)用程序均使用了包含SSL子層的通信協(xié)議(例如HTTPS)完成與服務(wù)器之間的數(shù)據(jù)傳輸. 但是錯(cuò)誤的調(diào)用相關(guān)函數(shù),或者對(duì)參數(shù)的設(shè)置不合理,將導(dǎo)致整個(gè)通信過程不再安全. 例如,在掃描的脫殼后樣本中,有67%設(shè)置了ALLOW_ALL_HOSTNAME_VERIFIER屬性,使得應(yīng)用在與遠(yuǎn)程服務(wù)器建立連接時(shí),不會(huì)檢查SSL證書的Common Name,任何持有有效證書的攻擊者將能進(jìn)行中間人攻擊[9],在通信過程中進(jìn)行數(shù)據(jù)的竊取和偽造.
② 文件屬性全局可讀或全局可寫. Android系統(tǒng)沙箱機(jī)制保證了每個(gè)應(yīng)用程序無法隨意訪問其他應(yīng)用程序的資源. 然而當(dāng)應(yīng)用程序錯(cuò)誤的設(shè)置自身私有數(shù)據(jù)屬性時(shí),將極大降低沙箱隔離的有效性,導(dǎo)致其它任何程序都能讀取或改寫其文件內(nèi)容. 脫殼后樣本中有73%設(shè)置了MODE_WORLD_READABLE或MODE_WORLD_WRITEABLE文件屬性.
③ WebView中使用addJavascriptInterface帶來的威脅. 應(yīng)用程序經(jīng)常使用WebView類來在應(yīng)用中內(nèi)置一個(gè)瀏覽器組件,同時(shí)也可以通過addJavascriptInterface函數(shù)來往WebView中注入Java對(duì)象,這使得JavaScript代碼能調(diào)用注入Java對(duì)象中的公有方法. 在Android 4.2以及之前的系統(tǒng)中,攻擊者能利用這個(gè)特性,通過反射的方式訪問被注入Java對(duì)象的所有公有域,甚至以應(yīng)用程序的權(quán)限執(zhí)行任意代碼[10].
綜上所述,對(duì)應(yīng)用加殼雖然起到了防止應(yīng)用被逆向破解和惡意竄改的作用,但由于殼代碼本身不會(huì)改變應(yīng)用原本的代碼邏輯,存在于應(yīng)用內(nèi)的安全問題并不能得到修補(bǔ),開發(fā)者不能因使用了加殼服務(wù)而忽視了安全編碼的重要性. 同時(shí),加殼本身也為應(yīng)用引入了一定風(fēng)險(xiǎn),一旦應(yīng)用被惡意攻擊,所造成的危害也會(huì)更大. 這與通常認(rèn)為加殼提升了安全的直覺是相矛盾的.
本文設(shè)計(jì)并實(shí)現(xiàn)了一種多層次的自動(dòng)化通用Android脫殼系統(tǒng),能正確還原出加殼應(yīng)用中被加密的代碼邏輯,供靜態(tài)分析工具使用. 實(shí)驗(yàn)表明,該系統(tǒng)能對(duì)市面上主流加殼服務(wù)保護(hù)后的應(yīng)用進(jìn)行正確脫殼. 利用該系統(tǒng),本文對(duì)市場(chǎng)上被加殼的應(yīng)用程序進(jìn)行安全性評(píng)估,證明了脫殼系統(tǒng)的實(shí)際應(yīng)用價(jià)值. 實(shí)驗(yàn)發(fā)現(xiàn)加殼應(yīng)用比未加殼應(yīng)用存在更多的安全問題,其原因在于加殼技術(shù)對(duì)原應(yīng)用程序引入了更多的安全風(fēng)險(xiǎn),及開發(fā)者可能過于信任加殼服務(wù)后忽視了安全編碼的重要性. 加殼廠商和程序開發(fā)者應(yīng)引起重視,進(jìn)一步提高相關(guān)代碼的安全性.