本片文章主要翻譯國外的一篇文章晚吞,原文在這里
摘要
Android插件化技術
是一種新型的應用程序級的
的虛擬化框架坷澡,它允許移動應用程序在不安裝應用程序的情況下動態(tài)加載并啟動其應用程序仅政。該技術的初衷是為了解決熱修復問題和減少APK的安裝包大小而誕生的。使用該技術的應用主要是為了滿足在同一個設備啟上動同一個應用程序的多個實例的需求只酥,比如同時登錄兩個Twitter賬戶,其中一個是個人賬戶苞也,另外一個是企業(yè)級的富纸。 Parallel Space是Googl play中使用插件化最為廣泛的APP但汞,它在Google Play的安裝量已經達到了5000萬次。
然而凛辣,據我們所知,永遠都不要低估黑客對移動趨勢的興趣。在境外就有一款Android的流氓軟件——“Dual-instance”框弛,它可以動態(tài)的加載并啟動官方的Twitter應用的APK文件,并可以劫持用戶輸入的密碼等敏感信息捕捂,并用于釣魚攻擊瑟枫。除此之外,在我們全面分析Android插件化技術的安全風險后指攒,我們發(fā)現(xiàn)插件化存儲的數(shù)據可以被惡意的宿主應用或其他插件所竊取慷妙。在Wildfire產品中,我們發(fā)現(xiàn)了119,898個樣本在使用插件化技術允悦。其中114,630個樣子是惡意的或者灰色的膝擂。所以說,Android插件化技術正在成為普通Android應用 新的安全威脅隙弛。
我們在這里將揭示Android插件化的神秘面紗架馋,并且在這里講解底層攻擊和安全問題。我們也提供了一個輕量級的防御方案驶鹉,一個已經發(fā)布了绩蜻,名字叫做"Plugin-Killer"的庫,它可以防止Android應用被使用Android插件化技術的宿主應用所啟動室埋。一旦在你的項目中依賴該庫办绝,該庫就可以檢測到虛擬環(huán)境中的潛在威脅,并在被其他使用插件化的軟件啟動的時候姚淆,終止該啟動
1介紹
Android插件化技術是應用程序級別的一項創(chuàng)新型技術孕蝉,它的初衷主要是用于熱更新,減少APK安裝包的大小腌逢,以及解決65535方法數(shù)量的限制降淮。從技術層面來說,Android插件化技術與傳統(tǒng)意義上的動態(tài)加載還不一樣搏讶,因為它在不需要聲明任何特定的接口或組件的情況下佳鳖,它就在可以加載或者啟動整個應用程序(比如apk文件)。Android插件化技術的主要應用場景是媒惕,在同一個設備上啟動多個應用的實例系吩,也就是我們常說的"雙開"。根據我們的觀察妒蔚,誕生Android插件化的的兩個主要動機是:1是在社交APP中的多賬戶需求穿挨,2是在應用商店中即時啟動應用程序月弛。上面這兩種應用場景均來自用戶的需求。比如科盛,一個用戶既擁有Twitter的個人賬戶帽衙,也有一個擁有Twitter的企業(yè)賬戶,而又不想來回注銷切換賬戶并重復登錄贞绵,并且不想使用兩個手機厉萝。Google Play中有一個很受歡迎的APP——"Parallel Space",就是采用的這項技術,它的安裝量已經有5000萬
次但壮。
然后冀泻,正如我們所知,流氓軟件的作者一直都在關注新技術蜡饵,因此弹渔,黑客最近已經自行創(chuàng)建基于Android插件化技術的流氓軟件。AVAST軟件
報道了一個新發(fā)現(xiàn)的Android惡意軟件——“Dual-instance ”就是基于Android插件化技術溯祸。在這個惡意軟件中肢专,開發(fā)者開發(fā)了一個假的Twitter應用程序(宿主應用程序),該應用程序可以動態(tài)加載Twitter的APK文件焦辅,而無需在設備中安裝Twiiter應用程序博杖。由于用戶真實的與Twiiter進行交互;所以筷登,從本質上來說剃根,這是一種很好的網絡釣魚攻擊。插件化技術允許惡意的宿主應用完全控制并hook插件應用前方,所以宿主應用就在Twitter的登錄界面狈醉,劫持對應的"EditText"來實現(xiàn)竊取信息的目的。Android插件化技術一把雙刃劍惠险。盡管它為用戶和開發(fā)人員帶來了更多的便利性苗傅,開發(fā)和維護成本更低,但它也有許多安全問題的隱患班巩,與使用該技術的數(shù)百萬可疑惡意應用相比渣慕,它僅僅是滄海一粟。我們預測抱慌,黑客將會利用插件化技術來用為新的攻擊媒介逊桦。由于攻擊者不會損害APK文件的完整性,所以這個新的攻擊媒介可以完全繞過現(xiàn)有的流氓查殺檢測系統(tǒng)抑进。
最嚴重的安全問題是卫袒,由于插件化技術的出現(xiàn),Android系統(tǒng)中的信任環(huán)境發(fā)生變化单匣。之前信任的基礎是建立在Android系統(tǒng)沒有漏洞這個假設上的。現(xiàn)在這個假設依然存在,但是由于Android應用完全可以在插件環(huán)境中運行户秤,而不是在真正的Android系統(tǒng)码秉,因此無法得到對環(huán)境的信任。一旦應用在插件環(huán)境中加載并啟動鸡号,它就完全由被宿主應用控制了转砖。在插件環(huán)境下運行官方的應用存在潛在風險,主要包括:1)宿主應用可以將官方應用作為插件而運行起來鲸伴,這樣存儲在文件系統(tǒng)中的所有數(shù)據可能會有被盜取的風險府蔗;2)宿主應用可以盜取用戶輸入的信息,比如登錄憑證汞窗。因此姓赤,官方應用正面臨來自Android插件化技術的新的安全威脅。
在本文中仲吏,我們將深入研究Android插件化技術不铆,并闡述底層攻擊媒介涉及的安全問題。我們提供給了一種輕量級的防御方案裹唆,并發(fā)布了一個名為"Plugin-Killer"的庫誓斥,它可以阻止Android應用使用Android插件化技術啟動Android應用。一旦正常的Android應用集成這個庫许帐,它會自動檢測是否運行在插件化環(huán)境劳坑,并在啟動時,自動終止成畦。
2 揭開插件化技術的神秘面紗
實現(xiàn)插件化有多種途徑距芬,比如DroidPlugin
,VirtualApp
和DynamicAPK
,他們在架構設計上有很多相似的地方羡鸥。本地蔑穴,我們將以DroidPlugin
作為例子來講解。
下圖描述了DroidPlugin內部是如何工作的惧浴。
它包含3個主要部分:Android系統(tǒng)框架存和、依賴DroidPlugin
SDK的宿主應用程序、作為單獨的APK的插件衷旅。DroidPlugin
庫中的基礎組件被稱之為Proxy Hook
捐腿。它位于插件與Android系統(tǒng)框架之間,負責攔截插件應用對Android系統(tǒng)API的調用柿顶。同時在發(fā)送到Android系統(tǒng)框架之前茄袖,攔截的調用將會被DroidPlugin
進行修改,比如修改傳遞的參數(shù)嘁锯,這就是DroidPlugin
無需安裝即可啟動APK文件的魅力之所在宪祥。
2.1 虛擬環(huán)境
插件化技術啟動應用的多個實例的原理機制是在Android系統(tǒng)框架的上面建立一個虛擬環(huán)境聂薪,這個虛擬環(huán)境對Android系統(tǒng)框架是透明的。所以插件可以繞過系統(tǒng)的限制蝗羊。DroidPlugin
的神奇之處在于利用了Proxy Hook
來攔截來自插件應用的Android API調用藏澳,并修改他們的參數(shù)
通常Hooking系統(tǒng)是一個標準的中間人的角色。當我們談論如何設計Hooking系統(tǒng)時耀找,我們通常會需要解答兩個問題:"如何Hook API"和"要Hook 哪個API"翔悠。第一個問題很簡單,因為在Java Hook一個API是有標準答案的野芒。Java提供了一個"動態(tài)代理"的設計模式蓄愁,這種設計模式用來創(chuàng)建動態(tài)代理的實例。一些API是在Android框架內部定義的狞悲,所以我們需要用反射來Hook它們撮抓。第二個問題就比較復雜了。涉及到了Android系統(tǒng)框架的工作原理效诅≌凸觯基本上,DroidPlugin
Hook了API以及以下任務:
- 無需安裝即可加載并啟動插件APK
- 管理APP組件的生命周期
- 插件之間通信
- 管理插件乱投,主要是下載與更新
這種技術聽起來有點和DCL類似咽笼,動態(tài)代理加載技術允許APP在運行時記載和執(zhí)行不屬于其靜態(tài)代碼庫中的代碼。在安裝包中并沒有這些代碼戚炫,而是在APP在運行時被加載的額外代碼剑刑。DCL只能允許加載一小部分緊密依賴基本應用程序的代碼。但是插件化技術更先進双肤,因為它可以啟動一個完整的APK文件施掏,其中包含執(zhí)行更復雜功能和更多與系統(tǒng)交互的代碼。
通過Hook ClassLoader無需安裝來啟動插件茅糜,在Android系統(tǒng)中七芭,APK或者Dex文件由ClassLoader加載。加載的文件和類存儲在名為DexElement的ClassLoader對象中定義的列表蔑赘。當需要加載一個類的時候狸驳,ClassLoader會掃描這個列表來找到匹配給定的類名。如果未能在當前的ClassLoader中找到對應的類缩赛,它會追溯到父ClassLoader耙箍。Android中有幾種類型ClassLoader:BootClassLoader
用于加載系統(tǒng)類;PathClassLoader
用于加載應用程序類酥馍。但是所有這些都是從其基類BaseDexClassLoader派生出來的辩昆。
起初,系統(tǒng)會找到安裝包的的路徑旨袒,通常是data/app文件夾下汁针,用來查找已安裝應用的APK文件和相關資源术辐。在啟動步驟中,只有主機應用的APK文件解析并保存在DexElement列報表中扇丛。由于插件APK文件不在這個特殊的路徑下术吗,系統(tǒng)無法自動加載該文件。Android系統(tǒng)依賴ActivityThread這個對象來加載并啟動一個新的Activity帆精,代碼如下:
java.lang.ClassLoader cl =
r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl,
component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
所以,如果系統(tǒng)嘗試使用當前ClassLoader加載在插件文件中定義的類隧魄,則無法找到任何內容卓练,并且插件無法啟動。而DroidPluging
會Hook這個ClassLoader购啄,并將其解析的插件APK插入到它的DexElement
列表中襟企。可以通過插件文件的路徑作為參數(shù)調用loadDex函數(shù)(圖3)狮含。如果這個Hook步驟完成顽悼,插件中定義的類可以被搜索和啟動。這個技巧有點類似Android中使用熱修復的套路几迄。
共享UID蔚龙,Android的包管理在安裝應用程序時會創(chuàng)建一個唯一的用戶ID(UID)和組(GID),并且這些保留直到應用程序被卸載映胁。對于插件應用來說木羹,雖然它被動態(tài)加載并由Hook類加載器啟動,但是從系統(tǒng)角度來看解孙,它不被視為新應用程序坑填。因此,所有插件應用程序與宿主應用程序共享相同的UID弛姜。不同的PID脐瑰。由于所有的應用程序都是用相同的UID,所以Android系統(tǒng)自帶的權限模型和數(shù)據隔離模型無法確保插件應用程序的安全性廷臼。
插樁組件 啟動沒有安裝的插件APK僅僅是第一步苍在,Droid
插件還需要維護插件應用中組件的生命周期。應用程序組件Activity
中剩,Service
忌穿,Broadcast Receiver
,Content Provider
是構成一個移動應用的基本模塊结啼。與UI組件不同的是掠剑,應用程序組件的生命周期是有系統(tǒng)來管理的。這意味著使用這些組件郊愧,就必須和Android系統(tǒng)框架進行交互朴译。正是由于插件化特殊的啟動方式井佑,DroidPlugin
必須使用一些其他的技巧。
我將啟動插件應用中的一個新的activity來做為樣例來講解DroidPlugin
眠寿。Activities是用戶與應用程序交互的入口點躬翁,也是用戶在應用程序內或應用程序之間跳轉的的核心。它經常在應用程序中被使用盯拱。圖4說明了在Android平臺上啟動一個新的activity的整個流程盒发。Android應用程序無法自行創(chuàng)建新的活動,他們需要使用系統(tǒng)提供的一個名為ActivityManagerService(或者叫AMS)來實現(xiàn)狡逢。AMS負責管理每個Activity的生命周期宁舰,例如創(chuàng)建activity和銷毀關閉activity。
創(chuàng)建一個activity
是通過顯示或者隱士的調用系統(tǒng)的startActivity
這個API奢浑。然后AMS將執(zhí)行一些任務蛮艰,例如pause Activity
,創(chuàng)建一個新的Activity
,然后將它們維持在一個堆棧中雀彼。AMS完成這些任務后壤蚜,它會把控制權返還給新的Activity
,并通知ActivityThread
加載并執(zhí)行新的Activity的代碼徊哑。就像Activity
的里面的onCreate
函數(shù)回調一樣
對于我們這篇文章袜刷,我們只關心3個函數(shù)startActivity
,AMS
实柠,handleLauncherActivity
水泉。上面這3個函數(shù)是Activity
與AMS
進行交互通信的地方。就像上面圖5所示窒盐,函數(shù)startActivity
向AMS
發(fā)送一個Intent
草则,這個Intent
里面包含將要被用于創(chuàng)建Activity
的Class類。當前Activity
就是這樣通知AMS
的蟹漓。一旦AMS
為這個新建的Activity
創(chuàng)建了Context
炕横,AMS
就會將這個Intent
轉發(fā)到應用程序中的的ActivityThread
處理,并調用handleLaunchActivity
來處理意圖葡粒,該函數(shù)將從Intent中
提取新的Activity
的類份殿,然后進行加載和執(zhí)行相應的代碼。這就是系統(tǒng)開啟一個新的Activity
的流程嗽交。
然而卿嘲,我們如果按照這個套路來啟動插件中的Activity,則會在AMS中啟動失敗夫壁。這是因為插件的Activity沒有在宿主應用中的AndroidManifest
里面注冊Activity拾枣。用戶可能會啟動任何一個插件應用,這樣就會導致DroidPlugin
庫無法預測它們的名稱。因此梅肤,在安裝之前就不可能將每個插件中的Activity注冊到宿主應用中司蔬。DroidPlugin
的解決方案是預先在宿主應用里面的AndroidManifest
里面注冊幾個"樁",這些"樁"可以定義為stubActivity01
之類Actiivty。宿主應用作為一個代理姨蝴,已經預先注冊了AndroidManifest里面的所有組件(例如Service俊啼、Activity、Receiver和Content Provider)和權限左医。通常的做法是授帕,宿主應用預先為每一種組件注冊10個"樁"組件,同時也要注冊所有的權限炒辉。因此豪墅,主機宿主應用和插件應用都是用這些預定義的"樁"組件
Hook AMS 來解決沒有定義的應用程序組件 在運行時期間,DroidPlugin
將攔截從當前Activity發(fā)送給AMS的Intent黔寇,并且將其包裝成一個新的intent,這個新的intent包含了"樁"Activity(圖6所示)斩萌。通過修改intent,DroidPlugin可以欺騙AMS來創(chuàng)建"樁"Activity缝裤,這樣就不會報錯了。但是這并沒有結束颊郎,因為AMS也會將intent轉發(fā)給新的Activity憋飞,ActivityThread根據包裝后的新的Intent內容來加載"樁"Activity的類。所以說姆吭,DroidPlugin也需要替換Intent榛做,并將原始的Intent返回給ActivityThread。
為了將這個包裝的intent發(fā)送到AMS内狸,DroidPlugin
需要像我們剛剛提到的那樣hookstartActivity
這個函數(shù)检眯。這個函數(shù)的核心邏輯是獲取AMS的Binder代理,然后就可以通過這個代理發(fā)送這個intent了昆淡。像圖7代碼所示锰瘸,Activity由于與AMS通信非常麻煩,所以不可能每次都從系統(tǒng)來獲取AMS的代理Binder昂灵,因此系統(tǒng)中保留了一個名為gDefault
的本地對象作為緩存避凝。所有的框架都是通過這個對象來獲取AMS的Binder代理。一旦DroidPlugin
hook 了這個緩存對象眨补,它就可以提供這個hook過的binder代理實例給"startActivity"這個API進行調用管削,通過這個套了,它就可以在發(fā)送給AMS之前撑螺,攔截intent含思。使用同樣的套路也可以hook handleLaunchActivity
以打開轉發(fā)的intent
如果我們再研究其他組件(Service
,content Provider
,broadcast receiver
)的系統(tǒng)創(chuàng)建過程,我們就會發(fā)現(xiàn)他們的創(chuàng)建流程很類似实蓬。這是因為茸俭,系統(tǒng)需要使用相同的機制來和AMS進行交互吊履。唯一的不同點是由當前的Activity來調用API。圖8顯示了通過調用調用startService
函數(shù)開啟一個新的service的過程调鬓。DroidPlugin
采用相同的hook機制來攔截intent艇炎,并且將intent中的目標service替換為"樁"service
3、利用惡意軟件破壞插件技術
插件化技術讓Android應用程序用戶體驗更好腾窝,所以說它功能強大缀踪,并且非常實用。但是虹脯,我們想說的是這門新技術已經被惡意軟件濫用了驴娃。在下面的文章中,我們將展示一些統(tǒng)計數(shù)據和真實的惡意軟件樣本來證明它被濫用了循集。
我們統(tǒng)計了我們數(shù)據庫中的所有應用程序唇敞,我們發(fā)現(xiàn)大約有12萬個應用使用了DroidPlugin庫或者其定制版本。其中有有5268是良性的咒彤,但是其中有114630個是惡意的疆柔。(在我們的數(shù)據庫中,我們根據動態(tài)分析模塊會發(fā)現(xiàn)應用的可疑行為镶柱,并將其標記為惡意)旷档。
而且我們測量了自2015年7月開始,DroidPlugin 支持的惡軟件樣本趨勢歇拆。從下圖我們發(fā)現(xiàn)鞋屈,截止到2016年1月,惡意樣本的數(shù)量是非常少的故觅,但是在2016年1季度出現(xiàn)了大幅增長厂庇,隨后又在第二季度再次增長。在2016年的最后幾個月逻卖,新樣本的數(shù)量增加了大約1000到2000
為什么插件技術被濫用宋列? 根據我們分析過的樣本,我們認為有三個原因:
- 1评也、更新惡意軟件炼杖,是不需要root 手機的,一旦這些攻擊者誘導用戶去安裝他們的惡意軟件到手機上盗迟,他們就可以利用插件化技術安裝新的惡意軟件或者更新現(xiàn)有的惡意軟件坤邪,而且還不需要root手機。這樣惡意軟件就可以把核心的惡意代碼放到單獨的插件APK中罚缕,當需要更新的時候艇纺,只需從遠程服務器下載最新的APK文件進行替換即可。通過這樣操作,當用戶去檢測的時候黔衡,就大幅降低被檢測到的風險蚓聘,而且整個過程,不需要和用戶進行交互盟劫。
- 2夜牡、方便逃避靜態(tài)檢測。由于惡意軟件的核心代碼位于遠程服務器并且是動態(tài)獲取的侣签,這就導致了宿主應用不包含任何可疑的API代碼塘装,所以它很難被靜態(tài)檢測出來。如果不進行動態(tài)檢測影所,是很難從宿主應用中找到惡意行為的證據
- 3蹦肴、目前最普遍,泛濫的惡意程序是2次打包猴娩,但是隨著檢測技術的發(fā)展阴幌,這種方式的機會越來越少小了。由于插件化技術可以實現(xiàn)不用打包卷中,所以它可以作為發(fā)起網絡釣魚攻擊的另一種方式裂七。攻擊者可以將經過身份驗證的APK作為插件來加載,而且不用進行任何修改仓坞,然后再將惡意代碼放入另一個插件中,這樣既可以竊取到用戶輸入信息或者其他憑證信息腰吟。
惡意軟件案例研究:PluginPlathom 我們發(fā)現(xiàn)第一個利用DroidPlugin
庫作為攻擊目標的惡意軟件被我們命名為PluginPhathom
无埃。在2016年11月,在alo Alto Networks
研究中心毛雇,我們發(fā)布了一篇博客嫉称,該博客展示了我們對PluginPhathom
的樣本分析,并且在媒體灵疮,比如SC Media
织阅,SecurityWeek
和BleepingComputer
中被轉載了。PluginPhathom
的攻擊很簡單震捣,主要包括拍照荔棉、截圖、錄制音頻蒿赢,以及截取和發(fā)送短信润樱。它的獨特之處在于,PluginPhathom
每個惡意功能模塊化羡棵,并將其放入某個插件中壹若,然后利用宿主應用在運行時來動態(tài)加載這些惡意插件并進行攻擊
PluginPhathom
家族,自2016年7月被我們首次發(fā)現(xiàn)至今一直在不斷的更新。攻擊者通過重構將每個惡意功能模塊化店展,然后將其放入每個插件APK中养篓,最后他們再利用DroidPlugin
庫來集成。它一共包含9個插件赂蕴。比如柳弄,通訊錄插件,可以竊取用戶的聯(lián)系人信息睡腿;文件插件可以竊取本地的文件语御。它還有一個叫做update的插件,它用來去遠程服務器下載最新的插件APK文件席怪,然后進行更新這個模塊卢肃。
惡意軟件案例研究:雙開 插件化技術被濫用的另一個場景是敌完,啟動多個正版而且受害的APP的實例(圖11)徐裸。Avast Threat Intelligence Team
首次發(fā)現(xiàn)在使用Twitter的雙開惡意軟件。其中有這樣的一個樣本——DualTwitter刻撒,當用戶想同時在一個設備上登陸多個Twitter賬戶的時候骨田,用戶就可以下載這個APP,但是它的成本是高額的声怔。因為用戶一旦使用這個應用登陸Twitter态贤,該惡意軟件就記錄用戶鍵盤輸入并竊取用戶的憑證信息。DualTwitter
使用的是VirtualApp
庫(另外一種插件化技術)醋火,在不需要重新打包的情況下悠汽,可以直接加載多個twitter應用程序實例。同樣芥驳,我們也發(fā)現(xiàn)了類似的Instagram的惡意軟件柿冲。
4、解決方案
濫用插件化技術趨勢現(xiàn)在已經愈演愈烈了兆旬,為了防止普通應用程序被這類新型的技術攻擊假抄,我們提出了一個輕量級的解決方案。我們叫他Plugin-Killer丽猬。它是一個Android SDK宿饱,它可以幫助普通應用檢測其他APK文件是否在插件化技術提供的虛擬環(huán)境中運行。同時我們也開源了我們的SDK宝鼓,可以直接從Github進行下載
4.1刑棵、潛在的解決方案
由于我們是第一個發(fā)現(xiàn)插件化被濫用的,所以目前還沒有一個科學的解決方案來解決問題愚铡。我們將分享我們對潛在解決方案的思考蛉签,并且闡述我們?yōu)槭裁催x擇Plugin-Killer作為我們最佳的解決方案
禁止插件化技術胡陪。很明顯,Android的插件化技術違背了移動安全的原則碍舍,并導致了多重的安全隱患柠座。禁止這個功能是一個簡單的解決方案,這樣我們的生態(tài)系統(tǒng)就安全了片橡。由于在日常生活中靈性的使用插件化技術有著大量的需求妈经,所以直接禁止插件化技術是不現(xiàn)實的。而且捧书,由于沒有嚴格的標準吹泡,所以全面禁止插件化技術同樣也是不現(xiàn)實的
從檢測使用插件化技術的惡意軟件。一些安全產品(比如防火墻或者殺毒軟件)可能會在用戶安裝此類惡意軟件時發(fā)出警告
但是我們卻很難區(qū)分惡意軟件和普通軟件经瓷,這是因為惡意軟件在開始使用APP使用的是同一個SDK的實例爆哑,而且他們的行為基本一致。這樣就會導致檢測系統(tǒng)有很高的誤報率通過Android 平臺來解決插件化的問題舆吮。最好的解決方案就是讓Android系統(tǒng)支持一種安全的機制來啟動一個應用的多個實例揭朝,我們堅信這是插件化攻擊的最終解決方案。在這個解決方案中色冀,Android系統(tǒng)可以擴展現(xiàn)有的Android安全體制一隔離同一個應用的多個實例潭袱,并且設計一套可配置的交互協(xié)議,這樣當用戶想啟動實例的時候锋恬,就可以直接啟動了屯换。如果這樣做的話,用戶就不需要在第三方APP上進行操作与学,替代的是直接在Android系統(tǒng)上進行操作了趟径,這樣Android 系統(tǒng)就直接扮演了宿主的角色了。這個解決方案看起來來和
AFrame
方案很相近癣防,AFrame
方案就是將主機應用程序與第三方庫相隔離。但是這種解決方案需要發(fā)布和更新所有的移動射擊掌眠,所以它肯定需要花費比較長的時間去設計(比如針對不同的Android版本的兼容性問題)蕾盯。所以一個輕量級的并且更快部署的解決方案是當下最需要的
4.2我們的解決方案:插件殺手
我們遇到一個問題就是:真實的應用程序不知道作為一個插件而被啟動。所以我們的解決方案主要就是要解決上面的這個問題蓝丙。換句話說级遭,像DualTwitter
這樣的軟件之所以能夠釣魚Twitter
的原因是,Twitter它作為原始的APK文件渺尘,它并不知道它作為插件而被啟動挫鸽。所以我們提出一個檢測方法,通過這個檢測方法鸥跟,Android應用程序可以檢測它是否正在運行在插件化技術創(chuàng)建的虛擬環(huán)境中丢郊,并且提供一個可以終止運行的選項盔沫。基于我們隊潛在解決方案的分析枫匾,我們的解決方案既不用禁止插件化技術架诞,也不用對Andorid系統(tǒng)進行任何修改。
Plugin-Killer 使用場景
我們的解決方案——Plugin-Killer是一種防御機制干茉,可提供多種方式來檢測虛擬環(huán)境谴忧,用來防止?jié)撛谕{。如果一個應用程序不想成為新型釣魚的受害者角虫,可以直接將我們的解決方案集成他們APP中沾谓,集成方式既可以是以庫的形式,也可以是sdk的形式戳鹅。就像我們剛剛分析的均驶,普通應用被用作插件在第三方程序中啟動是非常危險的。我們提供的PluginKille
來幫助普通應用的開發(fā)者防止他們的應用被作為插件而啟動粉楚。
良性應用是我們庫的客戶辣恋,他們希望在被作為插件啟動的時候,啟動檢測潛在威脅模软。比如伟骨,Twtter
的合法應用可以將PluginKiller
庫嵌集成到它們的APK中,當DualTwitter
惡意軟件將其作為插件啟動的時候燃异,Twitter
就可以檢測出來這些潛在風險携狭。如果圖12所示,Twiiter
應用程序只需要在其代碼的初始位置添加3行代碼即可回俐。比如在MainActivity
的onCreate
函數(shù)里面添加逛腿。
這兩個紅色標記的函數(shù),由我們PluginKiller庫來實現(xiàn):isLoadedAsPlugin函數(shù)的目的是返回一個布爾值來告訴應用程序是否運行在虛擬空間仅颇;TerminatesApp函數(shù)是我們庫中的實現(xiàn)的另外一個API单默,通過它可以直接終止應用程序或者提供用戶以傳統(tǒng)的方式來啟動這個應用程序。
對于熟悉網絡安全的人員而言忘瓦,他們很自然的將點擊劫持(clickjacking attack)
攻擊與雙開攻擊進行比較搁廓。在點擊劫持
攻擊中,受害人的網頁可能會加載到惡意網頁的iframe中耕皮。為了對抗攻擊境蜕,當受害人服務器生成網頁時,通常會添加一段JavaScript代碼來檢測頁面是否在主框架或子框架內部加載凌停。這種被稱之為FrameBusting
的技術被大多數(shù)流行網站所使用粱年。我們認為雙開惡意軟件與點擊劫持
存在很多相同點。如果在宿主應用創(chuàng)建的虛擬環(huán)境中罚拟,移動應用就崩潰台诗,就可以有效的抵抗這種新型攻擊完箩。
Plugin-Killer 的優(yōu)勢
除了我們的解決方案是唯一為用戶和應用開發(fā)者提供退出選項的解決方案,除此之外拉庶,我們的解決方案還有以下優(yōu)點:
- 目前市面上僅有的解決方案嗜憔。我們是第一個注意到惡意軟件大規(guī)模使用插件化技術的公司。PluginKiller是可以幫助良性應用抵抗這種新型攻擊的最佳解決方案
- 非常輕氏仗,我們的解決方案不需要對移動系統(tǒng)進行任何修改吉捶,它可以在任何版本上的Android系統(tǒng)上運行。移動應用程序除了添加上面的3行代碼皆尔,不需要對其代碼進行任何修改
- 良好的兼容性呐舔。所有Android版本都支持插件化技術,同樣的慷蠕,我們的解決方案也都支持這些所有的版本珊拼。這是因為我們用于檢測虛擬環(huán)境的方法僅僅依賴Android版本通用的API,所以我們的解決方案與所有Android版本兼容
- 操作簡潔流炕。
Plugin-Killer
庫很小澎现,因為它只包含很少的函數(shù)調用和很少的檢測邏輯
4.3、如何檢測虛擬環(huán)境
為了抵抗被不可信的宿主應用動態(tài)加載每辟,我們必須尋找出一個檢測方法剑辫,這個檢測方法可以檢測移動應用是否被作為插件來加載。據我們觀察渠欺,盡管Android插件化技術創(chuàng)建一個虛擬環(huán)境來加載和啟動插件妹蔽,但虛擬環(huán)境仍然與傳統(tǒng)方式所創(chuàng)建的虛擬環(huán)境存在很多差異。
在我們的庫中挠将,我們系統(tǒng)的列舉了所有能區(qū)別差異的方法胳岂,包括:
4.3.1檢測不匹配的AndroidManifest
每一個移動應用的根目錄都必須有一個AndroidManifest.xml文件。AndroidManifest.xml文件向Android系統(tǒng)提供有關應用程序的基本信息舔稀,系統(tǒng)運行任何應用程序的代碼之前乳丰,必須提前獲取該信息。在安裝階段内贮,系統(tǒng)將解析AndroidManifest.xml文件成艘,并記錄其中定義的信息(比如聲明的權限,組件包括Activity贺归、Service)。但是由于插件應用從來沒有被安裝過断箫,并且由主機應用程序動態(tài)啟動拂酣。插件應用和宿主應用的清單會有很多不匹配的地方。我們的庫仲义,嘗試通過發(fā)現(xiàn)插件應用和宿主應用的差異來檢測是否是虛擬環(huán)境婶熬。我們羅列了AndroidManifest中定義的可用于檢測差異的項目:
權限 由于用戶可能會將任何一個APK作為插件二載入剑勾,所以宿主應用通常會聲明大部分Android權限(例如DroidPulgin會聲明125個Android權限)。但是幾乎所有的宿主應用和庫都絕對不會遺漏插件中需要的權限的赵颅。所以虽另,插件被授予的權限絕對大于他們在AndroidManifest.xml里面聲明的權限。我們就可以利用PackageManager從宿主應用程序中獲取授予的權限饺谬,然后嘗試訪問哪些沒有在插件的AndroidManifest.xml里面聲明的權限限制的資源捂刺,如果可以訪問,說明是虛擬環(huán)境募寨,如果不能訪問則說明正常族展。
包名 所有安裝到系統(tǒng)中的Android應用程序都有一個獨特的包名,用于在這個設備上的唯一標示符拔鹰,標示一個應用程序仪缸。由于插件還沒有被安裝,所以可以檢測其包名是否已經注冊到系統(tǒng)中列肢,如果還沒有注冊說明恰画,在插件環(huán)境中。
應用組件名 正如我們所說的瓷马,
DroidPlugin
利用"樁"組件來欺騙AMS拴还,這樣就可以創(chuàng)建一個未在manifest文件中注冊的文件。所以說决采,AMS記錄的是都是"樁"組件的信息自沧,而不是實際調用的"插件組件"的信息。舉個列子树瞭,如果我們調用ActivityManager
的getRunningServices
這個API來獲取正在運行的Service信息拇厢,假設正在使用的是DroidPlugin,則存在AMS中的"樁"Service就可能是stub.ServiceStubStubP08P00
-
檢測宿主應用的運行時信息 鑒于插件是由宿主應用啟動的晒喷,我們發(fā)現(xiàn)插件的運行時信息和由系統(tǒng)啟動的運行時信息略有不同孝偎。所以。所以說凉敲,我們就可以根據運行時信息來分區(qū)是否處于虛擬環(huán)境中
進程信息 PID(進程ID)衣盾,它是一直保持不斷變化的。但是與PID的不同的是UID是保持不變的爷抓,系統(tǒng)在每個應用安裝的時候會給每個應用分配一個UID,只要沒有重新安裝势决,這個UID就不變發(fā)生改變。所以說蓝撇,對于每個應用程序來說果复,它的UID應該是唯一的,除非應用程序顯示請求說要與另外一個應用程序共享一個userid渤昌。由于 插件 APK并沒有安裝到系統(tǒng)虽抄,所以 插件 程序沒有唯一的UID走搁。即便宿主應用可以向DrroidPlugin那樣,fork一個新的進程來啟動它迈窟,這樣就會導致 插件 進程和 宿主應用 所在進程共享不同的PID私植,但是它們的UID卻是一樣的。如果我們要檢索正在運行的應用程序的進程信息车酣,我們需要申請
GET Task
權限(在Lollipop后棄用)曲稼,我們可以使用ActivityManager
類的getRunningAppProcesses
這個API來獲取所有的正在運行的進程信息,它的返回值是一個list骇径。舉個例子躯肌,在DroidPlugin
庫的進程名稱類似于{host app pkg name}:PluginP02
。內部存儲信息 Andorid文件系統(tǒng)會在APP安裝的時候破衔,將文件保存在內部存儲的指定目錄下清女,每一個應用程序都有一個指定的文件目錄,對應的文件目錄就是其包名晰筛。動態(tài)啟動的插件應用的目錄不在其包名下嫡丙,而是在宿主的應用的包名下。舉個例子說明弄下读第,系統(tǒng)通過PackageManager
來分配應用程序包目錄的曙博,所以我們可以通過
PackageManager來獲取應用程序的
dataDir路徑。正常情況下一個應用程序的包路徑是
'/data/data /{pkg name}'怜瞒。由于
DroidPlugin要分離不同的插件保存的數(shù)據父泳,所以每個插件的路徑是宿主應用的子目錄作為
dataDir。例如
DroidPlugin中插件的
dataDir是
/data/data/{host app pkg name}/Plugin/{plugin pkg name}/data/`吴汪。
4.3.2檢測APP的組件
對于Android應用來說惠窄,應用組件是其必不可少的組成部分。一個這些應用組件的獨特之處在于漾橙,任何應用都可以啟動其他應用組件杆融。Android系統(tǒng)的異步消息是通過intent來實現(xiàn),在運行時intent將各個組件進行相互綁定霜运。對于Android系統(tǒng)而言脾歇,動態(tài)啟動一個插件應用和啟動其他普通應用是無差別的。為了同時支持插件之間交互和其他應該交互淘捡,宿主應用需要去自定義一套intent通信協(xié)議藕各。通過自定義的通信協(xié)議,來差異化跳轉焦除。
已啟動APP中的Activity和Service的數(shù)量:
App必須先在AndroidManifest.xml里面注冊Activity和Service,只有這樣系統(tǒng)才能訪問對應的Activity和Service激况。由于插件應用還沒有被安裝,所以宿主必須先預注冊一定數(shù)目的"樁"組件,只有這樣才能欺騙AMS誉碴。在DroidPlugin中,它先預定義了10個Activity和10個Service瓣距。如果這個插件引用需要啟動超過10個Service黔帕,就會產生沖突。發(fā)送靜態(tài)廣播:
Android應用可以向Android系統(tǒng)/其他應用發(fā)送braodcast receiver蹈丸,也可以接收由Android系統(tǒng)/其他應用發(fā)出來的braodcast receiver成黄。這種方式類似于發(fā)布/訂閱的設計模式。應用可以注冊去接收特殊的廣播逻杖。發(fā)送廣播的手奋岁,系統(tǒng)會根據當時已經注冊的廣播接收者來尋找合適的接收者,然后進行廣播轉發(fā)荸百。一個APP即可以靜態(tài)注冊廣播闻伶,也可以動態(tài)的注冊廣播。靜態(tài)廣播是在應用安裝的時候注冊的够话。在安裝應用程序時蓝翰,系統(tǒng)在解析AndroidManifest.xml的時候,會根據里面"intent- filter"標簽來定義一個廣播接收者。應用也可以在代碼中調用registerReceiver
這個函數(shù)來動態(tài)注冊廣播接收者女嘲,動態(tài)廣播接收者是與應用的生命周期息息相關畜份。
由于插件應用程序從來沒有被安裝過,所以AndroidManifest.xml里面定義的靜態(tài)廣播接收者不會被系統(tǒng)解析欣尼。所以DroidPlugin
將解析插件AndroidManifest.xml里面的定義的靜態(tài)廣播接收者爆雹,并在運行時在代碼中動態(tài)去注冊它們。由于動態(tài)廣播接收者和靜態(tài)廣播接收者在攔截廣播方面是相同的愕鼓,所以插件不會特意去區(qū)分他們的不同钙态。但是我們在運行時操縱接收者,還是能檢測出變化的拒啰。
舉個例子說明一下驯绎,我們在插件的AndroidManifest里面注冊一個靜態(tài)廣播接受者,然后我們在運行時注銷所有的廣播接收器(通過使用unregisterReceiver
這個API)谋旦。在真實的環(huán)境下剩失,靜態(tài)接收者還是有效的。但是在DroidPlugin
創(chuàng)建的虛擬環(huán)境中册着,靜態(tài)和動態(tài)的所有廣播接收者都不可用了拴孤。所以,我們可以發(fā)送一個可以被靜態(tài)廣播接收者攔截的廣播甲捏,我們就可以檢測當前環(huán)境是否是虛擬環(huán)境了在運行時修改應用程序組件屬性
我們也可以另一種方式來檢測演熟,即在運行時修改應該程序中組件的屬性來檢測。當應用程序在AndroidManifest里面注冊一個組件的時候,可以注冊一些屬性芒粹,就像組件名兄纺,默認狀態(tài)或者標簽。其中有一個特殊性化漆,就是enable估脆,系統(tǒng)用這個屬性來判斷在APP啟動的時候是否允許實例化。在正常的啟動流程中座云,應用程序通過調用setComponntEnabledSetting
和應用組件名稱
來修改運行時啟動組件的enable屬性疙赠。如果是enabling
,這個組件將會保持可用朦拖。
對DroidPlugin
而言圃阳,他們有一個硬傷就是——在虛擬環(huán)境中,他們無法實例化一個被禁用的組件璧帝。如圖14所示捍岳,我們在插件的清單文件中定義了廣播接收器,并將其的啟動屬性默認設置為false裸弦。然后祟同,我們在運行時再調用setComponentEnabledSetting
這個API來啟動這個接收器。如果它以插件的形式運行理疙,則我們在運行時的啟動行為將不起作用晕城,而且該接收器仍處于禁用狀態(tài)。所以窖贤,我們可以輕易的發(fā)送一個匹配這個接收器的廣播來檢查它是否被棄用砖顷,并把它作為這個應用是否被作為插件的證據。
-
檢測其他插件應用程序的痕跡:
共享native組件赃梧,一些native組件在同一個應用內實例之間共享內部信息滤蝠。即便是插件還沒有運行,宿主應用仍然會保留共享信息授嘀,這樣就會導致一些數(shù)據殘留實例物咳。舉個例子說一下,WebVeiw蹄皱,一個用C++實現(xiàn)的web容器览闰,它會記錄瀏覽狀態(tài)到本地數(shù)據庫中,而且這些記錄還是在同一個應用實例間共享巷折。如果應用被雙開的情況下压鉴,宿主應用和插件應用會被看成一個應用,因此它們共享一個相同的UID锻拘。因此油吭,如果用戶在插件中的WebView登錄過某個網站击蹲,其他插件的用戶就可以再次訪問這個網站來來檢測登錄狀態(tài),遮掩就可以確認自身是否已經在虛擬環(huán)境中了婉宰。
4.4 PluginKiller的評估
為了測試PluginKiller
能夠檢測處各種插件化技術產生的不同的虛擬環(huán)境歌豺,我們拿了很多主流的開源的宿主應用來進行評估。這并不代表圖中所示的流行宿主應用(Parallel Space
心包,Gemini
等)是流浪軟件世曾。我們用他們來進行測試因為當前沒有一套插件化技術的標準。攻擊者谴咸,可以對其代碼進行逆向,并使用類似的方法來實現(xiàn)自己的惡意代碼骗露,甚至會提出一種更新的方法來實現(xiàn)插件化技術岭佳。盡管我們現(xiàn)在只發(fā)現(xiàn)一些惡意軟件只集成了DroidPlugin
和VirtualCore
這兩個插件化庫,但是我們仍想展示PluginKiller
是極有可能檢測出惡意軟件創(chuàng)建的虛擬環(huán)境萧锉。
評估結果如圖15所示珊随。 每一行代表我們前面討論的測試用例的檢測結果,每一列都是不同的虛擬環(huán)境柿隙。 我們構建一個僅嵌入PluginKiller庫的虛擬APK文件叶洞,并使用不同類型的宿主應用程序將其作為插件啟動以獲取檢測結果。 評估顯示PluginKiller可以檢測到所有當前的虛擬環(huán)境禀崖。