周立博,梁 彬,游 偉,黃建軍,石文昌
中國人民大學(xué)信息學(xué)院 北京 中國 100872
根據(jù)國際數(shù)據(jù)公司IDC 發(fā)布的統(tǒng)計(jì)資料,近五年來,安卓系統(tǒng)的市場份額穩(wěn)定在85%以上[1],安卓應(yīng)用生態(tài)一片繁榮。但與此同時,安卓應(yīng)用也面臨著嚴(yán)重的重打包威脅。Zhou 等人[2]的研究顯示,有85%以上的惡意應(yīng)用是重打包應(yīng)用。
為了有效降低惡意重打包應(yīng)用所帶來的危害,如圖 1 安卓應(yīng)用重打包威脅模型所示,研究人員從開發(fā)者、應(yīng)用市場和應(yīng)用安全服務(wù)商三個角度出發(fā),提出了不同的重打包攻擊對抗方式:①開發(fā)者實(shí)施重打包防御策略,對應(yīng)用進(jìn)行加固,提高攻擊者構(gòu)建重打包應(yīng)用的難度。常見的策略有防篡改檢查[3-4]、代碼混淆[5-7]、應(yīng)用反調(diào)試和信息隱藏等。這種方式部署靈活,開發(fā)者可以根據(jù)需要配置不同的防御策略,保護(hù)通過不同渠道發(fā)布的應(yīng)用。②應(yīng)用市場對應(yīng)用進(jìn)行靜態(tài)重打包應(yīng)用檢測,通過重打包應(yīng)用與原應(yīng)用的相似性[8-17]進(jìn)行檢測,限制重打包應(yīng)用通過應(yīng)用市場傳播。③應(yīng)用安全服務(wù)商在應(yīng)用安裝和執(zhí)行時收集特征信息來進(jìn)行重打包應(yīng)用檢測。常見的檢測方式有安裝時簽名校驗(yàn),運(yùn)行時UI 相似度檢測[18-20]等。
在上述對抗方式中,開發(fā)者利用安卓應(yīng)用重打包工具的實(shí)現(xiàn)缺陷來加固應(yīng)用,中斷圖 1 中的反編譯環(huán)節(jié),是一種有效的重打包防御策略。但目前僅有少數(shù)工作對其進(jìn)行研究,Tim Strazzere[21]指出可以利用反編譯工具解析dex 文件的一個特定缺陷來中斷重打包工具對APK 的解析操作。盡管該缺陷目前已被修復(fù),但證明了該思路的可行性。自然地,我們想要知道,如何系統(tǒng)化地發(fā)現(xiàn)更多重打包工具中的缺陷?
針對這一問題,我們提出了一種面向重打包對抗的重打包工具可利用缺陷檢測方法。如圖 2 所示,本方法能夠盡可能地檢出重打包工具中的可利用缺陷。開發(fā)者可以利用這些缺陷對應(yīng)用進(jìn)行加固,加固后的應(yīng)用可以在目標(biāo)安卓設(shè)備中正常運(yùn)行而無法被重打包工具正常解析。與其它由開發(fā)者實(shí)施的重打包攻擊對抗技術(shù)(如防篡改檢查、代碼混淆、應(yīng)用反調(diào)試和信息隱藏等)相比,本文提出的方法具有易于實(shí)施、運(yùn)行時開銷小等優(yōu)勢。同時,該方法與其它加固方法互補(bǔ),能夠與其他加固方法共同使用,進(jìn)一步提高應(yīng)用抗重打包的能力。
本方法利用重打包工具中缺陷與異常的聯(lián)系將對缺陷的檢測轉(zhuǎn)換到對重打包工具中潛在異常點(diǎn)的研究上來。這一轉(zhuǎn)換基于我們的以下觀察:①重打包工具中的文件解析缺陷能夠?qū)е缕鋵PK 的解析失敗,使得重打包工具不能輸出正確的反編譯結(jié)果。這一特性可用于對安卓應(yīng)用進(jìn)行加固。②重打包工具中的文件解析缺陷主要由程序執(zhí)行過程中未經(jīng)處理的異常引起。現(xiàn)有工作[21]中對重打包工具解析缺陷的利用證明了我們觀察的合理性。此外,我們在研究過程中發(fā)現(xiàn),一些知名的應(yīng)用程序(如作業(yè)幫、Instagram)也基于類似觀察進(jìn)行應(yīng)用加固。
本工作的主要貢獻(xiàn)有以下兩點(diǎn):
1) 提出了一種面向重打包對抗的重打包工具解析APK 文件的實(shí)現(xiàn)缺陷檢測方法,以發(fā)現(xiàn)可利用的缺陷來加固應(yīng)用。該方法利用重打包工具文件解析缺陷與異常的聯(lián)系,把對缺陷的檢測轉(zhuǎn)換為對重打包工具中潛在異常點(diǎn)的定位、觸發(fā)和可利用性確認(rèn)。
2) 我們以當(dāng)下最流行的重打包工具Apktool[22]作為實(shí)驗(yàn)對象,在Apktool 2.4.1 中找到了12 個未知的可利用的解析缺陷。并利用這些缺陷對真實(shí)應(yīng)用進(jìn)行了加固,加固后的應(yīng)用不能被Apktool 重打包,證明了方法的實(shí)際價值。
為了對應(yīng)用進(jìn)行重打包,攻擊者可能會使用多種重打包工具對APK(Android package)文件進(jìn)行解析。常見的重打包工具有Apktool、Jadx、dex2Jar 等。在眾多重打包工具中,Apktool 使用最為廣泛,是本文的重點(diǎn)研究對象。為了便于讀者對本文檢測方法的理解,本節(jié)對Apktool 和重打包工具中的文件解析異常進(jìn)行簡要介紹。
Apktool 是主要由Ryszard Wi?niewski 與Connor Tumbleson 開發(fā)和維護(hù)的開源安卓重打包工具。Apktool 功能完善,能夠反編譯resources.arsc、dex文件、png 格式的圖像文件和二進(jìn)制的xml 文件(包括AndroidManifest.xml 文件與res 目錄下壓縮后的xml 資源文件等)并在之后對其進(jìn)行回編譯。其使用Java 語言實(shí)現(xiàn)對APK 的反編譯,利用安卓官方提供的打包工具aapt 或aapt2 進(jìn)行回編譯生成未簽名的重打包應(yīng)用。
APK 文件本質(zhì)上是ZIP 格式的壓縮文件,重打包功能提供對壓縮文件中部分或全部文件的解析功能。重打包工具對文件的解析通常是順序進(jìn)行的,即一次解析壓縮文件中一個或一組文件。當(dāng)重打包工具中存在文件解析缺陷時,重打包工具可能會因?yàn)槟承┪募馕鍪《K止運(yùn)行導(dǎo)致APK 解析失敗。而重打包工具的文件解析過程通?;谔囟ǖ奈募袷?。當(dāng)遇到不符合工具開發(fā)者設(shè)定格式的文件時,程序通常會產(chǎn)生異常,若開發(fā)者認(rèn)為該異常無法被處理,則重打包工具則會因?yàn)樵摦惓6K止執(zhí)行。但如果此時安卓操作系統(tǒng)能夠?qū)υ搼?yīng)用正常解析,我們就可以認(rèn)為重打包工具在實(shí)現(xiàn)上具有缺陷。由這一思路出發(fā),本文提出了重打包工具解析缺陷的檢測方法,第三節(jié)是對這一方法的具體介紹。
本方法的指導(dǎo)思想是通過檢測重打包工具解析APK 文件的實(shí)現(xiàn)缺陷,以發(fā)現(xiàn)能夠用于加固應(yīng)用的可利用缺陷。我們設(shè)計(jì)了包含二次模糊測試的缺陷檢測方法,通過尋找可利用的異常點(diǎn)來檢測重打包工具中的缺陷。我們以當(dāng)下最流行的重打包工具Apktool 為研究對象,對本方法的具體實(shí)現(xiàn)進(jìn)行介紹。
圖3 是本方法的總體流程圖。如圖所示,本方法分可主要分為潛在異常點(diǎn)定位、基于模糊測試的異常觸發(fā)和包含二次模糊測試的異常點(diǎn)可利用性確認(rèn)三個階段。首先,在異常定位階段,我們使用靜態(tài)分析的方法對應(yīng)用代碼進(jìn)行掃描,確定潛在的異常點(diǎn);其次,在異常觸發(fā)階段,我們使用模糊測試的方式來生成測試應(yīng)用,根據(jù)Apktool 解析測試應(yīng)用的日志判斷異常是否被觸發(fā);最后,在異常點(diǎn)可利用性確認(rèn)階段,確認(rèn)潛在異常點(diǎn)能否用于應(yīng)用加固,并對部分無法直接確認(rèn)可利用性的異常點(diǎn)進(jìn)行第二次模糊測試。
下面,我們對本方法的每個環(huán)節(jié)的具體實(shí)現(xiàn)進(jìn)行詳細(xì)介紹。
在進(jìn)行異常定位前,我們首先要了解Apktool 中的異常。由前文我們對Apktool 的介紹可知,Apktool進(jìn)行APK 解析部分的代碼由Java 語言編寫。Java 語言提供了良好的錯誤處理機(jī)制,其使用Throwable 類的眾多子類來描述各種不同的異常,為開發(fā)者提供了try,catch 語句捕獲和處理異常。
在本方法中,我們將Java 語言中的潛在異常點(diǎn)分為兩類:顯式異常點(diǎn)和隱式異常點(diǎn)。顯式異常點(diǎn)指使用throw 關(guān)鍵字拋出異常的語句,如圖 4 中第12行和第18 行所示。隱式異常點(diǎn)指的是,開發(fā)者沒有主動進(jìn)行異常處理的可能導(dǎo)致運(yùn)行時異常的代碼塊。圖 4 中的array函數(shù)包含了一個隱式異常點(diǎn)實(shí)例,在第23 行,參數(shù)x沒有經(jīng)過檢查就被當(dāng)作數(shù)組初始化的下標(biāo)使用。當(dāng)參數(shù)x為負(fù)值時,程序會在運(yùn)行時拋出異常Java.lang.NegativeArraySizeException,同時沒有異常處理語句對此異常進(jìn)行捕獲處理。在本工作中,我們僅關(guān)注那些可能導(dǎo)致重打包工具解析終止的異常點(diǎn),過濾掉被已被捕獲處理的異常點(diǎn)。圖4 中test1函數(shù)僅在invoke函數(shù)中被調(diào)用(第3 行),其拋出的異常會在invoke函數(shù)中被捕獲處理(4~6 行),因此我們將忽略test1函數(shù)中的異常點(diǎn)。
為了進(jìn)行潛在異常點(diǎn)的定位,我們實(shí)現(xiàn)了基于Soot[23]的代碼掃描工具。其工作流程如圖5 所示。首先,掃描器將輸入的Java 字節(jié)碼轉(zhuǎn)換為Jimple 中間代碼,生成程序的函數(shù)調(diào)用圖(Call Graph,CG)和控制流圖(Control Flow Graph,CFG)。在生成的CFG 中包含從throw 子句到catch 模塊的邊和從隱式異常點(diǎn)的前驅(qū)節(jié)點(diǎn)到異常處理語句的邊。我們可以在遍歷過程中獲得可能的異常點(diǎn)。然后,如算法1 所示,通過嘗試匹配異常點(diǎn)與其try 模塊來確認(rèn)其是否被捕獲處理,過濾掉那些已經(jīng)被捕獲處理的異常點(diǎn)。
算法1 異常過濾
由于不是所有異常點(diǎn)都能夠被觸發(fā),我們需要通過異常觸發(fā)測試篩選出可觸發(fā)的潛在異常點(diǎn)。如圖 6 所示,這一階段的主要步驟包括:①通過重打包工具插樁和測試獲得異??赡鼙挥|發(fā)時所處的解析階段和對應(yīng)的解析文件類型;②根據(jù)待檢測的異常和其對應(yīng)解析文件類型生成變異應(yīng)用;③使用Apktool 解析測試應(yīng)用,確認(rèn)異常觸發(fā)情況。
異常點(diǎn)對應(yīng)觸發(fā)文件類型關(guān)系獲取
本階段的目的是獲得APK 中不同的文件類型可能觸發(fā)的異常點(diǎn),以此加速后續(xù)的模糊測試。在整個方案中,該步驟只需進(jìn)行一次。我們首先對Apktool正常解析APK 獲得的日志進(jìn)行分析,發(fā)現(xiàn)Apktool對APK 中不同部分的解析相對獨(dú)立,每一段解析開始時均會輸出特定的日志??梢愿鶕?jù)日志區(qū)分Apktool 開始解析不同類型文件的順序,在該日志輸出處插入相應(yīng)的開關(guān)變量,標(biāo)識相應(yīng)的解析流程。Apktool 對不同類型文件的解析順序如表 1 所示。
表1 Apktool 對安卓應(yīng)用中不同類型文件的解析順序Table 1 The order of parsing files of different types in Apks with Apktool
接下來我們依據(jù)Apktool 的解析流程和已獲得的異常點(diǎn)進(jìn)行代碼插樁操作。圖 7 展示了我們的插樁結(jié)果:在Apktool中加入Phase類,使用靜態(tài)域now表明當(dāng)前屬于哪個分析階段。在異常點(diǎn)所在控制流的第一個條件跳轉(zhuǎn)語句前添加日志輸出語句,記錄可能觸發(fā)的異常。
插樁工作完成后,我們使用插樁后的Apktool 對測試應(yīng)用進(jìn)行解析,獲得輸出日志之后就可以根據(jù)日志信息確定對應(yīng)異常觸發(fā)與APK 中文件類型的對應(yīng)關(guān)系。圖8 展示了插樁后的Apktool 解析多看閱讀應(yīng)用的實(shí)例,根據(jù)日志片段,我們可以看到StringBlock 類中的getUtf8與getUtf16函數(shù)中存在的異常可能會在AndroidManifest.xml 和res 目錄下資源文件解析的過程中被觸發(fā)。
·變異應(yīng)用生成
由于APK 本質(zhì)上是一個ZIP 格式的壓縮文檔,而ZIP 文件中存在大量文件有效性檢查。例如,ZIP文件的本地文件頭中的CRC-32 校驗(yàn)值,核心目錄頭中存儲的其相對本地目錄頭的偏移量,對這些變量的修改會導(dǎo)致APK 無法通過ZIP 格式校驗(yàn)。
為此,我們采用變異解壓后的文件,再重新壓縮,簽名的方式生成用于測試的變異應(yīng)用。本質(zhì)而言,我們的模糊測試是一種以字節(jié)為單位進(jìn)行變異的針對特定目標(biāo)文件和特定異常點(diǎn)的定向模糊測試。其中的關(guān)鍵環(huán)節(jié)包括變異文件選擇和具體的文件變異方式。
1) 變異文件選擇
首先根據(jù)需要探測的異常點(diǎn)和APK 中文件類型之間的對應(yīng)關(guān)系,確定可能觸發(fā)異常點(diǎn)的文件類型。接著遍歷APK 內(nèi)的文件,從滿足類型且在之前的測試中沒有被選中的文件中,找到體積最小的文件作為輸出結(jié)果。通過變異文件的選擇,我們可以減小每次測試過程中進(jìn)行變異的選擇范圍,提高模糊測試效率。
2) 具體的文件變異方式如圖 9 所示,對于每一個文件,我們以單字節(jié)為基本單位對文件進(jìn)行變異。這主要是因?yàn)橹卮虬ぞ咄ǔR宰止?jié)作為單位進(jìn)行讀取,因此以字節(jié)為基本單位進(jìn)行變異是一個自然的選擇。從文件頭開始,逐字節(jié)將原始位置變異為0x00-0xFF 之間的一個隨機(jī)值。每變異一個字節(jié)生成一個新文件,用“源文件名_文件名_位置_變異值”的方式命名變異后的文件。在后續(xù)的測試過程中,Apktool 測試輸出的日志同樣按照此規(guī)律進(jìn)行命名,根據(jù)日志文件名就可以確定對應(yīng)測試應(yīng)用變異的字節(jié),避免因存儲大量變異應(yīng)用而帶來的存儲開銷。
·Apktool 異常觸發(fā)確認(rèn)
生成變異應(yīng)用以后,我們使用Apktool 對測試應(yīng)用進(jìn)行解析,生成對應(yīng)的日志文件。此時,若日志文件中存在報錯信息且應(yīng)用解析提前停止,我們就認(rèn)為異常被觸發(fā),可以從日志文件中得到異常的相關(guān)信息。否則,我們認(rèn)為這次變異沒有導(dǎo)致異常被觸發(fā)。
為了保證利用缺陷加固的應(yīng)用在使Apktool 解析出錯的同時能夠在目標(biāo)安卓設(shè)備上正常運(yùn)行,我們對應(yīng)用進(jìn)行異常點(diǎn)可利用性確認(rèn)。確認(rèn)流程如圖 10所示,包含兩個主要流程:執(zhí)行監(jiān)測和第二次模糊測試。下面對這兩階段進(jìn)行詳細(xì)介紹。
·執(zhí)行監(jiān)測
在應(yīng)用執(zhí)行監(jiān)測環(huán)節(jié),我們需要判斷變異應(yīng)用能否在目標(biāo)安卓系統(tǒng)上正常運(yùn)行。因此,我們需要對應(yīng)用的正常運(yùn)行狀態(tài)進(jìn)行刻畫??紤]到變異應(yīng)用可能會影響原始應(yīng)用的正常功能,而從市場下載的應(yīng)用正常功能對于測試而言是未知的。同時可能存在其他反重打包措施導(dǎo)致變異應(yīng)用無法直接運(yùn)行。因此我們考慮直接開發(fā)一個測試應(yīng)用作為兩次模糊測試的種子應(yīng)用。為了使種子應(yīng)用能夠觸發(fā)盡可能多的解析異常,我們根據(jù)合法APK 所可能包含的內(nèi)容,在應(yīng)用中添加對應(yīng)資源,如在res/目錄下添加menu,assets 等非必須資源項(xiàng),并在相應(yīng)的Activity 進(jìn)行加載和調(diào)用。同時為了便于測試,我們將對不同資源的訪問分布在不同的Activity 下,通過配置Activity 的
·進(jìn)一步模糊測試
在執(zhí)行檢測過程中,我們發(fā)現(xiàn)一些異常能夠使Apktool 在解析APK時崩潰,同時對應(yīng)變異應(yīng)用無法在安卓手機(jī)上正常執(zhí)行。圖 12 展示了一個此類待確認(rèn)異常。
在對測試應(yīng)用中res/layout 目錄下一個布局文件進(jìn)行變異后,該異常被觸發(fā)并導(dǎo)致Apktool 崩潰,但變異應(yīng)用無法在安卓系統(tǒng)上正常運(yùn)行。圖 13 展示了其在實(shí)際執(zhí)行中產(chǎn)生的崩潰日志。
我們認(rèn)為對于此類異常已經(jīng)體現(xiàn)了重打包工具與安卓系統(tǒng)在解析APK 上的差異,通過后續(xù)人工分析造成差異的原因可能將此類異常利用起來。接著我們將此變異測試應(yīng)用作為模糊測試的種子,對該文件進(jìn)行變異。根據(jù)日志分析判斷對應(yīng)的測試應(yīng)用所變異的字節(jié)與待確定異常是否相關(guān)。
在本章,我們將用實(shí)驗(yàn)來評估我們的方案在Apktool 上的具體實(shí)現(xiàn)。首先,我們對實(shí)驗(yàn)中的環(huán)境和使用的數(shù)據(jù)做簡要介紹(4.1 節(jié));接著,我們對通過實(shí)驗(yàn)找到的可利用異常進(jìn)行介紹,并對其中的部分實(shí)例進(jìn)行解析(4.2 節(jié));然后,我們對本方法的性能開銷進(jìn)行分析(4.3 節(jié));最后,我們以LinkedIn 為例,展示了兩個可利用異常對實(shí)際應(yīng)用進(jìn)行加固的過程和效果(4.4 節(jié))。
我們在Java 環(huán)境中實(shí)現(xiàn)了對Apktool 字節(jié)碼的靜態(tài)分析和插樁工作,使用Python 語言編寫腳本進(jìn)行模糊測試和應(yīng)用在安卓設(shè)備上運(yùn)行情況監(jiān)測。實(shí)驗(yàn)用到的PC 配置為16GB 內(nèi)存,6 個2.1GHz 內(nèi)核和1TB 硬盤,安卓手機(jī)型號是小米6,安卓系統(tǒng)版本為9.0。
我們的實(shí)驗(yàn)主要有以下兩個數(shù)據(jù)來源:
1) 測試應(yīng)用:測試應(yīng)用集合來自豌豆莢與Apkpure。其中包含豌豆莢應(yīng)用分類排行榜14 個分類中,每類的前50 個應(yīng)用,Apkpure 中分類排行榜32個分類中每類前10 個應(yīng)用,總測試應(yīng)用共計(jì)有1020個。在異常點(diǎn)對應(yīng)觸發(fā)文件類型關(guān)系獲取階段,我們使用插樁后的Apktool 對測試應(yīng)用進(jìn)行解析,獲得異常和APK 壓縮包中文件類型之間的對應(yīng)關(guān)系。
2) 種子應(yīng)用:我們在進(jìn)行模糊測試時使用自己開發(fā)的測試應(yīng)用作為種子應(yīng)用,以避免應(yīng)用市場中包含重打包檢測,代碼混淆和資源混淆的應(yīng)用對實(shí)驗(yàn)結(jié)果造成影響。
通過實(shí)驗(yàn)與人工分析,在Apktool 2.4.1 上共發(fā)現(xiàn)343 個異常,總共確認(rèn)了12 個未知的可利用的缺陷,與缺陷相關(guān)的可利用異常點(diǎn)的詳細(xì)信息如表2所示,下面我們對找到的異常及其拋出這些異常的解析缺陷進(jìn)行分析。
表2 可利用異常點(diǎn)Table 2 Available exception points
·拋出顯式異常的解析缺陷
圖14 展示了ExtDataInput 類中被確認(rèn)的顯式異常。在異常定位階段,我們能夠通過對代碼的解析,定位到該throw 語句,并逐級檢查該函數(shù)拋出的異常有沒有被調(diào)用者用catch 語句捕獲。最終我們能夠從找到從main函數(shù)到該函數(shù)的路徑,確認(rèn)在main函數(shù)拋出的異常中可能包含此異常,因此將其作為可能的異常。之后在變異arsc 文件的過程中得到的變異應(yīng)用觸發(fā)了該異常,且能夠在目標(biāo)設(shè)備上正常運(yùn)行。由此我們確認(rèn)其是一個可利用異常。
·拋出隱式異常的解析缺陷
圖15 展示了ARSCDecoder 類中的一個隱式異常,該隱式異常同樣與數(shù)組操作相關(guān)。圖中packageCount變量從文件中獲取,后續(xù)作為數(shù)組的大小在初始化時被使用。與StringBlock 類中的例子類似,該值同樣可能為負(fù)值,導(dǎo)致拋出Java.lang.NegativeArraySizeException 異常。
但 Android 系統(tǒng)去解析 APK 時,并不關(guān)心packageCount對應(yīng)的字節(jié)。該解析差異導(dǎo)致此異常被觸發(fā)的同時,應(yīng)用能夠在手機(jī)上正常運(yùn)行。
·需要進(jìn)一步探測的解析缺陷
以3.3 節(jié)我們討論的異常為例,在使用種子應(yīng)用進(jìn)行模糊測試測試的過程中我們注意到,若在第一輪探測中當(dāng)變換res/layout/activity_main.xml 中第64個字節(jié)為0xFF 時,會導(dǎo)致第318 行offset值為負(fù)值,觸發(fā)Java.lang.NegativeArraySizeException 異常。但該應(yīng)用無法在手機(jī)上正常運(yùn)行。于是我們將此變異測試應(yīng)用作為模糊測試的種子進(jìn)行第二輪fuzz操作。
通過這種方式,我們可以發(fā)現(xiàn)異常的關(guān)鍵輸入,如圖 16所示。確認(rèn)了arsc文件中與其對應(yīng)的關(guān)鍵字節(jié),通過觀察可以得知其儲存著值res/layout/activity_main.xml,即我們變異的文件。經(jīng)過進(jìn)一步分析,我們可以從中獲得一種加固應(yīng)用的新方法:向res/layout 目錄下插入無意義的損壞布局文件,同時在對應(yīng)的索引文件中添加相應(yīng)的索引值。這樣由于Apktool 會依據(jù)索引值對APK 中的文件進(jìn)行解析,重打包工具將會在解析到我們添加的損壞布局文件時出錯。而無意義的布局文件不會在系統(tǒng)中被解析,使得加固后的安卓應(yīng)用能夠在目標(biāo)安卓設(shè)備上正常執(zhí)行。
本文方案在實(shí)現(xiàn)上可以大致分為三個階段:潛在異常點(diǎn)定位、異常觸發(fā)和異常可利用性確認(rèn)。在潛在異常點(diǎn)定位階段,我們主要對Apktool 進(jìn)行靜態(tài)分析,這一步驟需要對重打包應(yīng)用的CG 和CFG 進(jìn)行遍歷。靜態(tài)分析階段在整個方案中僅需執(zhí)行一次,即使消耗時間較長也在可接受范圍內(nèi)。在異常觸發(fā)階段,會進(jìn)行大量變異操作并使用Apktool 進(jìn)行解析,消耗時間較長。在異??捎眯源_認(rèn)階段,我們能夠利用異常觸發(fā)階段的結(jié)果,跳過部分可能導(dǎo)致異常的變異探測,從而加速關(guān)鍵字節(jié)的探測過程。每個階段的詳細(xì)耗時情況如表3 所示。
從表3 可以看出,異常查找花費(fèi)時間最少,平均時間在1.05 s 左右,異常觸發(fā)花費(fèi)時間最長,平均每個異常被觸發(fā)需要十分鐘以上。在異常利用階段因?yàn)橐呀?jīng)獲得觸發(fā)階段的數(shù)據(jù),平均每個異常耗時600 s 要低于異常觸發(fā)階段,符合我們的預(yù)期。
表3 各階段耗時統(tǒng)計(jì)Table 3 Time consuming statistics of each stage
在實(shí)例驗(yàn)證階段,我們從豌豆莢和Apkpure 中挑選了9 個真實(shí)應(yīng)用,使用已檢測到的缺陷進(jìn)行應(yīng)用加固驗(yàn)證。9 個應(yīng)用可以按大小分為三組,1~3 號小型應(yīng)用(1~20MB),4~6 號中型應(yīng)用(20~100MB),7~9 號大型應(yīng)用。每組應(yīng)用從來自豌豆莢中的測試應(yīng)用中隨機(jī)選出,為了體現(xiàn)Apkpure 商店與豌豆莢的差異,我們使用Apkpure 特有的應(yīng)用替換部分測試應(yīng)用。得到了最終的真實(shí)應(yīng)用列表,如表 4 所示。
表4 真實(shí)應(yīng)用列表Table 4 Real application list
接下來我們以常見的LinkedIn 應(yīng)用為例,展示我們利用4.2 節(jié)已分析的部分異常點(diǎn)對實(shí)際應(yīng)用的加固效果和加固細(xì)節(jié)。如圖 17 所示,在應(yīng)用加固前后,應(yīng)用功能和用戶界面沒有發(fā)生變化,加固后應(yīng)用能夠在目標(biāo)安卓設(shè)備上正常運(yùn)行。
下面介紹應(yīng)用的加固細(xì)節(jié)。skipCheckShort函數(shù)中異常對應(yīng)的解析缺陷是Apktool 在解析arsc 文件時對Entry 資源項(xiàng)數(shù)值讀取的額外檢查。進(jìn)行檢查的語句為 ARSCDecoder 類readValue方法中的mIn.skipCheckShort((short) 8),該語句檢查讀入的數(shù)值是否為0x08,當(dāng)檢測到的值不是0x08 時,拋出顯式異常。由此,我們首先對LinkedIn 應(yīng)用中arsc 文件的部分Entry 項(xiàng)進(jìn)行修改,將對應(yīng)的0x08 替換成0xFF,如圖 18 所示。
接著用修改后的arsc 文件替換原arsc 文件生成LinkedIn 的重打包應(yīng)用com.linkedin.android_1.apk。重打包應(yīng)用能夠在手機(jī)上正常運(yùn)行,使用Apktool 無法正常進(jìn)行解析,在解析過程中拋出異常:brut.androlib.AndrolibException:Could not decode arsc file。同樣的,我們也可以利用隱式異常使得Apktool 拋出運(yùn)行時異常。圖 19 展示了對readTableHeader函數(shù)中隱式異常的利用。
通過變異arsc 文件起始的第9~12 個字節(jié),使預(yù)期對應(yīng)的packageCount值為–1,最終導(dǎo)致Apktool在解析過程中拋出異常:Exception in thread "main"Java.lang.NegativeArraySizeException。
類似地,我們可以利用其他缺陷對應(yīng)用進(jìn)行加固。加固后的應(yīng)用在目標(biāo)設(shè)備上正常運(yùn)行地同時能夠使Apktool 解析異常。限于文章篇幅,其他異常點(diǎn)的利用情況不再一一贅述。
文件變異方式:在本文中,我們以單字節(jié)為基本單位對文件進(jìn)行變異。這主要是因?yàn)橹卮虬ぞ咄ǔR宰止?jié)作為單位進(jìn)行讀取,因此以字節(jié)為基本單位進(jìn)行變異是一個自然的選擇。另一個可能的選擇是以比特為單位進(jìn)行變異,這種變異方式可能會提高觸發(fā)異常的可能性,但是在模糊測試階段會帶來較大的性能開銷。在未來工作中,我們將深入探索不同變異策略的異常觸發(fā)效果及性能開銷。
方法自動化程度提升:本方法在執(zhí)行檢測環(huán)節(jié),根據(jù)日志判斷應(yīng)用是否在目標(biāo)系統(tǒng)上正常運(yùn)行。目前,應(yīng)用不能正常運(yùn)行的具體原因需要人工對日志內(nèi)容進(jìn)行分析確認(rèn)。在實(shí)驗(yàn)過程中,我們發(fā)現(xiàn)從日志中提取出的關(guān)鍵字能夠反映出應(yīng)用不能正常運(yùn)行的原因。在未來工作中,我們擬設(shè)計(jì)啟發(fā)式規(guī)則,根據(jù)日志內(nèi)容提取出的關(guān)鍵字,確定應(yīng)用崩潰原因。
方法有效性:本工作提出了一種新的應(yīng)用自我保護(hù)策略來對抗安卓應(yīng)用重打包技術(shù)——利用安卓應(yīng)用重打包工具解析APK 的實(shí)現(xiàn)缺陷對應(yīng)用進(jìn)行加固。盡管目前在本方案中發(fā)現(xiàn)的Apktool 解析缺陷可能在后續(xù)版本中被修復(fù),但這一思路能夠被應(yīng)用加固廠商借鑒,將其擴(kuò)展到其他重打包工具如jadx,dex2jar 等,并發(fā)現(xiàn)新版本中可能存在的缺陷。對于攻擊者來說,通過本方案加固的應(yīng)用能夠增加其重打包應(yīng)用的難度。即使攻擊者已經(jīng)獲得了可能會導(dǎo)致重打包工具出錯的異常點(diǎn),也要對重打包工具或加固后的應(yīng)用進(jìn)行修改。提高了其進(jìn)行攻擊的時間成本,在一定程度上能夠起到提高重打包攻擊技術(shù)門檻的效果。
對于如何抵抗安卓重打包攻擊,目前主要有三種防御方法:一是開發(fā)者對應(yīng)用進(jìn)行加固,在應(yīng)用中實(shí)施自我保護(hù)策略;二是在應(yīng)用市場方面進(jìn)行的靜態(tài)重打包應(yīng)用檢測;三是在應(yīng)用安裝或執(zhí)行時由可靠的應(yīng)用安全服務(wù)提供商進(jìn)行動態(tài)重打包應(yīng)用檢測。
應(yīng)用重打包對抗的一種主流方式是開發(fā)者進(jìn)行應(yīng)用加固,既在應(yīng)用中實(shí)施應(yīng)用自我保護(hù)策略,常見的策略有防篡改檢查、代碼混淆、應(yīng)用反調(diào)試和信息隱藏等。防篡改檢查是指在應(yīng)用中添加代碼檢測應(yīng)用自身是否被篡改。為了加強(qiáng)防篡改檢查代碼的安全性,Luo 等人[3]在應(yīng)用中分散插入大量檢測代碼來使得攻擊者難以定位所有檢測代碼,Zeng等人[4]在方案BombDroid 中創(chuàng)造性地利用經(jīng)常在惡意軟件中使用的邏輯炸彈來檢測攻擊者對應(yīng)用的修改。代碼混淆技術(shù)通過對應(yīng)用的控制流[5]、程序中涉及到的標(biāo)識符和字符串進(jìn)行混淆[6-7],通過提高攻擊者分析混淆代碼難度來對應(yīng)用進(jìn)行保護(hù)。應(yīng)用反調(diào)試則通過在應(yīng)用中添加調(diào)試檢測代碼來進(jìn)行判斷應(yīng)用執(zhí)行狀態(tài),阻礙攻擊者通過調(diào)試進(jìn)行動態(tài)分析。提高攻擊者重打包應(yīng)用的難度。信息隱藏技術(shù)是指通過加密等方式隱藏部分關(guān)鍵代碼,提高攻擊者對代碼進(jìn)行分析的難度。本質(zhì)而言,本文提出的方法屬于由開發(fā)者實(shí)施的重打包攻擊對抗技術(shù)。相比于已有的防篡改檢查、代碼混淆、應(yīng)用反調(diào)試等策略,本文提出的方法具有易于實(shí)施、運(yùn)行時開銷小等優(yōu)勢。同時,該方法與其它加固方法互補(bǔ),能夠與其他加固方法共同使用,進(jìn)一步提高應(yīng)用抗重打包的能力。
重打包應(yīng)用檢測技術(shù)以重打包應(yīng)用與原應(yīng)用之間的相似性為基礎(chǔ),通過特征選取,相似性比較來判斷待檢測應(yīng)用是否為重打包應(yīng)用。根據(jù)選取特征的方式,重打包應(yīng)用檢測技術(shù)可以進(jìn)一步分為兩種類型:靜態(tài)重打包應(yīng)用檢測和動態(tài)重打包應(yīng)用檢測。靜態(tài)重打包應(yīng)用檢測對APK 進(jìn)行靜態(tài)分析,選取不同的應(yīng)用特征如應(yīng)用代碼、API 調(diào)用序列、代碼中包含的控制流信息、應(yīng)用功能、資源文件等作為相似性度量的基礎(chǔ)。Zhou 等人[8]在安卓發(fā)展的早期就實(shí)現(xiàn)了一款名為DroidMoss 的相似性度量系統(tǒng)。該系統(tǒng)從dex 文件中抽取指令序列作為待測應(yīng)用的初步特征,接著計(jì)算指令序列的模糊哈希(Fuzzy Hashing)值作為該應(yīng)用的指紋信息,最后通過兩兩計(jì)算應(yīng)用指紋之間的編輯距離來確定第三方市場中是否存在重打包應(yīng)用。文獻(xiàn)[9-10]發(fā)現(xiàn)大量第三方庫的使用會導(dǎo)致基于dex文件的相似性檢測系統(tǒng)產(chǎn)生誤報,提出了兩階段的檢測方案:在進(jìn)行特征提取前首先對應(yīng)用使用的庫進(jìn)行檢測,移除第三方庫代碼后再進(jìn)行特征提取操作。Chen 等[11]的團(tuán)隊(duì)與 Marastoni 等[12]團(tuán)隊(duì)對代碼做進(jìn)一步處理,將代碼之間的控制流信息作為相似性比較的基礎(chǔ)。Marastoni 等人為了獲得更好的檢測效果,還額外提取了API 的調(diào)用情況作為第二特征來刻畫應(yīng)用。Abdurrahman 等人[13]與Fan等人[14]利用機(jī)器學(xué)習(xí)技術(shù),從程序的API 調(diào)用情況出發(fā)訓(xùn)練分類器進(jìn)行重打包應(yīng)用的檢測。文獻(xiàn)[15-17]基于重打包應(yīng)用與原應(yīng)用UI 的高度相似性,提出不同的檢測方法,對重打包應(yīng)用進(jìn)行檢測。
應(yīng)用安全服務(wù)提供商常用動態(tài)重打包檢測來進(jìn)行重打包應(yīng)用檢測。他們可以在應(yīng)用執(zhí)行時收集應(yīng)用特征來進(jìn)行重打包應(yīng)用檢測。文獻(xiàn)[18-20]收集應(yīng)用運(yùn)行時產(chǎn)生的UI 信息來進(jìn)行相似性檢測,文獻(xiàn)[24]提出了一種收集程序運(yùn)行時API 調(diào)用信息作為檢測依據(jù)的方法,文獻(xiàn)[25]提出了一種向應(yīng)用中添加水印信息并在運(yùn)行過程中進(jìn)行檢查的重打包應(yīng)用檢測方式。
本文提出了一種面向重打包對抗的重打包工具可利用缺陷檢測方法,能夠發(fā)現(xiàn)可用于加固應(yīng)用的重打包工具文件解析缺陷。首先,我們使用靜態(tài)代碼分析的方式對重打包應(yīng)用進(jìn)行代碼掃描,定位可能的異常點(diǎn);其次,使用模糊測試技術(shù)觸發(fā)異常,獲得異常對應(yīng)的關(guān)鍵輸入;然后,監(jiān)測觸發(fā)異常的變異應(yīng)用在目標(biāo)安卓設(shè)備上的運(yùn)行情況,對異常的可用性進(jìn)行確認(rèn),并進(jìn)行進(jìn)一步的模糊測試來輔助研究者構(gòu)建能被用于對抗重打包攻擊的異常觸發(fā)向量。在以重打包工具Apktool 2.4.1 為實(shí)驗(yàn)對象的測試中,我們總共發(fā)現(xiàn)了12 個未知的可利用的缺陷。所有這些缺陷都已被證明可用于實(shí)際應(yīng)用中,能夠有效對抗重打包攻擊,證明了本工作的可用性。
盡管已經(jīng)可以利用本方法檢測出Apktool 中未知的可利用缺陷,但本工作仍存在一定不足和需要改進(jìn)的地方。
一是在其他重打包工具上進(jìn)行推廣驗(yàn)證。當(dāng)前我們針對Apktool 進(jìn)行實(shí)驗(yàn)驗(yàn)證,未來我們將在后續(xù)工作中將本方法推廣應(yīng)用到其他重打包工具上。
二是增加對其他重打包階段的考慮。應(yīng)用的重打包過程通常需要經(jīng)歷反編譯與回編譯兩個階段。在本文的工作中,我們主要考慮Apktool 在反編譯方面可能引起的異常,缺少對回編譯階段的分析。為此,我們要在將來的后續(xù)工作中加入對回編譯階段異常的利用,實(shí)現(xiàn)對重打包工具的全流程覆蓋。