學習筆記:Android Xposed 框架入門

學習筆記:Android Xposed 框架入門

目錄

  • Xposed 框架簡介
  • Xposed 框架的具體使用
  • 原理分析

Xposed 框架簡介

Xposed是一款優(yōu)秀的android java層 hook 框架。它允許你在不修改apk源碼的情況下,通過編寫自己的模塊來改變apk的行為。它的優(yōu)點是采用了插件機制,模塊能夠適用不同版本的框架和rom。模塊改變apk行為的操作發(fā)生在內(nèi)存中,對源apk不進行任何修改。你只需要安裝編寫的模塊并重啟相應的設備即可。

xposed 主要由三個項目來組成的:

  1. Xposed:Xposed的C++ 部分,主要是用來替換 /system/bin/app_process,并為XposedBridge 提供 JNI方法。
  2. XposedBridge:Xposed 提供的jar文件,app_process 啟動過程中會加載該jar包,其他的 Modules 的開發(fā)都是基于 該jar包。
  3. XposedInstaller:Xposed的安裝包,提供對基于Xposed框架的Modules的管理。

xposed 目前已逐步支持 ART虛擬機,兼容 android 5.0 以上版本。


Xposed 框架的具體使用

具體的安裝教程需要自行百度,的確是安裝環(huán)境比較耗費時間,不過都是躲不掉的?。?!這里用一個繞過密碼登錄的例子進行說明。Android studio的配置代碼這里就不貼了,需要的話可以去百度一下,很多資源。以下是安裝使用教程:Xposed框架安裝使用教程

1. 創(chuàng)建 Android 工程

一個 Xposed 模塊本質(zhì)上是一個正常的 apk,所以你只需要去創(chuàng)建一個空的工程,不需要添加任何的 Activity。

2. 添加 jar 包

下載地址:jar包
在添加依賴項的時候注意使用 provided 不要使用 compile! 如下圖紅線部分所示:

然后還需要在 AndroidManifest.xml 文件配置,在Application節(jié)點下添加以下信息:

3. 在 assets 文件夾下寫入入口信息

在 Android 工程的 main 文件夾下創(chuàng)建 assets 文件夾(沒有的話)。XposedBridge 從assets 目錄中的xposed_init 文件中獲取入口點。xposed_init文件中每行配置一個進入點,使用完全限定名。在該例子中,進行如下配置。

4. 模塊實現(xiàn)
  1. 在模塊中創(chuàng)建一個類,根據(jù)自己的需求實現(xiàn)以下的接口:

    • 安卓系統(tǒng)啟動的時候(使用 IXposedHookZygoteInit 接口)
    • 一個新的app被加載的時候(使用 IXposedHookLoadPackage 接口)
    • 一個資源被初始化的時候( 使用 IXposedHookInitPackageResources 接口)
  2. 指定要 hook 的包名(這里是 com.markable.androidsecurity ),也就是你想要 hook 的應用包名,我這里就是本項目。

  3. 判斷當前加載的包是否是指定的包(在接口方法中判斷)

  4. 指定要 hook 的方法名??

  5. 實現(xiàn)beforeHookedMethod方法和afterHookedMethod方法( hook 的具體功能)??

以下是繞過登錄的完整代碼。

package com.markable.androidsecurity.module;

import android.widget.TextView;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

/**
 * Created by Markable on 2018/7/11.
 * Github: https://github.com/ddz-mark
 * Info:
 */

public class SkipLoginCheck implements IXposedHookLoadPackage {

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam param) throws Throwable {
        // 判斷是否是應用的包名
        if (param.packageName.equals("com.markable.androidsecurity")) {
            findAndHookMethod("com.markable.androidsecurity.LoginActivity", param.classLoader, "login", String.class, String.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    XposedBridge.log("開始劫持了~");
                    XposedBridge.log("參數(shù)1 = " + param.args[0]);
                    XposedBridge.log("參數(shù)2 = " + param.args[1]);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    XposedBridge.log("劫持前返回的result: " + param.getResult());
                    param.setResult(true);// 繞過登錄
                    XposedBridge.log("劫持后返回的result: " + param.getResult());
                    XposedBridge.log("hook finish");
                }
            });
        }

    }

}

以上是繞過登錄的功能代碼,核心代碼在于 param.setResult(true),可以讓登錄直接通過(這里是簡單的登錄模擬功能)。


5. 原理分析

在 Android 系統(tǒng)中,應用程序進程以及系統(tǒng)服務進程 SystemServer 都是由 Zygote 進程孵化出來的,而 Zygote 進程是由 Init 進程啟動的, Zygote 進程在啟動時會創(chuàng)建一個 Dalvik 虛擬機實例,每當它孵化一個新的應用程序進程時,都會將這個 Dalvik 虛擬機實例復制到新的應用程序進程里面去,從而使得每一個應用程序進程都有一個獨立的 Dalvik 虛擬機實例,這也是 Xposed 選擇替換 app_process 的原因。

Zygote進程在啟動的過程中,除了會創(chuàng)建一個Dalvik虛擬機實例之外,還會將Java運行時庫加載到進程中來,以及注冊一些Android核心類的JNI方法來前面創(chuàng)建的Dalvik虛擬機實例中去。注意,一個應用程序進程被Zygote進程孵化出來的時候,不僅會獲得Zygote進程中的Dalvik虛擬機實例拷貝,還會與Zygote一起共享Java運行時庫。這也就是可以將XposedBridge這個jar包加載到每一個Android應用程序中的原因。XposedBridge有一個私有的Native(JNI)方法hookMethodNative,這個方法也在app_process中使用。這個函數(shù)提供一個方法對象利用Java的Reflection機制來對內(nèi)置方法覆寫。具體的實現(xiàn)可以看下文的Xposed源代碼分析。

  • Hook/Replace 簡析

Xposed 框架中真正起作用的是對方法的hook。在Repackage技術(shù)中,如果要對APK做修改,則需要修改Smali代碼中的指令。而另一種動態(tài)修改指令的技術(shù)需要在程序運行時基于匹配搜索來替換smali代碼,但因為方法聲明的多樣性與復雜性,這種方法也比較復雜。
在Android系統(tǒng)啟動的時候,zygote進程加載XposedBridge將所有需要替換的Method通過JNI方法hookMethodNative指向Native方法xposedCallHandler,xposedCallHandler在轉(zhuǎn)入handleHookedMethod這個Java方法執(zhí)行用戶規(guī)定的Hook Func。
XposedBridge這個jar包含有一個私有的本地方法:hookMethodNative,該方法在附加的app_process程序中也得到了實現(xiàn)。它將一個方法對象作為輸入?yún)?shù)(你可以使用Java的反射機制來獲取這個方法)并且改變Dalvik虛擬機中對于該方法的定義。它將該方法的類型改變?yōu)閚ative并且將這個方法的實現(xiàn)鏈接到它的本地的通用類的方法。換言之,當調(diào)用那個被hook的方法時候,通用的類方法會被調(diào)用而不會對調(diào)用者有任何的影響。在hookMethodNative的實現(xiàn)中,會調(diào)用XposedBridge中的handleHookedMethod這個方法來傳遞參數(shù)。handleHookedMethod這個方法類似于一個統(tǒng)一調(diào)度的Dispatch例程,其對應的底層的C++函數(shù)是xposedCallHandler。而handleHookedMethod實現(xiàn)里面會根據(jù)一個全局結(jié)構(gòu)hookedMethodCallbacks來選擇相應的hook函數(shù),并調(diào)用他們的before, after函數(shù)。
當多模塊同時Hook一個方法的時候,Xposed會自動根據(jù)Module的優(yōu)先級來排序,調(diào)用順序如下:
A.before -> B.before -> original method -> B.after -> A.after

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

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

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