HOOK

一、Binder機制

相信開發者都知道系統的服務其實都是一個遠程Binder對象,而這個對象都是由ServiceManager大管家管理的,用戶在使用系統服務的時候,會通過指定服務的Stub方法的asInterface把遠程的Binder對象轉化成本地化對象即可使用,而在這個過程中,我們也知道因為系統服務是在system_server進程中的,所以這個系統服務使用過程中屬于跨進程調用,那么返回的對象其實就是Proxy代理對象。

二、系統中服務使用流程

本文主要就是借助這個知識點,通過Hook系統的服務來攔截服務方法,下面我們就通過系統剪切板服務案例作為分析


這里看到了,使用系統服務的時候都是用了getSystemService方法,通過定義在Context中的服務描述符常量來獲取服務對象,而getSystemService方法定義在ComtextImpl.java類中:


這里維護了一個ServiceFetcher的Map結構,看看這個結構在哪里填充數據的:


在registerService方法中添加一個服務名稱和一個ServiceFetcher對象,而這個方法在靜態代碼塊中進行調用的:


我們找到了ClipboardManager這個服務:


這里其實是一個ClipboardManager對象,其實這個對象是內部封裝了IClipboard.Stub功能,可以看看其他的服務:


比如這里的聯網服務,直接調用了IConnectivityManager.Stub類的asInterface方法獲取Proxy對象。

下面就進去ClipboardManager.java中看看究竟:

看到這里的設置剪切板內容的方法,其實內部是調用了getService方法獲取對象然后在調用指定方法,那么可以大概知道了這個getService方法返回的應該就是IClipboard.Stub通過asInterface方法返回的Proxy對象:


好吧,果然是這樣,這里通過ServiceManager獲取到Clipboard的遠端IBinder對象,然后通過asInterface方法返回一個Proxy對象即可。

到這里我們就簡單的分析完了系統中的獲取剪切板的服務,其實系統中的服務都是這么個邏輯,只是有的可能會在外面包裝一層罷了,下面總結一下流程:


現在只要記住一點:每次獲取系統服務的流程都是一樣的,先通過ServiceManager的getService方法獲取遠端服務的IBinder對象,然后在通過指定服務的Stub類的asInterface方法轉化成本地可使用對象,而這個對象其實就是一個Proxy對象,在這個過程中,Stub類繼承了Binder對象和實現了AIDL接口類型,Proxy對象實現了AIDL接口類型,而AIDL接口類型實現了IInterface接口類型。

三、Hook系統服務

上面分析完了Android中系統服務的使用流程以及原理解析,下面在來看一下Android中實現Hook機制的方法和原理解析,我們知道其實在很多系統中都存在這樣一個Hook技術,有的也叫作鉤子,但是不管任何系統,Hook技術的核心點都是一樣的,只有兩點即可完成Hook技術:

1、找到Hook點,即你想Hook哪個對象,那么得先找到這個對象定義的地方,然后使用反射獲取到這個對象實例。所以這里可以看到,一般Hook點都是一個類的單例方法或者是靜態變量,因為這樣的話Hook起來就非常方便,都是static類型,反射調用都比較方便無需具體的實例對象即可。而關于這個點也是整個Hook過程中最難的點,因為很難找到這個點。Android中主要是依靠分析系統源碼類來做到的。

2、構造一個Hook原始對象的代理類,關于這個代理其實在Java中有兩種方式,一種是靜態代理,一種是動態代理。

靜態代理:代理類中維護一個原始對象的成員變量,每個方法調用之前調用原始對象的方法即可。無需任何條件限制

動態代理:比靜態代理復雜點就是有一個規則:就是原始對象必須要實現接口才可以操作,原理是因為動態代理其實是自動生成一個代理類的字節碼,類名一般都是Proxy$0啥的,這個類會自動實現原始類實現的接口方法,然后在使用反射機制調用接口中的所有方法。


案例使用就很簡單了,下面我們通過源碼分析這個原理:

主要調用了getProxyClass0方法生成代理類的字節碼:

然后生成代理類:

看到這里,其實這里的生成字節碼不是很復雜的,我們可以借助asm等工具包就可以手動的生成一個字節碼,然后在使用類加載器加載即可,所以會發現需要傳遞類加載器。(更多開發技術加群:178852651驗證:022)

當上面生成代理類之后,我們可以把這個類反編譯看一下,看一下方法的調用,在代理類中的靜態代碼塊:


會使用反射獲取到類的所有方法。


然后在指定方法中調用傳遞進來的InvocationHandler的回調接口的invoke方法,就是這么實現的。

從源碼角度分析完動態代理之后,發現其實沒什么復雜的,就是手動的生成一個代理類,然后用反射獲取類中所有的方法,在指定方法中用反射調用,同時回調InvocationHandler的invoke方法即可,所以這里看到InvocationHandler中的invoke方法的第一個參數對象是代理類對象。


注意:

在JavaWeb開發中我們會用到Spring框架中的AOP編程,其實他就是利用了Java中動態代理技術,但是他依賴的是CGlib的功能,不是采用Java原生的這種自動產生代理類,從上面可以看到能夠做動態代理的類必須要實現一個接口,而這一個規則有時候要求非常高,很多類都沒有實現接口,導致無法實現代理功能,所以Spring采用了cglib,原理其實差不多,他采用asm工具包也是手動生成一個類,但是這個類是原始對象的子類,這樣也可以實現代理功能,但是這樣一來也有一個限制了,那就是代理對象不能是final類型,同時一些主要方法最好不能是final類型的,當然這個限制和上面的那個接口實現限制比起來還是好點的。

到此我們了解了Java中的Hook技術的核心知識點了,下面就用開始的剪切板服務來做實驗,我們Hook系統的剪切板服務功能,攔截其方法,上面也說道了,既然要Hook服務,首先得找到Hook點,通過開始對Android中系統服務的調用流程分析知道,其實這些服務都是一些保存在ServiceManager中的遠端IBinder對象,這其實是一個Hook點:

其實ServiceManager中每次在獲取服務的時候,其實是先從一個緩存池中查找,如果有就直接返回了:


而這個緩存池正好是全局的static類型,所以就可以很好的使用反射機制獲取到他了,然后進行操作了。

接下來,我們就需要構造一個剪切板的服務IBinder對象了,然后在把這個對象放到上面得到的池子中即可。那么按照上面的動態代理的流程,

第一、原始對象必須實現一個接口,這里也正好符合這個規則,每個遠程服務其實是實現了IBinder接口的。

第二、其次是要有原始對象,這個也可以,通過上面的緩存池即可獲取

有了這兩個條件那么接下來就可以使用動態代理構造一個代理類了:

通過反射去獲取ServiceManager中的緩存池Binder對象就不多說了,完全反射機制即可,我們先獲取到緩存池,然后得到剪切板服務Binder對象,構造一個代理類,最后在設置回去即可。下面主要來看一下構造了代理類之后,如何攔截哪些方法?

這里一定要注意了,有的同學可能想直接在這里攔截setPrimaryClip這樣的剪切板方法不就可以了嗎?想想是肯定不可以的,為什么呢?因為我們現在代理的是遠端服務的Binder對象,他還沒有轉化成本地對象呢?如何會有這些方法呢,而我們真正要攔截的方法是IClipboardManager,其實就是Proxy類,而這個對象也是Stub類的asInterface方法得到的,所以我們現在的思路是有了遠端服務的代理對象,攔截肯定是攔截這個代理對象Binder的一些方法,那么這個遠端服務有哪些方法會在這個過程中被調用呢?我們再看看之前的一個簡單AIDL的例子:

在asInterface方法中可以看到,傳遞進來的就是一個遠端服務IBinder對象,這里會先調用它的queryLocalInerface方法獲取本進程的本地化對象,那么這個方法就是攔截的目標了。

然后在想,我們如果想攔截IClipboardManager的setPrimaryClip方法,其實就是要攔截ClipboardManager$Proxy的這些方法,那么還需要做一次代理,代理ClipboardManager$Proxy類對象

第一、ClipboardManager$Proxy類實現了AIDL接口類型,符合規則。

第二、我們可以直接使用反射獲取到IClipboardManager$Stub類,然后反射調用它的asInterface方法就可以得到了IClipboardManager$Proxy對象了,符合規則。


到這里,看來這個對象也符合了代理的條件,那么就簡單了,繼續使用動態代理機制產生一個代理類即可:


這個代理類的InvocationHandler中,先需要通過反射獲取到Proxy原始對象:


最后才開始實現攔截操作。

下面來看一個實驗結果:


我們調用系統的剪切板服務,但是返回的結果卻是:


看到了,這里的剪切板的內容已經被之前攔截,內容也被替換了。

上面就全部介紹了如何Hook系統的剪切板服務功能,流程如下:


1、我們的目的就是攔截系統的服務功能,那么最開始的入口就是服務大管家ServiceManager對象,而在他內部也正好有一個遠端服務對象的IBinder緩存池,那么這個變量就是我們操作的對象了,可以先使用反射機制去獲取到他,然后在獲取到指定的剪切板服務IBinder對象實例。

2、下一步肯定是Hook這個剪切板服務的Binder對象,這里采用動態代理方式產生一個Binder對象代理類,符合兩個規則:

1》這個Binder對象實現了IBinder接口類型

2》我們已經得到了原始的Binder對象實例

構造完代理類之后,我們攔截的方法是queryLocalInterface方法,為什么是這個方法呢?因為在整個服務使用過程中之后在Stub類中使用到了這個方法,(更多開發技術加群:178852651驗證:022)很多同學會認為為什么不在這里直接攔截系統方法呢?這是一個誤區,要想清楚,這里的代理對象是遠程服務的Binder,還不是本地化對象,不能會有哪些系統方法的,所以得再做一次Hook,去Hook住系統的本地化對象。

3、在攔截了Binder對象的queryLocalInterface方法之后,再一次做一下本地化服務對象的代理生成操作,而這個本地化對象一般都是IClipboard$Proxy,那么動態代理的規則:

1》本地化服務對象都會實現AIDL接口類型(這里才有哪些我們想攔截的系統方法)

2》通過反射調用IClipboard$Stub類的asInterface方法得到IClipboard$Proxy類對象實例

符合這兩個規則那么就可以產生代理對象了,然后開始攔截服務的指定方法即可。

上面總結的這個流程是可以完全用于其他系統服務的Hook工作的,因為系統服務的機制都是一致的,所以這個流程一定要理解清楚,后面的工作才好進行。

四、補充說明

有的同學可能會好奇詢問,這個Hook系統服務貌似只對本應用有效吧?哈哈,的確是這樣的,上面的攔截只會對本應用有效,那有的同學會問,只對本應用有效意義就不是很大的,其實這個要看個人需求了,后面會介紹一些開發中遇到的問題,就需要借助這個技術去解決了,但是真正能夠攔截系統的服務對所有的應用有效,其實想想實現也不難,因為應用都會請求服務,而所有的服務都在system_server進程中,那么就可以采用root之后,注入system_server進程,那時候在開始Hook工作即可完成真正意義上的攔截操作,這個用途就大了,比如我們可以修改系統的經緯度信息,偽造假的當前位置信息,篡改設備的IMEI值,讓有的游戲識別唯一設備無效等。

五、總結

到這里我們就介紹完了Android中Hook系統服務的流程,本文中主要介紹了Hook系統剪切板服務,攔截指定方法,其實后面還會繼續介紹攔截AMS和PMS服務,實現應用啟動的攔截操作,達到我們想要的效果。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容