天天看點

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

hook方案,有飲水思源、回饋開源項目的意思。與xposed不同的是,dexposed是自己hook自己的應用,是以不需要root權限。

它的關鍵點是:在native層中先找到要修複的java函數對應的method對象,修改它變為native方法,把它的nativefunc指向hookedmethodcallback。這樣對這個java函數的調用就轉為調用hookedmethodcallback這個native函數了,然後再用這個native函數回調java層自己實作的統一接口來處理。這個統一接口是xc_methodreplacement類,它主要有beforehookedmethod、afterhookedmethod和replacehookedmethod等幾個方法,前兩個在執行原java函數前後做一些事,replacehookedmethod則是替換原java方法。下面來詳細分析下這個hook的過程。

一、dexposedbridge.findandhookmethod

findandhookmethod是hook原java方法的入口,它傳入的參數是類class和方法名,最後一個可變參數parametertypesandcallback,是使用者實作的用于替換原方法的xc_methodreplacement的執行個體。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

先調用xposedhelpers.findmethodexact找到要hook的java方法,再用hookmethod進行真正的hook。

1.findmethodexact根據類名和方法名,用反射找到method,并把它的屬性改為可通路。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

2.hookmethod先把hook成功後的callback、要hook的方法的參數和傳回值類型儲存到additionalhookinfo中,把它作為參數傳給hookmethodnative。hookmethodnative是一個native方法,它的第3個參數slot表示該method在class的方法表中所處的位置,在native的實作中會用到這個slot。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

hookmethodnative的實作環境分dalvik和art,因為dexposed對art的支援不完善,同時art本身的原理和機制也是一個難點,是以本篇隻介紹dalvik下的實作,art的有關内容以後有機會再作介紹。

二、hookmethodnative

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

每一個java的類在虛拟機的實作中都對應着一個c++的classobject。dvmdecodeindirectref是libdvm中的方法,它可以從java對象的間接引用獲得classobject對象,再根據slot,用dvmslottomethod找到method對象。這裡的classobject和method都是虛拟機内部用來表示class和method的資料結構。

然後把原來的method結構先備份到xposedhookinfo中,

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

xposedhookinfo的結構如下:

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

可見,它用originalmethod儲存原來java方法的method,用reflectedmethod儲存原java方法在native的引用,注意這跟originalmethod中儲存的method對象不同。originalmethod中儲存的method可以了解為執行位元組碼的位址,而reflectedmethod中儲存的是用來描述原java方法的一個classobject對象。它們兩個在第五部分重新調用原java方法時會用到。

additionalinfo用來儲存附加資訊additionalhookinfo。接着使用set_method_flag宏把該方法設為native,讓nativefunc指向hookedmethodcallback,這樣對該java方法的調用就會轉為對hookedmethodcallback這個native方法的調用了。insns指向這個方法的位元組碼,在這裡把它改為指向hookinfo,實際上也就是originalmethod的位元組碼的位址。

三、hookedmethodcallback

hookedmethodcallback會回調java層的方法handlehookedmethod,最終會調用到前面說過的,在findandhookmethod中傳入的xc_methodreplacement裡的before、after方法。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

這裡首先把在hookinfo中儲存的資訊作為傳給java層的handlehookedmethod的參數,然後用dvmcallmethod這個dalvik的函數調用xposedhandlehookedmethod這個java的方法。xposedhandlehookedmethod在初始化時已經被設定好了。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

getstaticmethodid是dvm中用來擷取靜态方法位址的函數,可見在初始化時,已經把java的靜态方法handlehookedmethod的位址賦給了xposedhandlehookedmethod了。這裡需要注意兩點,一是這個時候已經不能像沒hook之前那樣,通過jni從native調java的函數,或者從java調native的函數,因為原來java方法的上下文已經被改變了(已經被儲存在hookinfo中),是以後面隻能通過libdvm中的方法,手動修改函數的指向。二是dvmcallmethod的第5和第6個參數originalreflected和original就是第二部分中儲存的方法的引用和方法的位元組碼位址(original被直接轉成了int型),後面第五部分中這兩項還會被重新傳回native層用來找到原java函數的入口。

四、handlehookedmethod

前面說到從native中調回java的方法handlehookedmethod,handlehookedmethod會根據需要,選擇是否還調用原來的java方法,或者隻調用xc_methodreplacement裡自己實作的before、after方法。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

其中beforehookedmethod方法預設會調用replacehookedmethod,我們隻要實作它即可替代對原方法的調用。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

如果param.returnearly為false才會調invokeoriginalmethodnative執行原來的方法。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

預設的beforehookedmethod中會調setparam,把param.returnearly的值設為為true,這樣就不會再調用原來的java方法了。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

最後還要把傳回值傳回。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

五、invokeoriginalmethodnative

如果在java層需要重新調用原java函數,那麼在第二部分中把原java函數的資訊備份到hookinfo中就能起到作用了。java層的invokeoriginalmethod方法會調一個native的方法invokeoriginalmethodnative來實作這個過程。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

這個native函數同樣在初始化時就被設定好了:

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

要調用的invokeoriginalmethodnative在虛拟機中method是dexposedinvokeoriginalmethod,這裡傳入了第二部分中備份的原java方法的對象引用reflectedmethod和位元組碼位址int型的original。

dvmsetnativefunc的第2個參數是dalvikbridgefunc類型的指針,這個函數會把dexposedinvokeoriginalmethod的nativefunc指向xxx_invokeoriginalmethodnative。再次注意此時不能像平常的jni調用那樣,java層的invokeoriginalmethodnative經過jni注冊後能直接調到com_taobao_android_dexposed_dexposedbridge_invokeoriginalmethodnative了。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

dvminvokemethod跟dvmcallmethod一樣,都是dalvik中用來直接調method的函數,這樣就完成了對原java方法的調用。

最後一句話概括這種hook方法,就是通過把原java方法的類型改為native來把對java函數的調用轉到native層,在native層用dvm的各種函數來操作method的指針和對象來控制函數流程。

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

百分百原創,每周兩篇,阿裡、魅族、nvidia、龍芯、炬力、拓爾思等頂級企業資深工程師分享----嵌入式、linux、物聯網、gpu、android、自動駕駛等技術,歡迎掃碼關注微信公衆号:嵌入式企鵝圈,實時推送原創文章!

Android熱更新檔技術—dexposed原理簡析(手機淘寶采用方案)

繼續閱讀