天天看點

Xposed架構

有關Xposed架構的說明有一大堆,這篇blog寫得比較詳細。最近也在利用Xposed架構開發基于短信的應用,這裡進行總結一下。

Xposed架構是是GitHUB上rovo89設計的一個針對Android平台的動态劫持項目。通過替換/system/bin/app_process程式控制zygote程序,使得app_process在啟動過程中會加載XposedBridge.jar這個jar包,進而完成對Zygote程序及其建立的Dalvik虛拟機的劫持。與采取傳統的Inhook方式相比,Xposed在開機的時候完成對所有的Hook Function的劫持,在原Function執行的前後加上自定義代碼。

因為Xposed工作原理是在/system/bin目錄下替換檔案,在install的時候需要root權限,但是運作時不需要root權限。此外,需要在Android 4.0以上版本的機器中才能運作。

Xposed的部分核心源碼在github上是開源的,主要的子產品和包如下:

  1. XposedBridge.jar

    Xposed提供的jar檔案,負責在native層和framework層進行互動,Android系統的/system/bin/app_process程序啟動過程中會加載該jar包,Xposed架構所有Modules的開發與運作都是基于該jar包的支援

  2. Xposed

    Xposed架構中的C++部分,主要用來替換app_process檔案,同時為XposedBridge提供JNI方法

  3. XposedInstaller

    Xposed的安裝包,負責配置Xposed的工作環境,并提供管理架構子產品、激活應用子產品、下載下傳應用子產品、日志等功能

  4. XposedMod

    基于Xposed架構開發的子產品(Module),如其中的AppSettings是一個可進行權限動态管理的應用

Xposed的hook原理

在Android系統中,應用程式程序都是由Zygote程序孵化出來的,而Zygote程序是由Init程序啟動的。Zygote程序在啟動時會建立一個Dalvik虛拟機執行個體,每當它孵化一個新的應用程式程序時,都會将這個Dalvik虛拟機執行個體複制到新的應用程式程序裡面去,進而使得每一個應用程式程序都有一個獨立的Dalvik虛拟機執行個體。這也是Xposed選擇替換app_process的原因。除此之外,Zygote程序在啟動的過程中,還會将Java運作時庫加載到程序中來,以及注冊一些Android核心類的JNI方法到前面建立的Dalvik虛拟機執行個體中去。

Xposed架構通過替換系統目錄下/system/bin/app_process程序,進而控制zygote程序,最後使得app_process程序在啟動的過程中,加載其架構的XposedBridge.jar包,令每個Android應用程式啟動時,都加載XposedBridge.jar包。XposedBridge.jar具有一個私有的Native(JNI)方法hookMethodNative,它提供一個方法對象,利用java中的反射機制進行對内置方法的覆寫,進而實作對Android系統API的hook。

綜上所述,Xposed架構實作hook的具體流程如下:

1) Android系統啟動,zygote程序加載XposedBridge.jar包;

2) Xposed将所有需要替換的Method通過JNI方法hookMethodNative處理,将方法對象作為輸入參數,并改變Dalvik虛拟機中對于該方法的定義,hookMethodNative會将該方法的類型變為native,同時,将此方法的實作連結到本地通用類的方法;

3) hookMethodNative将被hook的Method指向Native方法xposedCallHandler,使得Method被調用時,其通用類的方法運作,不影響其調用者;

4) xposedCallHandler轉入handleHookedMethod,利用它傳遞Method相應的參數,控制方法執行流程,根據開發者輸入的參數,在原方法執行之前或者之後運作替換的函數。

Xposed子產品及相關方法介紹

在Android系統環境中對Xposed架構進行安裝後,開發者可以通過編寫Xposed子產品的方式使用Xposed架構的接口。Xposed子產品設定了部分特殊資料标志位,是以需要在應用程式的工程中進行相應的配置。

1) Xposed子產品編寫配置

具體應用實作中,需要在AndroidManifest.xml檔案中添加如下内容:

<meta-data  android:name="xposedmodule"  android:value="true" />
           

同時需要将XposedBridge.jar包導入工程,并在assets目錄下建立“xposed_init”檔案,在檔案中說明需要加載到XposedInstaller的入口類。完成相應的配置後,即可按照開發一般Android應用程式的方式進行開發,開發完成後在有Xposed架構的Android環境中安裝,安裝完成後激活相應的應用并重新開機,此子產品就會依賴于Xposed架構正常運作。

2) Xposed接口方法介紹

Xposed提供了豐富的接口方法以便開發者調用,其中較為常用的接口方法有handleHookedMethod、findAndHookedMethod等,下面對這些較常用的方法進行說明。

IXposedHookLoadPackage中的handleLoadPackage方法主要用于加載應用程式包時執行使用者的操作。類似于一個統一排程的Dispatch例程,在Xposed源碼中,其對應的C++函數是xposedCallHandler。其函數原型如下:

public void handleHookedMethod(final LoadPackageParam lpparam)
           

其中參數lpparam是所加載的應用程式的基本資訊,包括packageName、processName、APPInfo等。

XposedHelpers類中findAndHookedMethod方法主要用于尋找需要進行hook的類及其相應的方法,并在原方法調用前或調用後運作自定義的替換函數。其函數原型如下:

findAndHookMethod(
String className,//需要進行hook的類名
ClassLoader classLoader,//類加載器,可以為空
String methodName,// 需要進行hook的方法名
Object... parameterTypesAndCallback//參數集,目标方法的參數類及回調
)
           

其中,回調分為如下兩種:

XC_MethodHook:在目标方法執行前/後運作相應的替換函數;

XC_MethodReplace:完全替換目标方法,執行使用者自定義的新方法。

在findAndHookedMethod方法的XC_MethodHook回調中,有beforeHookedMethod和afterHookedMethod兩種方法,其函數原型如下:

beforeHookedMethod(
MethodHookParam param
)
           

該方法在hook目标方法執行前調用,其中,參數param指的是目标方法的相關參數、回調、方法等資訊;

afterHookedMethod(
MethodHookParam param
)
           

該方法在hook目标方法執行後調用,其中,參數param指的是目标方法的相關參數、回調、方法等資訊。

Xposed運作多個子產品對同一個方法進行hook時,架構就會根據Xposed子產品的優先級來排序,在具有a.before、a.after、b.before、b.after的情況下,運作的先後順序如下:

XposedBridge類中hookAllMethods和log方法主要用于一次hook每個類的所有方法或夠造函數。其原型如下:

hookAllMethods(
Class<?> hookClass,//需要進行hook的類
String methodName,//需要進行hook的方法名
XC_MethodHook callback//回調函數
)