朱旭超 徐 建
(南京理工大學計算機科學與工程學院 南京 210094)
隨著移動互聯(lián)網(wǎng)和移動智能終端的普及和快速發(fā)展,移動應用程序的數(shù)量呈爆發(fā)式增長,其中Android平臺智能終端及其應用占據(jù)市場主導地位。然而,面對日益增長的應用市場,App被盜版后加入惡意代碼的情況越來越嚴重,部分破壞者利用這些惡意程序收集用戶隱私、篡改數(shù)據(jù),給用戶帶來巨大的經(jīng)濟利益損失及安全威脅。攻擊者為了更廣泛地傳播Android惡意應用,會將惡意代碼注入并重打包到當前市場上流行的Android應用程序中,并通過第三方電子市場、Android應用程序分享論壇等途徑進行傳播[9]。
由于Android[15]系統(tǒng)的權(quán)限控制機制,用戶往往在不知道Apk應用具體需要哪些權(quán)限時,在使用Apk前就需要對Apk所需要的權(quán)限進行授權(quán)。這往往給了惡意應用以可趁之機,通過申請文件讀寫,短信讀寫等敏感權(quán)限,盜取用戶信息[10]。
目前,對于Android平臺的安全保護主要有代碼混淆,安全加固,權(quán)限控制三個方面。目前的權(quán)限控制基本是通過第三方應用,如Jinseong Jeon等提出的 Dr.Android[2]以及 Michael Backes等提出的AppGuard[4]等。這些第三方應用往往需要獲取ROOT權(quán)限,通過廣播監(jiān)聽等方式,對于敏感權(quán)限進行監(jiān)控和攔截。然而獲取ROOT權(quán)限往往會對用戶手機的安全性能造成隱藏危害,比如信息泄露風險,系統(tǒng)危害,軟件危害等。此外,有些權(quán)限控制方面的研究通過修改安卓內(nèi)核,在內(nèi)核中加入監(jiān)聽模塊從而實現(xiàn)權(quán)限控制的效果。如Xueqiang Wang等提出的DeepDroid[3]和Stephen Smalley提出的SE?Droid[1]等。這些方案都需要對用戶的Android的系統(tǒng)進行一定程度上的修改,而這往往具有很大的風險,會降低系統(tǒng)的穩(wěn)定性,同時具有較高門檻,普及難度較大[12]。
針對存在的問題,本文提出一種基于smali注入的敏感 API攔截方法研究,通過 smali[5]注入的方式,對程序源代碼進行一些修改,并分析敏感權(quán)限,映射出對應的敏感API,通過對系統(tǒng)中的敏感API進行攔截,從而實現(xiàn)在不需要ROOT的情況下,在Apk運行中對敏感權(quán)限的提醒和攔截的功能。
Dalvik虛擬機是Android系統(tǒng)框架的核心組成部分之一,Android系統(tǒng)實際上很大部分是由java語言編寫的。Android軟件安裝包Apk文件,本質(zhì)上是一種zip壓縮文件,其核心文件是classes.dex。dex文件由該android應用對應工程中所有的java類編譯生成的。由于一般無法獲得一個android應用的源代碼,因此可以利用工具對dex文件進行反編譯,獲得dalvikbytecode文件,即smali文件,從而實現(xiàn)權(quán)限的攔截注入。
具體過程如圖1所示,主要分為四個部分:首先確認敏感權(quán)限,通過Pscout構(gòu)造敏感權(quán)限-API映射表;然后獲取dex文件,使用baksmali工具將dex文件轉(zhuǎn)化為smali文件;接著通過映射表定位敏感API位置,針對smali文件中三類方法調(diào)用注入攔截模塊,最后使用smali工具將修改過的smali文件還原為dex文件并重打包,簽名。
圖1 敏感API攔截系統(tǒng)基本流程
首先,進行權(quán)限攔截前,需要先確認想要攔截的相關(guān)敏感權(quán)限。在Android中,權(quán)限模型是嵌入在Android框架中的,該框架公開了一個應用程序編程接口(API),其中包含用于開發(fā)人員與系統(tǒng)資源交互的類和方法。如果調(diào)用了某個API,這個API方法涉及到隱私或安全性問題,這個時候框架會檢查調(diào)用者是否被明確地授予了相應的權(quán)限[7]。所以說權(quán)限模型對應用程序的開發(fā)過程造成了影響,因為開發(fā)者必須為其所使用的每一個API申請使程序正常工作的權(quán)限。
對于敏感權(quán)限攔截來說,需要攔截特定的API,因此需要建立“權(quán)限-API”映射關(guān)系。然而,由于Android平臺的開放性,并且官方總是不給出最新的、清晰的映射關(guān)系,開發(fā)者經(jīng)常為了方便而過多地申請權(quán)限[14],而Android又缺乏權(quán)威機構(gòu)做規(guī)范檢查,這使得Android平臺冗余授權(quán)的現(xiàn)象普遍存在[11]??偟膩碚f,建立Android系統(tǒng)中權(quán)限和API清晰明確的映射關(guān)系是必不可少的。
“權(quán)限-API”映射關(guān)系管理模塊需要建立“權(quán)限-API”的映射關(guān)系[13],還需要提供一些其他的輔助功能,例如檢索功能,包括根據(jù)API檢索其需要申請的權(quán)限、根據(jù)權(quán)限檢索該需要該權(quán)限對應的API。
具體的實現(xiàn)方式:1)通過查看Android官方文檔,從中篩選出特定的敏感權(quán)限,如android.tele?phony.SmsManager為短信收發(fā)相關(guān)權(quán)限,可以將其認定為敏感權(quán)限;2)構(gòu)造“權(quán)限-API”之間映射關(guān)系,構(gòu)造過程可以查看Android官方文檔,還可以進行動態(tài)測試等方法,主要參考現(xiàn)有的PScout工具,構(gòu)建權(quán)限和API之間多對多的映射關(guān)系,大致流程如圖2所示;3)將映射關(guān)系存儲到數(shù)據(jù)庫,構(gòu)建敏感API表;4)實現(xiàn)根據(jù)權(quán)限檢索API、根據(jù)API檢索權(quán)限的功能。
圖2 PScout映射構(gòu)建流程
2.3.1 Dalvikbytecode層原方法修改
由于要從dalvikbytecode層通過smali注入[8]的方式,對敏感權(quán)限映射的API進行攔截,因此就需要掌握dalvikbytecode方法調(diào)用原理。Dalvikbyte?code主要有三種類型的調(diào)用方法:靜態(tài)方法,實例方法和構(gòu)造方法,分別以invoke-static,invoke-vir?tual,invoke-direct等三個smali引用關(guān)鍵字開始。不同的調(diào)用方法攔截方法不盡相同。
1)靜態(tài)方法:使用static關(guān)鍵字進行修飾,被調(diào)用時必須與類名一起調(diào)用,而無需創(chuàng)建對應實例。對于這種靜態(tài)方法,可以在攔截類中創(chuàng)建一個同名,且同返回類型的方法。比如對于一條靜態(tài)方法調(diào)用smali語句:invoke-static{v0,p0},Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I,要攔截android.util.log.d這一方法,可以在攔截類nde?fend中構(gòu)造一個ndefend.android.util.log.d的方法。這個新方法的參數(shù)和返回值與原方法相同。
2)實例方法:實例方法與靜態(tài)方法不同,實例方法在調(diào)用前必須要創(chuàng)建對應的實例對象,使用“對象名·方法名”的方式進行調(diào)用。對于實例方法,可以在攔截類中創(chuàng)建一個同名,同返回類型的方法,但是在傳遞的參數(shù)方面,新方法會接受一個被攔截類的實例的一個新參數(shù)。比如對于一條實例方法調(diào)用 smali語句:invoke-virtual{v6,v7},Landroid/widget/EditText;->setEnabled(Z)V,要攔截android.widget.EditText.setEnabled這一方法,可以在攔截類ndefend中構(gòu)造一個ndenfed.android.widget.EditText.setEnabled的新方法,但是與原方法不同的地方在于,新方法接收的參數(shù)除了原本的boolean型參數(shù)外,還要額外接收一個android.wid?get.EditText的實例。
3)構(gòu)造方法:構(gòu)造方法用來創(chuàng)建類的實例。構(gòu)造方法沒有返回值,對于構(gòu)造方法來說,一般不涉及敏感API,因此一般不需要進行攔截。對于少數(shù)需要攔截的構(gòu)造方法,可以使用構(gòu)造一個“工廠”類型的新方法的方式進行攔截。比如一條構(gòu)造方法調(diào)用smali語句:invoke-direct{p0},Landroid/app/Activity;-><init>()V,要攔截 android.app.Activity的構(gòu)造方法。與之前類似,可以在攔截類ndefend中構(gòu)造一個ndenfend.android.app.Activity的方法,新方法與原方法有一樣的參數(shù),但是返回值為an?droid.app.Activity。
針對上述三種調(diào)用方法,通過構(gòu)造對應的新方法來對原方法進行替換,使程序在運行時調(diào)用構(gòu)造的新方法而不是原方法。并且在新方法中,通過反射方式,實現(xiàn)原方法本身的功能,并在其基礎上,加入日志記錄模塊以及權(quán)限攔截模塊,如圖3所示。
圖3 構(gòu)造新方法結(jié)構(gòu)
2.3.2 日志記錄模塊及攔截模塊實現(xiàn)
日志記錄模塊及攔截模塊是通過smali注入的方式來實現(xiàn)的。之前的smali注入就是在軟件源代碼中添加幾行代碼,目的在于簡單地改變軟件功能,或查看修改運行中的某幾個寄存器的數(shù)值。然而在smali注入時需要注意,添加的注入代碼所使用的寄存器不能重復,否則影響后續(xù)代碼的執(zhí)行。因此,當注入代碼較多時,這個要求就很難實現(xiàn)了。為了解決這個問題,可以把需要注入的日志記錄和權(quán)限攔截的smali代碼寫進專門的smali文件,然后在要注入的地方調(diào)用smali里預先記錄的方法即可,這樣我們只用在源代碼中注入一行代碼,并且不會影響其他寄存器的使用。
例如對于一段簡單的smali代碼,如圖4所示,如果想要對v1,v2兩個寄存器進行日志記錄,一般使用log.d的smali注入方式,如圖5所示??梢钥闯?,這不光需要對代碼進行插入,還需要對寄存器個數(shù)等全局參數(shù)進行修改。
圖4 smali注入前代碼
當要注入多個模塊進行修改時,這種注入方式不僅變更工作量大,而且由于寄存器個數(shù)限制等原因,容易造成源程序崩潰,注入失敗。因此,可以預先創(chuàng)建crack.smali文件,通過調(diào)用創(chuàng)建好的smali文件進行注入。如圖6所示就是一個簡單的日志記錄smali代碼:
圖5 smali注入后代碼
圖6 日志記錄smali代碼
只需要將這樣一段smali模塊代碼放入原安卓應用安裝包中,然后在源程序中進行調(diào)用即可,這最大限度地減小了需要注入的代碼長度,同時不會影響源代碼的運行,如圖7所示,只要插入一行語句即可,同時不需要對寄存器等全局參數(shù)進行修改:
圖7 改進后的smali注入后代碼
為了驗證日志及攔截模塊效果,構(gòu)造測試用例以測試模塊效果。為了易于驗證,設計了一款模擬收發(fā)短信的安卓應用。該應用通過調(diào)用系統(tǒng)的SMSManager等敏感API,可以實現(xiàn)與系統(tǒng)自帶信息相類似的收發(fā)短信的功能。程序由Java實現(xiàn),敏感API日志記錄以txt形式保存在手機本地sd卡中。
運行njust.defend.java注入模塊,模塊首先調(diào)用baksmali工具,將Apk文件中的classes.dex文件轉(zhuǎn)化為classes對應的smalli文件。將事先編譯好的LogRecord.smali和Intercept.smali放入classes.dex文件夾,接著對該文件夾下所有的smali文件進行遍歷,對于其中的API調(diào)用函數(shù),逐條與敏感API數(shù)據(jù)庫相比對,確定需要替換的敏感API,并構(gòu)建對應新的API調(diào)用方法。
將修改過后的smali文件重新轉(zhuǎn)化為dex文件并重打包簽名后的app安裝到手機上,運行時結(jié)果如圖8所示,會跳出與用戶交互的可選擇彈窗,即可提醒用戶應用在調(diào)用的敏感權(quán)限,即獲取用戶手機號碼,由用戶選擇是否允許該行為。同時也會在手機本地生成Log.txt的日志文件,如圖9所示。
圖8 用戶交互權(quán)限控制彈窗
圖9 log日志文件
為解決在不ROOT且不加裝第三方應用的情況下對android手機應用進行權(quán)限防護,本文利用Pscout,baksmali和 smali等工具,設計并實現(xiàn)了一種基于smali注入的android手機應用敏感權(quán)限日志記錄和攔截的相關(guān)模塊。實驗以正常短信發(fā)送程序被注入惡意短信攔截smali代碼為例,進行smali代碼注入的實驗,成功打印并攔截到短信收發(fā)、號碼讀取等敏感權(quán)限。但是該方法也存在一定的不足,對于一些進行過加固的Apk,通過反編譯得到的smali文件往往有缺失,因此難以使用smali代碼注入的,這也是smali代碼注入的一個局限性。對于這種情況,可以選擇結(jié)合現(xiàn)有的一些脫殼的手段對smali文件進行還原再進行smali注入。