1. 程式人生 > >Android中免root的hook框架Legend原理解析

Android中免root的hook框架Legend原理解析

一、前言

Android中hook框架已經非常多了,最優秀的當屬Xposed和Substrate了,這兩個框架我在之前的文章都詳細介紹過了,不瞭解的同學,可以轉戰這裡:http://www.wjdiankong.cn;但是這兩個框架用於破解逆向是非常有用的,可惜他們最大的侷限性就是需要root許可權,這個幾乎現階段可能阻礙了很多產品的商業化,畢竟國內人的安全意識越來越高了。所以這裡就需要藉助一個免root的hook框架了。而對於免root的框架最大的好處就在於無需root許可權,但是弊端就是隻能hook自身,對於系統其它app無能無力,就有人好奇了,只能hook自己有個卵用,的確是沒什麼用,但是也並非一點用都沒有。

二、免root的hook功能用途

關於Android中的Hook機制,我在之前已經說得非常詳細了,大致就兩個方式:

第一個方式:root許可權,直接hook系統,可以幹掉所有app。

第二種方式:免root許可權,但是隻能hook自身。

對於免root許可權只能hook自身,並非一點用都沒有,比如我之前介紹到的自動破解簽名校驗工具kstools,就是藉助這個原理實現,不瞭解原理的同學可以看這裡:Android中自動破解簽名校驗工具kstools,我們在破解逆向app的時候,需要反編譯,二次打包,那麼這時候其實我們想針對於這個app做點手腳,就可以藉助這個技術,比如現在想改一個app,使得他獲取系統的imei值是隨機的,有這種需求的,有的遊戲有的功能會用裝置的imei值做唯一處理,隨機imei值的話就可以跳過這個功能了。那麼這時候我們可以反編譯這遊戲,在遊戲入口處加上hook程式碼,即hook遊戲自身的imei值即可

,這就是需求,只需要hook這一款遊戲即可。這樣無需在用xposed來編寫外掛了。遊戲二次打包即可使用了。

三、以往hook框架原理分析

那麼其實免root進行hook功能在之前我已經介紹過了一款阿里的開源框架Dexposed了,不過這個框架已經廢棄了,取而代之的是AndFix,原理很簡單在native層把Java層的方法強制改成native型別,然後在將方法的native標誌指向自定義的native函式即可。這樣原來的方法就會走到自定義的native函式中,這個框架是非常優秀的AOP框架,可惜相容性問題不能繼續維護了。取而代之的是AndFix,關於它的原理就更簡單了,他沒有了AOP功能,直接將原始方法和自定義的新方法資訊進行對換,這樣原來方法執行的邏輯就是新的方法了。這個框架主要用於熱修復,所以沒必要需要AOP功能了。而今天介紹的這款框架原理也是類似,只不過覺得比較好的是,他把大部分的功能都放到了Java層,這樣的相容性就非常好了,而且自身的相容也很優秀。

四、Legend框架原理分析

下面就來介紹一下他的原理,程式碼量不是很多,框架下載地址可以去github上:https://github.com/asLody/legend,下載下來直接執行就ok了,我們繼續來分析它的程式碼吧:


進入這個方法檢視:


到這裡我們會發現,他是編譯傳入進來的class類,然後編譯他所有用到了Hook註解的方法,獲取其需要hook的方法資訊,具體樣式為:類名::方法名@引數1#引數2#...

然後解析完了註解獲取方法簽名信息之後,開始呼叫hookMethod進行hook操作:


這裡看到,每個hook方法必須是static型別的,然後會區分是art還是dalvik的,分別處理,這裡直接分析dalvik方法,後面的程式碼是有一個快取池,用於快取每次替換完之後的原始方法資訊,為了後面會呼叫原始方法功能。下面繼續來看dalvik方法的hook程式碼:


這裡首先會獲取原始方法和hook新方法對應的dalivk的資料結構資訊,這個就是框架的核心點了,關於dalivk對應的方法結構體資訊大致如下:

  • accessFlags: 各個不同標誌位表示此方法的多個屬性,其中標誌位0x00000100表明此方法是native的
  • registersSize: 該方法總共用到的暫存器個數,包含輸入引數所用到的暫存器,還有方法內部另外使用到的暫存器,在呼叫方法時會為其申請棧記憶體
  • outsSize: 該方法呼叫其他方法時使用到的暫存器個數,注意:只有此方法為非native方法時,此值才有效.
  • insSize: 該方法輸入引數用到的暫存器個數(registersSize包含此值)
  • insns: 若方法型別為1,這裡指向實際的位元組碼首地址;若方法型別為2,這裡指向實際的JNI函式首地址;若方法型別為3,這裡為null
  • jniArgInfo: 當方法型別為2時有效,記錄了一些預先計算好的資訊(具體資訊格式與實際CPU架構有關,但總是包含返回值型別),從而不需要在呼叫的時候再通過方法的引數和返回值實時計算了,提高了JNI呼叫的速度。如果第一位為1(即0x80000000),則Dalvik虛擬機器會忽略後面的所有資訊,強制在呼叫時實時計算
  • nativeFunc: 若方法型別為1,此值無效;若方法型別為2,這裡指向dvmCallJNIMethod;若方法型別為3,這裡指向實際的處理函式(DalvikBridgeFunc型別)
還記得最後一個引數嗎?當初介紹Dexposed框架就是利用這個引數進行操作的,他對應的就是一個方法的native函式,對於AndFix框架,其實也就是直接替換方法的這些結構體資訊即可。替換新舊方法的結構體資訊,做到移花積木的功能:
然後就把替換之後額資料寫入到記憶體中,而這裡我們要注意的是,操作記憶體,Java實在不靠譜的,所以這裡需要將工作移動到native層做,操作記憶體資料,指標是萬能的,所以就跑到C++中幹了:
這裡看到,其實不是寫入記憶體,而是對記憶體資料的一個替換,直接利用指標方便快捷。

五、案例用法

那麼到這裡,其實我們就大致分析完了這個框架的功能,關於art型別的可以自行分析程式碼,原理都是一樣的,這裡的hook機制非常簡潔,直接構造出新舊方法對應的虛擬機器資料結構,然後替換資訊,會寫到記憶體中即可。和阿里的AndFix框架原理幾乎一樣。分析完了原理之後,接下來才是正事,演示一個案例,這裡主要介紹兩個案例,首先來看看如何hook系統的imei值:
這裡需要用到註解,形式如:類名::方法名,因為這裡沒有引數資訊,所以忽略,然後在定義一個新的hook方法,每個hook方法第一個引數必須是hook方法所屬的類型別,這裡直接返回imei值為110,然後在獲取imei值看看效果:
看到了,hook成功了,操作就是這麼簡單。下面再來看一個例子,就是hook應用中所有的webview載入的url值,這個也是這次我要分析這個框架的原因,因為專案需要,想攔截應用所有webview載入的url值:
這裡看到了,我們一般用WebView載入url都會走shouldOverrideUrlLoading方法,所以直接hook這個方法即可,看到這裡的註解型別也好理解:類名::方法名@引數1#引數2...,這裡還有一個重要的知識就是呼叫callSuper方法可以呼叫原來的方法,這樣我們只做了一層攔截,不要破壞原始方法的執行流程,而這裡可以呼叫原始方法其實就是利用之前提到的原始方法快取池功能即可實現,這裡可以看出有AOP的意思了。執行看一下效果:
這裡會把每個頁面載入請求的url進行攔截了,這就是我專案想要的功能。因為上面分析了框架的原理,大部分功能都是在Java層做的,這樣很大程度上能夠做到相容,因為這樣,我也想嘗試利用這個框架來操作專案,畢竟也算是一種嘗試。注意:1、框架可以選擇不使用註解的方式進行hook,直接使用api方式,具體用法參見github上說明。2、hook的時機最好要早,一般在程式的入口處即可。

六、總結

最後還是想說這個框架本身來說並不是很複雜,但是思想還是很重要,記住這種hook思想對應用開發還是逆向都有很大的幫助,相信未來我們還是有需求需要用到這個優秀的框架。敬請期待!

《Android應用安全防護和逆向分析》

點選立即購買:京東  天貓

更多內容:點選這裡

關注微信公眾號,最新技術乾貨實時推送

編碼美麗技術圈微信掃一掃進入我的"技術圈"世界
掃一掃加小編微信
新增時請註明:“編碼美麗”非常感謝!