在了解系統(tǒng)的activity,service,broadcastReceiver的啟動(dòng)過(guò)程后,今天將分析下360 DroidPlugin是如何預(yù)注冊(cè)占坑的?本篇文章主要分析Activity預(yù)注冊(cè)占坑,Activity占了坑后又是什么時(shí)候開(kāi)始瞞天過(guò)海欺騙AMS的?先看下Agenda:
- AndroidMainfest.xml中概覽
- Activity中關(guān)鍵方法被hook時(shí)機(jī)
- startActivity被hook
- handelPerformActivity被hook
- Activity預(yù)注冊(cè)占坑整體流程圖
- 瞞天過(guò)海,冒充真實(shí)身份,欺騙AMS
AndroidMainfest.xml中概覽
我們知道所有能用的四大組件都要在Manifest中注冊(cè)聲明,第一步,先看AndroidManifest.xml,雖然在說(shuō)hook機(jī)制時(shí),也有提及過(guò),但是畢竟沒(méi)細(xì)致分析,話不多說(shuō),看代碼上圖:
然后看下各個(gè)屬性的意思
表示一個(gè)activity1原來(lái)屬于task1,但是如果task2啟動(dòng)起來(lái)的話,activity1可能不再屬于task1了,轉(zhuǎn)而投奔task2去了。
功能:?jiǎn)?dòng)硬件加速
缺點(diǎn):占用內(nèi)存
特點(diǎn):可以在Application、Activity、Window、View四個(gè)級(jí)別進(jìn)行硬件加速控制
從Android3.0(API Level 11)開(kāi)始,Android 2D渲染管道能夠更好的支持硬件加速。硬件加速執(zhí)行的所有的繪圖操作都是使用GPU在View對(duì)象的畫(huà)布上來(lái)進(jìn)行的。因?yàn)閱⒂糜布铀贂?huì)增加資源的需求,因此這樣的應(yīng)用會(huì)占用更多的內(nèi)存。
啟用硬件加速的最容易的方法是給整個(gè)應(yīng)用程序都打開(kāi)全局硬件加速功能。如果應(yīng)用程序只使用標(biāo)準(zhǔn)的View和Drawable,那么打開(kāi)全局硬件加速不會(huì)導(dǎo)致任何的不良的繪制效果。但是,因?yàn)橛布铀俨⒉恢С炙械?D圖形繪制操作,所以對(duì)于那些使用定制的View和繪制調(diào)用的應(yīng)用程序來(lái)說(shuō),打開(kāi)全局硬件加速,可以會(huì)影響繪制效果。問(wèn)題通常會(huì)出現(xiàn)在對(duì)那些不可見(jiàn)的元素進(jìn)行了異?;蝈e(cuò)誤的像素渲染。為了避免這種問(wèn)題,Android提供以下級(jí)別,以便可選擇性的啟用或禁止硬件加速:
控制硬件加速,能夠用以下級(jí)別來(lái)控制硬件加速:
1、Application級(jí)別
在應(yīng)用的Android清單文件中,把下列屬性添加到元素中,來(lái)開(kāi)啟整個(gè)應(yīng)用程序的硬件加速。
2、Activity級(jí)別
如果應(yīng)用程序不能夠正確的使用被打開(kāi)的全局硬件加速,那么也可以對(duì)Activity分別進(jìn)行控制。在元素中使用android:hardwareAccelerated屬性,能夠啟用或禁止Activity級(jí)別的硬件加速。以下示例啟用全局的硬件加速,但卻禁止了一個(gè)Activity的硬件加速。
3、Window級(jí)別
如果需要更細(xì)粒度的控制,就可以使用下列代碼來(lái)針對(duì)給定的窗口來(lái)啟用硬件加速:
注意:當(dāng)前不能在Window級(jí)別禁止硬件加速。
4、View級(jí)別
能夠使用下列代碼在運(yùn)行時(shí)針對(duì)一個(gè)獨(dú)立的View對(duì)象來(lái)禁止硬件加速:
注意:當(dāng)前不能在View級(jí)別開(kāi)啟硬件加速。View層除了禁止硬件加速以外,還有其他的功能,更多的相關(guān)信息請(qǐng)看本文的“View層”。
以上就是聲明屬性的含義說(shuō)明,作為背景了解即可。重點(diǎn)看下面的分析
Manifest中注冊(cè)了8個(gè)進(jìn)程,加上主進(jìn)程共9個(gè)
然后第每個(gè)進(jìn)程下面又有26個(gè)Activity注冊(cè),一個(gè)service,一個(gè)contentprovider,那么問(wèn)題來(lái)了,搞這么多注冊(cè)在manifest做什么用?仔細(xì)分類(lèi):就兩類(lèi)一類(lèi)是Activity,一類(lèi)是Dialog,我們知道Dialog是建立在Activity之上的,如果Activity被finish或destory后,就會(huì)報(bào)出異常:android.view.WindowManager$BadTokenException: Unable to add window — token android.os.BinderProxy@438e7108 is not valid; is your activity running?
附《插件占坑,四大組件動(dòng)態(tài)注冊(cè)前奏(一) 系統(tǒng)Activity的啟動(dòng)流程》(也可點(diǎn)擊鏈接過(guò)去看詳細(xì)過(guò)程)的activity的啟動(dòng)時(shí)序列圖:
Activity中關(guān)鍵方法被hook時(shí)機(jī)
其中startActivity()和handleLanchActivity()是被DroidPlugin 要欺騙系統(tǒng)的兩個(gè)主要方法:
第一個(gè)方法是最被經(jīng)常使用的startActivity(),hook機(jī)制見(jiàn)《插件開(kāi)發(fā)之360 DroidPlugin源碼分析(二)Hook機(jī)制》中分析,主要是通過(guò)Java的反射機(jī)制替換掉IActivityManager全局對(duì)象,具體IActivityManagerHookHandle的onInstall()方法如下:
第二個(gè)方法是handleLaunchActivity(),這個(gè)方法屬于ActivityThread的一個(gè)叫做H的內(nèi)部類(lèi),前面講Activity啟動(dòng)時(shí),已埋下伏筆,可以參考《插件占坑,四大組件動(dòng)態(tài)注冊(cè)前奏(一) 系統(tǒng)Activity的啟動(dòng)流程》,如果學(xué)過(guò)中間人攻擊協(xié)議的話,我們知道,現(xiàn)個(gè)通信雙方發(fā)出消息后,進(jìn)行消息驗(yàn)證,如果中間人攔截相關(guān)協(xié)議內(nèi)容,通過(guò)一個(gè)代理進(jìn)行轉(zhuǎn)發(fā)出去,從而達(dá)到欺騙的目的,這里暫且理解handleLanchActivity被中間人攻擊了,當(dāng)啟動(dòng)handleLanchActivity時(shí),被DroidPlugin hook后,那多人可能會(huì)想,你怎么hook住hanleLanchActivity呢?別忘了,我們可是在Manifest占了一堆坑的。要是不好理解,可以參看《插件前奏-android黑科技 hook介紹 :http://blog.csdn.net/hejjunlin/article/details/52091833》,可能更直觀些,哪在DroidPlugin中,如何在代碼中瞞天過(guò)海的呢?
我們可以看下:PluginCallbackHook.java,其中有一個(gè)onInstall()方法:
如上代碼也有注釋?zhuān)煽偨Y(jié)為:
1.DroidPlugin不是完全攻擊mH這個(gè)內(nèi)部類(lèi),而是把mH的mCallback成員變量攻擊了,然后替換成了一個(gè)PluginCallback對(duì)象,進(jìn)行消息分發(fā),那么就可以在在PluginCallback的handleMessage()里任意攔截想要分發(fā)的消息,來(lái)欺騙AMS。經(jīng)過(guò)中間人這么一鬧騰,那就能達(dá)到控制這個(gè)區(qū)域的目的了。
最狠的看下面:
上面代碼中,有一個(gè)mH的mCallback,是被攔截攻擊了吧,既然被攔截后又要冒充一個(gè)擔(dān)當(dāng)mH的mCallback職責(zé)相關(guān),(這里暫且夸張的說(shuō))那肯定得扒了它身上的某些特性放到冒充的mCallback吧,如身份驗(yàn)證相關(guān)之類(lèi),所以那原來(lái)的mCallback丟了它的身份相關(guān),不就是廢了,暫且理解為mCallback為null,實(shí)際上有mCallback在未賦值之前,初始化時(shí),本身也是null。然后看下PluginCallback的handleMessage()方法:(ps: PluginCallback簡(jiǎn)直就是仿照ActivityThread中的H內(nèi)部類(lèi)寫(xiě)的,幾乎邏輯一樣,具體可看系統(tǒng)源碼證實(shí))
這里只攔截了一個(gè)消息類(lèi)型為L(zhǎng)AUNCH_ACTIVITY(ActivityThread中的H內(nèi)部類(lèi)中會(huì)有很多消息類(lèi)型,也包含LAUNCH_ACTIVITY)。mCallback不為null,就是發(fā)一些偽裝的消息(因?yàn)槲覀儎倲r截了mCallback),如果為null,返回false,這樣就會(huì)會(huì)再通過(guò)mH調(diào)用回真正ActivityThread的handleLaunchActivity()。(ps:系統(tǒng)發(fā)的消息沒(méi)什么卵用時(shí),我們就不去攔截,暫且理解為這樣)
以上就是兩個(gè)方法怎么被hook相關(guān)分析,也可參考在Hook機(jī)制舉例為IPackageManager的驗(yàn)證簽名被hook的過(guò)程,接下來(lái)就是要看hook中做了什么事?附一張Activity預(yù)注冊(cè)占坑整體流程圖:
前面我們都是在說(shuō)DroidPlugin怎么用中間人攻擊方式,攔截了startActivity()方法和hanleLanchActivity()方法,接下來(lái)要看下攔截了后,怎么把這種身份角色搞變化了(就是一個(gè)怎么扮演冒充的角色過(guò)程):
1.首先得找一個(gè)和真實(shí)的人像的角色,這時(shí)啟用的我們備用人員,也就是事先占的坑stub.ActivityStubxxx。
2.真實(shí)的角色身上有某些特定的特性,如愛(ài)抽煙,頭發(fā)亂糟糟的,像Activity中Intent作為一個(gè)extra傳到另一個(gè)Activity時(shí),還有一些自己的lanchmode(啟動(dòng)方式),theme(主題),這些都是Activity的一些特性,所以stub.ActivityStubxxx也得有這些,否則怎么能達(dá)到冒充呢,這些我們?cè)诖a中早就寫(xiě)好了,所有的那些注冊(cè)的26個(gè)備用人員都是繼承ActivityStub,而ActivityStub是直接繼承Activity,那還說(shuō)啥呢,不就是天然的冒充么?說(shuō)這么多了,直接看代碼IActivityManagerHookHandle$startActvity:
這是一個(gè)靜態(tài)內(nèi)部類(lèi),繼承ReplaceCallingPackageHookedMethodHandler,重寫(xiě)了beforeInvoke方法,暫且理解為在冒充之前的一些準(zhǔn)備工作,如下:
接著再看beforeStartActivity方法:
就是判斷了下Activity的啟動(dòng)模式,接著都調(diào)入doFinshIt(mRunningXXXActivityList),繼續(xù)看此方法:
STUB_NO_ACTIVITY_MAX_NUM為4,上面方法總結(jié)為:runningActivityList(備用activity的list的總數(shù))大于等于3時(shí),就把最早進(jìn)入activityRecord棧中的那個(gè)finish掉,因?yàn)榭泳湍敲炊?,要是都占著不干活,那要它干嘛?/p>
瞞天過(guò)海,冒充真實(shí)身份,欺騙AMS
前面這些,還是小打小鬧,接下來(lái)看一個(gè)核心方法,就是beforeInvoke中的doReplaceIntentForStartActivityAPILow方法:
前面我們說(shuō)了,欺騙了兩個(gè)方法,上面說(shuō)的都是startActivity(),接下來(lái)看另個(gè)一個(gè)方法handleLanchActivity(), 這個(gè)方法在哪呢?我們前面說(shuō)過(guò)有一個(gè)仿照ActivityThread中H內(nèi)部類(lèi)的class叫PluginCallBack,對(duì),handleLaunchActivity就是在接到handleMessage中消息類(lèi)型為L(zhǎng)ANCH_ACTIVITY時(shí)調(diào)用的:
以上就是Activity預(yù)注冊(cè)占坑,并欺騙AMS的過(guò)程,下篇分析Service預(yù)注冊(cè)占坑。
如果你覺(jué)得好,隨手點(diǎn)贊,也是對(duì)筆者的肯定,也可以分享此公眾號(hào)給你更多的人,原創(chuàng)不易