Hook技術(shù)實(shí)現(xiàn)大型集中式登錄框架

前言:類(lèi)似于京東、淘寶等大型app,不需要賬號(hào)登錄,也能瀏覽商品,但是等你需要加入購(gòu)物車(chē)或者開(kāi)始購(gòu)買(mǎi)時(shí)候,就需要跳轉(zhuǎn)到登錄界面,實(shí)現(xiàn)這個(gè)需求,可以用AOP來(lái)實(shí)現(xiàn),也可以用Hook技術(shù)實(shí)現(xiàn),這篇文章講的是通過(guò)Hook技術(shù)來(lái)實(shí)現(xiàn)登錄架構(gòu)。

一、什么是Hook?

Hook技術(shù)也稱(chēng)為鉤子函數(shù),鉤子函數(shù)實(shí)際上是一個(gè)處理消息的程序段,通過(guò)系統(tǒng)調(diào)用,把它掛入系統(tǒng)。在系統(tǒng)沒(méi)有調(diào)用該函數(shù)之前,鉤子程序就先捕獲該消息,這樣鉤子函數(shù)先得到控制權(quán),這時(shí)鉤子函數(shù)既可以加工處理(改變)該函數(shù)的執(zhí)行行為,還可以強(qiáng)制結(jié)束消息的傳遞。

二、Hook技術(shù)(java層面)實(shí)現(xiàn)途徑

第一:找到Hook點(diǎn);(這一點(diǎn)是最難的,是尋找方法的過(guò)程)
第二:找到Hook方法,然后插入我們執(zhí)行前的代碼和執(zhí)行后的代碼;
第三:將Hook方法放到系統(tǒng)之外執(zhí)行。
備注:實(shí)現(xiàn)Hook技術(shù),可以分兩個(gè)層面,一個(gè)是java層,就是通過(guò)反射,另一個(gè)是ndk層,比如andfix、xPos等,直接找到j(luò)ava對(duì)象來(lái)操作。

三、Hook技術(shù)在java層有個(gè)前提條件

找到的對(duì)象,一定要是靜態(tài)的,原因是反射獲取的實(shí)例對(duì)象一定要和內(nèi)部方法有關(guān)聯(lián),假如不是靜態(tài)的反射之后就不是同一個(gè)對(duì)象了。

四、Hook技術(shù)實(shí)現(xiàn)登錄流程說(shuō)明

寫(xiě)在前面:登錄架構(gòu)需要劫持Android系統(tǒng)中的AMS.
打開(kāi)Activity的源碼,找到startActivity的方法,發(fā)現(xiàn)它內(nèi)部的核心方法是:
ActivityServiceNative.getDefault().startActivity();
此時(shí)要將這個(gè)核心方法拆分為兩個(gè)部分:1.ActivityServiceNative.getDefault;2.startActivity


image.png

步驟一、找到了Hook點(diǎn)是ActivityServiceNative.getDefault,首先我們要還原getDefault的成員變量


image.png

這一步我們得到了IActivityManager,接下來(lái)要在塔調(diào)用的startActivity方法之前和之后插入我們自己的業(yè)務(wù)邏輯,那么這一點(diǎn)就是相當(dāng)于把系統(tǒng)的startActivity拉到我們自己的代碼來(lái)執(zhí)行,那么此刻對(duì)于Java層有兩種實(shí)現(xiàn)方法:1.動(dòng)態(tài)代理;2.設(shè)置接口。
考慮到IActivityManager本身就是一個(gè)接口,同時(shí)系統(tǒng)也沒(méi)有提供額外的接口給我們,所以這里使用動(dòng)態(tài)代理的方法。
代理設(shè)計(jì)模式:可以粗俗的理解為創(chuàng)造一個(gè)假的孫悟空,來(lái)代替真的孫悟空,Proxy.newProxyInstance(),該方法三個(gè)參數(shù),在下圖中有注釋說(shuō)明:

image.png

image.png

好了,做到這一步,然后再M(fèi)ainActivity中執(zhí)行startActivity的代碼,發(fā)現(xiàn)InvocationHandler中的invoke兩行日志可以答應(yīng)出來(lái),證明我們已經(jīng)對(duì)startActivity成功Hook。

步驟二、接下來(lái),新建一個(gè)ProxyActivity,我們可以先做這樣一個(gè)測(cè)試,就是MainActivity執(zhí)行startActivity方法跳轉(zhuǎn)到SecondActivity,然后我們?cè)趇nvoke方法中,進(jìn)行一次"瞞天過(guò)海"的騷操作,就是讓它跳轉(zhuǎn)到ProxyActivity!如圖所示:

image.png

步驟三、完成了步驟一和步驟二,就完成了startActivity的hook,但是只是完成了一半,因?yàn)橥ㄟ^(guò)觀察ActivityThread源碼發(fā)現(xiàn),拉起一個(gè)Activity的核心方法是在ActivityThread的內(nèi)部類(lèi)Handler,在收到消息為100之后,執(zhí)行LaunchActivity方法。所以我們接下來(lái)還要進(jìn)行第二個(gè)Hook點(diǎn),就是找到Handler的handlerMessage方法,通過(guò)源碼可知,ActivityThread的內(nèi)部類(lèi)H不是靜態(tài)的,那我們就找ActivityThread的本身有沒(méi)有靜態(tài)的對(duì)象(這里衍生個(gè)問(wèn)題,如果ActivityThread本身也沒(méi)有靜態(tài)的對(duì)象,我們?cè)撛趺崔k?那只有往上一步看看哪些上層的類(lèi)持有ActivityThread的靜態(tài)對(duì)象),幸運(yùn)的是ActivityThread類(lèi)由一個(gè)靜態(tài)的成員對(duì)象:sCurrentActivityThread
image.png

上圖中的注釋我寫(xiě)的很清楚了,這里通過(guò)設(shè)置接口的方式,來(lái)將handlerMessage拉到我們自己的代碼里來(lái)執(zhí)行,如下圖所示:

image.png

寫(xiě)到這里我們就完成了簡(jiǎn)單的集中式登錄架構(gòu),此刻我突然回想起在2019年8月份在oppo面試的一道題目,當(dāng)時(shí)面試官問(wèn)到:如何加載一個(gè)未注冊(cè)的Activity?它是怎么繞過(guò)系統(tǒng)AMS的檢查?這里我再次做一個(gè)總結(jié)性的回答:
1.Activity的跳轉(zhuǎn)入口對(duì)于Android層面來(lái)說(shuō)是startActivity方法,我們?cè)趫?zhí)行startActivity方法時(shí)候,必須要傳入Intent這個(gè)意圖,這個(gè)Intent就包含有要跳轉(zhuǎn)的頁(yè)面信息,可以是顯示的也可以是隱試的,對(duì)于集中式登錄框架來(lái)講,就必須要hook抓住系統(tǒng)的startActivity方法,然后通過(guò)動(dòng)態(tài)代理的方式,重寫(xiě)InvocationHandler的invoke方法,將傳遞過(guò)來(lái)的Intent,轉(zhuǎn)換為一個(gè)注冊(cè)過(guò)的ProxyActivity,這里就是和阿里插件的插樁式類(lèi)似,然后將真實(shí)的意圖通過(guò)鍵值對(duì)的方式保存到新的Intent中,這里就然后了AMS的檢查;
2.因?yàn)槔鹨粋€(gè)Activity,核心方法是在ActivityThread類(lèi)中的Handler類(lèi),當(dāng)接收到LAUNCH_ACTIVITY(100)這個(gè)消息后,執(zhí)行LaunchActivity這個(gè)方法,所以我們還要Hook住Handler的HandlerMessage這個(gè)方法,因?yàn)镠andler本身已經(jīng)提供了Callback這個(gè)接口,所以我們可以通過(guò)設(shè)置接口的方式,將HandlerMessage這個(gè)方法拉到自己的業(yè)務(wù)代碼中來(lái),重新對(duì)Intent進(jìn)行還原。
所以回到到以上兩點(diǎn),應(yīng)該就能把這個(gè)面試問(wèn)題解釋清楚。
Demo地址:
https://github.com/cWX411904/HookPlugin

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容