徐玄驥,張智斌
(昆明理工大學(xué),云南 昆明 650500)
Android 操作系統(tǒng)是使用人數(shù)最多的移動(dòng)操作系統(tǒng)。統(tǒng)計(jì)信息顯示,截至2020 年12 月,Google Play 共有超過(guò)350 萬(wàn)款應(yīng)用可供下載,每月平均下載人次超過(guò)500 萬(wàn)。然而,廣闊的使用場(chǎng)景也為惡意軟件發(fā)展提供了溫床。另有統(tǒng)計(jì)顯示,2020 年1—3 月間,共發(fā)現(xiàn)Android 惡意軟件超過(guò)48 萬(wàn)款,其中木馬為最主要的類型。種種數(shù)據(jù)都表明,惡意軟件檢測(cè)是一個(gè)重要的亟待解決的問(wèn)題。然而,隨著時(shí)間的推移,Android 惡意軟件也展現(xiàn)出了更強(qiáng)的偽裝性,傳統(tǒng)檢測(cè)手段是否奏效存疑。
本文針對(duì)上述提到的問(wèn)題,提出了一套基于多維度特征的Android 惡意軟件檢測(cè)方法。通過(guò)反編譯Android 應(yīng)用程序、抽取權(quán)限、使用應(yīng)用程序編程接口(Application Programming Interface,API)、網(wǎng)絡(luò)證書(shū)時(shí)效性、代碼混淆程度等不同特征并將其組成向量,之后使用隨機(jī)森林與支持向量機(jī)算法訓(xùn)練分類器,來(lái)實(shí)現(xiàn)對(duì)Android 惡意代碼的自動(dòng)化識(shí)別。
目前,關(guān)于Android 惡意代碼檢測(cè)的文獻(xiàn)較多,主要思路可歸結(jié)為基于權(quán)限與特征API、基于程序控制流與數(shù)據(jù)流以及基于動(dòng)態(tài)行為分析3 種。文獻(xiàn)[1]考慮了不同權(quán)限之間的組合與惡意代碼的關(guān)系,提出了一種基于隨機(jī)森林的靜態(tài)惡意代碼檢測(cè)方法。代碼控制流信息也常常被用來(lái)進(jìn)行惡意代碼檢測(cè)。文獻(xiàn)[2]提出了一種Dalvik 字節(jié)碼插樁方案,通過(guò)對(duì)控制流的監(jiān)控實(shí)現(xiàn)對(duì)應(yīng)用惡意行為的識(shí)別。相比于靜態(tài)分析,動(dòng)態(tài)分析對(duì)軟件的運(yùn)行狀態(tài)有更強(qiáng)的捕捉能力,因此也經(jīng)常被應(yīng)用于惡意代碼檢測(cè)。文獻(xiàn)[3]使用污點(diǎn)分析技術(shù)追蹤多個(gè)敏感數(shù)據(jù)源的數(shù)據(jù)流動(dòng),從而判斷應(yīng)用是否存在威脅用戶隱私的操作,但污點(diǎn)分析開(kāi)銷大,運(yùn)行效率較低。文獻(xiàn)[4]將靜態(tài)反編譯特征與動(dòng)態(tài)運(yùn)行特征相結(jié)合,使用卷積神經(jīng)網(wǎng)絡(luò)與長(zhǎng)短期記憶網(wǎng)絡(luò)混合的方法對(duì)惡意應(yīng)用進(jìn)行檢測(cè)。
由于Java 語(yǔ)言易于逆向的特征,代碼混淆技術(shù)被廣泛應(yīng)用于Android 程序開(kāi)發(fā)的過(guò)程中。代碼混淆通過(guò)去除代碼中的語(yǔ)義信息,用等效的代碼替換原有代碼結(jié)構(gòu)等方式,使得混淆后的代碼難以理解,從而增加逆向的成本。文獻(xiàn)[5]通過(guò)對(duì)Google官方市場(chǎng),中國(guó)第三方應(yīng)用市場(chǎng)以及惡意軟件等3個(gè)數(shù)據(jù)源的10 余萬(wàn)應(yīng)用程序包(Android application package,APK)進(jìn)行大規(guī)模掃描,統(tǒng)計(jì)了常見(jiàn)的3 種代碼混淆技術(shù)的使用情況。統(tǒng)計(jì)結(jié)果顯示,Android 惡意軟件對(duì)于代碼混淆技術(shù)的使用與普通應(yīng)用程序有較大差別。
1.1.1 標(biāo)識(shí)符重命名
在軟件開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)者通常賦予變量名較多的語(yǔ)義信息,以保證程序的較高可讀性。然而,充足的語(yǔ)義也為逆向者提供了方便,在變量名的幫助下,逆向者可以輕易理解原作者的意圖,竊取其中重要的實(shí)現(xiàn),從而對(duì)開(kāi)發(fā)者的知識(shí)產(chǎn)權(quán)產(chǎn)生威脅。
標(biāo)識(shí)符重命名通過(guò)將變量中的語(yǔ)義信息抹除,可以有效增加逆向者的攻擊成本,從而被廣泛使用。根據(jù)文獻(xiàn)[5]所述,有超過(guò)70%的中國(guó)開(kāi)發(fā)者和超過(guò)60%的惡意軟件開(kāi)發(fā)者會(huì)使用標(biāo)識(shí)符重命名的方式進(jìn)行混淆。但是二者的混淆實(shí)現(xiàn)存在較大差異。普通開(kāi)發(fā)者通常使用Android Studio(Google 官方推薦的Android 開(kāi)發(fā)集成環(huán)境)中內(nèi)置的proguard 工具進(jìn)行標(biāo)識(shí)符重命名,然而其策略較為簡(jiǎn)單,通常只按照字典順序?qū)?biāo)識(shí)符重命名為“a”“b”“aa”“ab”……,惡意軟件開(kāi)發(fā)者則會(huì)使用更具有迷惑性的策略,如形狀相近的字母組合,如“Ill1I1ll”或“00OoOO0”等,甚至出現(xiàn)英語(yǔ)以外的字符(Unicode)。除此之外,惡意軟件還經(jīng)常將重載特性與標(biāo)識(shí)符重命名結(jié)合起來(lái),比如將某些敏感函數(shù)重命名為Android 軟件開(kāi)發(fā)工具包(Software Development Kit,SDK)中定義的一些關(guān)鍵API,由于參數(shù)不同,不會(huì)影響程序的正常運(yùn)行,但往往會(huì)誤導(dǎo)逆向工程師。
1.1.2 字符串加密
由于應(yīng)用中的字符串包含了非常多的語(yǔ)義信息,逆向者通常會(huì)將其作為理解程序語(yǔ)義的突破口。下面的程序片段表明,即便混淆了程序中出現(xiàn)的標(biāo)識(shí)符名稱,有經(jīng)驗(yàn)的逆向者仍然可以依靠字符串來(lái)猜測(cè)函數(shù)的功能。
為了防止程序中的明文對(duì)信息的泄漏,字符串加密被作為一種有效的混淆手段。在Android 應(yīng)用開(kāi)發(fā)的過(guò)程中,字符串加密可應(yīng)用在多個(gè)階段,包括Java 代碼編譯階段、Java 字節(jié)碼轉(zhuǎn)Dex 文件階段等。
對(duì)于惡意代碼開(kāi)發(fā)者來(lái)說(shuō),字符串加密能夠有效地抹除程序語(yǔ)義信息,抵御部分基于硬編碼特征的掃描工具的檢測(cè),假如加密算法實(shí)現(xiàn)得足夠復(fù)雜,還能夠有效地增加逆向過(guò)程的時(shí)間成本。根據(jù)文獻(xiàn)[5]所述,普通軟件開(kāi)發(fā)者極少使用字符串加密。
1.1.3 Java 反射
反射是Java 語(yǔ)言的一種高級(jí)用法,提供了一種靈活的交互方式,使得開(kāi)發(fā)者能夠在程序運(yùn)行時(shí)了解類、方法和變量的信息,甚至動(dòng)態(tài)地創(chuàng)建類的實(shí)例或調(diào)用方法。在Android 程序開(kāi)發(fā)領(lǐng)域,Java 通常被用來(lái)調(diào)用Android SDK 中的非公開(kāi)方法(標(biāo)注有hidden 注解的API)。以下代碼展示了如何通過(guò)反射,調(diào)用“android.telephony.TelephonyManager”類的“getNetworkTypeName”方法。
反射在普通程序與惡意程序中都會(huì)被使用,但是二者對(duì)反射的使用模式差異較大。普通軟件通常會(huì)利用反射進(jìn)行JNI 調(diào)用或后向兼容性的檢測(cè),然而惡意軟件則會(huì)利用反射去隱藏控制流,從而抵抗靜態(tài)分析工具的檢測(cè),或使用反射將原本正常的函數(shù)調(diào)用變得十分臃腫,加強(qiáng)對(duì)逆向者的干擾。
1.2.1 權(quán)限特征選擇及獲取
Android 權(quán)限機(jī)制提供了對(duì)應(yīng)用的訪問(wèn)控制。目前,Android 系統(tǒng)提供了超過(guò)170 種權(quán)限,覆蓋應(yīng)用行為的方方面面。然而,其中一部分權(quán)限可能會(huì)對(duì)用戶的隱私或設(shè)備的運(yùn)行狀態(tài)產(chǎn)生影響,這部分權(quán)限被Android 標(biāo)記為“危險(xiǎn)”,需要開(kāi)發(fā)者與用戶謹(jǐn)慎對(duì)待。由于惡意應(yīng)用往往覬覦用戶的隱私或企圖掌握對(duì)設(shè)備的全面控制,危險(xiǎn)權(quán)限的出現(xiàn)頻率通常高于普通應(yīng)用。除此之外,還發(fā)現(xiàn),部分惡意軟件傾向于定義較多的自定義權(quán)限?;谝陨蟽煞N觀察,從Android 應(yīng)用的清單文件中抽取權(quán)限列表,并統(tǒng)計(jì)其中危險(xiǎn)權(quán)限以及自定義權(quán)限的出現(xiàn)次數(shù),作為應(yīng)用權(quán)限方面的特征。所選擇的部分高危權(quán)限如表1 所示。
1.2.2 證書(shū)特征選擇及獲取
在Android 應(yīng)用開(kāi)發(fā)的過(guò)程中,需要對(duì)應(yīng)用進(jìn)行簽名,簽名后將會(huì)產(chǎn)生一個(gè)證書(shū)文件,通常以.RSA作為后綴。當(dāng)應(yīng)用被上傳到應(yīng)用市場(chǎng)上進(jìn)行審核時(shí),證書(shū)將會(huì)被用來(lái)證明程序的正當(dāng)性。然而,某些惡意軟件不能在正規(guī)市場(chǎng)中流通,他們所使用的證書(shū)也存在各種問(wèn)題。在本文中,抽取了應(yīng)用中的證書(shū)文件,并以其是否過(guò)期作為特征。
表1 所選擇的部分高危權(quán)限
1.2.3 敏感API 調(diào)用特征選擇及獲取
Android SDK 提供了豐富的API 供開(kāi)發(fā)者實(shí)現(xiàn)對(duì)應(yīng)功能。與權(quán)限類似,部分API 的濫用也可能造成用戶隱私被竊取或設(shè)備系統(tǒng)異常,這部分API 被稱為敏感API,開(kāi)發(fā)者在使用時(shí)需要特別注意。通常來(lái)講,惡意軟件對(duì)敏感API 的使用更加頻繁,基于此觀察,選擇敏感API 的調(diào)用次數(shù)作為特征之一。除此之外,相比于普通軟件,惡意軟件對(duì)敏感API的調(diào)用方式通常較為單一,調(diào)用過(guò)程也更容易被觸發(fā),因此,選擇敏感API 調(diào)用路徑的平均長(zhǎng)度作為特征之二。敏感API 調(diào)用路徑平均長(zhǎng)度的計(jì)算方法如下偽代碼所示:
選擇的部分敏感API 如表2 所示。
表2 選擇的部分敏感API
1.2.4 程序混淆信息選擇及獲取
如第1.1 小節(jié)所示,代碼混淆技術(shù)在正常應(yīng)用與惡意應(yīng)用的使用有較大差異?;诖?,選擇如下特征表示程序的混淆信息:
(1)應(yīng)用程序中標(biāo)識(shí)符名稱的平均長(zhǎng)度。由于Android 惡意軟件傾向于對(duì)標(biāo)識(shí)符進(jìn)行復(fù)雜地重命名,其標(biāo)識(shí)符名稱的分布將不同于普通應(yīng)用。除了標(biāo)識(shí)符的平均長(zhǎng)度以外,還可以使用信息熵來(lái)表征標(biāo)識(shí)符名稱上的差異。
(2)應(yīng)用程序中字符串的信息熵。信息熵用于量化表示信息的不確定性,當(dāng)某條信息被加密后,其信息熵將會(huì)增大。信息熵的通用計(jì)算公式如下:
式中,N表示事件的個(gè)數(shù),Pi表示事件i的發(fā)生概率。在本系統(tǒng)的實(shí)現(xiàn)中,抽取一個(gè)Android 應(yīng)用中出現(xiàn)的所有字符串并將其合并。假設(shè)合并后的字符串為S中出現(xiàn)的字符種類共為N,Pi表示第i個(gè)字符Xi出現(xiàn)的概率,則,其中S.count(Xi)表示Xi在S中出現(xiàn)的次數(shù),S.length表示字符串的長(zhǎng)度。最終的信息熵可以根據(jù)公式(1)計(jì)算出來(lái)。
(3)應(yīng)用程序中Java 反射API 調(diào)用次數(shù)。根據(jù)文獻(xiàn)[5],雖然Java 反射在Android 普通軟件與惡意軟件中均被廣泛使用,但惡意軟件對(duì)其的使用頻率遠(yuǎn)遠(yuǎn)高于普通軟件。遍歷應(yīng)用中的每個(gè)函數(shù),恢復(fù)其smali 格式的代碼,并與Java 反射API 作對(duì)比,統(tǒng)計(jì)其被調(diào)用的次數(shù)。選擇的smali 格式的Java 反射API 如表3 所示。
表3 選擇的Java 反射API 列表
1.2.5 分類算法
在從App 中提取特征之后,需要使用機(jī)器學(xué)習(xí)算法對(duì)特征進(jìn)行學(xué)習(xí),從而實(shí)現(xiàn)對(duì)Android 惡意代碼的自動(dòng)化鑒別。機(jī)器學(xué)習(xí)模型種類繁多,各具特點(diǎn)。經(jīng)過(guò)調(diào)研,決定采用有監(jiān)督二分類模型來(lái)進(jìn)行實(shí)驗(yàn),根據(jù)以往文獻(xiàn)的經(jīng)驗(yàn),發(fā)現(xiàn)支持向量機(jī)與隨機(jī)森林模型具有訓(xùn)練速度快、準(zhǔn)確性高的優(yōu)點(diǎn),故針對(duì)兩者進(jìn)行了實(shí)驗(yàn)驗(yàn)證。
本文采用androguard 作為Android 程序分析框架。Androguard 提供了豐富的功能與Python 開(kāi)發(fā)接口,能夠從Android 程序中自動(dòng)提取出類、方法、成員等信息,并生成對(duì)象間的函數(shù)調(diào)用圖。使用Androguard 抽取出每個(gè)Android 程序的七個(gè)特征組成向量,并使用scikit learn 庫(kù)來(lái)對(duì)支持向量機(jī)模型與隨機(jī)森林模型進(jìn)行訓(xùn)練和預(yù)測(cè)。
為了使實(shí)驗(yàn)結(jié)果更具有說(shuō)服力,采用文獻(xiàn)中提到的數(shù)據(jù)源。這些正常的Android 程序均是從國(guó)內(nèi)第三方市場(chǎng)以及Google Play 上下載,惡意程序主要獲取于VirusShare 網(wǎng)站以及文獻(xiàn)[6]從該數(shù)據(jù)源中隨機(jī)抽取了2 000 個(gè)正常的Android 程序與2 000 個(gè)惡意的Android 組成了本實(shí)驗(yàn)的數(shù)據(jù)集。
為了驗(yàn)證本文所選擇的特征的有效性,將特征分成了4 類。
(1)權(quán)限類特征:Android 程序中申請(qǐng)的高危權(quán)限數(shù)量以及自定義權(quán)限數(shù)量。
(2)證書(shū)類特征:證書(shū)是否已經(jīng)過(guò)期。
(3)API 特征:敏感API 被調(diào)用的平均次數(shù)以及調(diào)用路徑的長(zhǎng)度。
(4)混淆特征:Android 程序中標(biāo)識(shí)符平均長(zhǎng)度、字符串的信息熵以及Java 反射的使用次數(shù)。
將數(shù)據(jù)集按照8:2 的比例拆分為訓(xùn)練集和測(cè)試集,并進(jìn)行5 次的交叉檢驗(yàn)。對(duì)于機(jī)器學(xué)習(xí)模型,均采用了scikit learn 庫(kù)中提供的默認(rèn)參數(shù),具體的參數(shù)信息如表4 所示。
實(shí)驗(yàn)結(jié)果表明,當(dāng)使用全部特征時(shí),隨機(jī)森林模型可以達(dá)到95.3%的準(zhǔn)確率,94.4%的精確率以及98.0%的召回率,相比之下,支持向量機(jī)擁有62.6%的準(zhǔn)確率,62.0%的精確率與100%的召回率??梢钥闯?,雖然支持向量機(jī)能夠?qū)y(cè)試集中的全部惡意應(yīng)用找出,但是同樣存在非常多的誤報(bào),使得最終分類效果不理想。因此實(shí)際選擇了隨機(jī)森林作為本文的分類模型。確定分類模型之后,與只使用高危權(quán)限作為特征的傳統(tǒng)方案進(jìn)行對(duì)比實(shí)驗(yàn)。兩種方案均采用隨機(jī)森林作為分類模型,實(shí)驗(yàn)結(jié)果如表5 所示。
表4 分類模型默認(rèn)參數(shù)
表5 在選用樣本上的實(shí)驗(yàn)結(jié)果
可以看出,相對(duì)于傳統(tǒng)方案,本方案的準(zhǔn)確率、精確率以及召回率的提升分別為19.4%、16.5%以及13.3%,從而證明了特征與分類模型選擇的有效性。為了更好地理解各個(gè)特征對(duì)分類結(jié)果的貢獻(xiàn)度,輸出了scikit learn 庫(kù)中隨機(jī)森林的特征重要性,結(jié)果顯示,各個(gè)特征的權(quán)重如表6 所示。
表6 實(shí)驗(yàn)中各個(gè)特征的特征重要性
可以看出,權(quán)限特征、API 特征以及混淆特征擁有較高的貢獻(xiàn)度,混淆特征的貢獻(xiàn)度甚至超過(guò)50%,證明了混淆方式的異同確實(shí)能夠有效地鑒別一個(gè)應(yīng)用程序的惡意性。但是標(biāo)志符的平均長(zhǎng)度未能表現(xiàn)出任何區(qū)分性,原因可能是測(cè)試集中使用復(fù)雜重命名方式的惡意應(yīng)用數(shù)量過(guò)少,同時(shí)普通應(yīng)用開(kāi)發(fā)者更加注重混淆保護(hù),使得二者的重命名模式難以區(qū)分。
在本文中,提出了一種基于多種特征的Android惡意軟件檢測(cè)算法。與其他文章相比,在特征中融入了軟件的代碼混淆信息,實(shí)驗(yàn)結(jié)果表明:與傳統(tǒng)只使用權(quán)限與API 特征的方法相比,代碼混淆信息能夠有效地提升檢測(cè)算法的性能,其中準(zhǔn)確率提升19.4%,精確率提升16.5%,召回率提升13.4%。在本文所使用的3 種代碼混淆特征中,標(biāo)識(shí)符的長(zhǎng)度未能有效區(qū)分正常應(yīng)用與惡意應(yīng)用,這與越來(lái)越多的應(yīng)用開(kāi)始使用自動(dòng)化工具(如proguard)進(jìn)行標(biāo)識(shí)符重命名有關(guān)。相比支持向量機(jī)算法,隨機(jī)森林算法在Android 惡意軟件的檢測(cè)中表現(xiàn)出了更好的性能,精確率與召回率非常接近。
下一步的實(shí)驗(yàn)中,將會(huì)著重剖析Android 惡意軟件在代碼混淆上的使用,通過(guò)提取更多特征,來(lái)多維度地建立Android 惡意軟件的畫(huà)像,包括控制流混淆情況、虛假重載等。