Android逆向(前7章打包下載)|Xposed Hook(上)
聲明:所有實驗含部分虛構,純屬技術練習,未對真實環境造成任何影響。也請勿將相關技術用于非法操作,否則責任自負。
0x01 Hook修改變量
在編寫hook類的時候會去實現一個IXposedHookLoadPackage接口(加載應用程序,即“ Android軟件包”時獲得通知), 重寫了handleLoadPackage方法(加載應用程序時將調用此方法),該方法有一個參數lpparam(有關該應用程序的信息), 這個方法向被實現的模塊提供更多關于運行環境上下文的信息。首先我們實驗的app是一款編寫好的XposedDemo,將其安裝到模擬器上,打開運行后沒有任何效果,如圖所示:

使用jadx-gui反編譯工具查看其代碼,注意在一個Activity在啟動的時候,都會在onCreat()方法中執行setContentView(R.layout.activity_main)這行代碼,來將指定的資源xml文件加載到對應的activity中。

然后定位到res/layout/activity_main.xml,可以發現當我們點擊button的時候會觸發myTest方法,回到MainActivity,跟進myTest()的Demo類。



經過分析test()方法可以發現,當我們點擊按鈕時會在日志中輸出很多對應的日志信息,其中包括靜態變量staticInt = 100,注意靜態全局變量hook的時候調用的是使用的XposedHelpers.setStaticIntField(),若是全局普通變量用XposedHelpers.setIntField()。


我們再次運行app點擊按鈕,不過此次打開我們的ddms查看日志輸出。

然后編寫hook代碼如下:
package com.xposed; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; import android.util.Log; public class Hook implements IXposedHookLoadPackage { public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable { Log.d("feichen", "hook..."); //日志輸出方式一 XposedBridge.log("Loaded app: " + lpparam.packageName); //日志輸出方式二 if (lpparam.packageName.equals("com.feichen.xposeddemo")){ final Class clazz = XposedHelpers.findClass("com.feichen.xposeddemo.Demo",lpparam.classLoader); XposedHelpers.setStaticIntField(clazz,"staticInt",520); } } } |
將寫好的xposed編譯安裝到xposed后,勾選上寫好的xposed模塊,并重啟手機,然后運行app,打開ddms,點擊button按鈕,查看ddms中的staticInt初始化值已經被我們hook修改為520,如圖:

然后hook字符串變量的話使用XposedHelpers.setStaticObjectField(clazz,"Tag","Lvmeng");這一條語句,具體的效果這里不再演示,有興趣的小伙伴下去可以自己嘗試。
0x02 Hook普通方法
Hook普通方法使用的是XposedHelpers下的findAndHookMethod(類的字節碼,方法名,回調函數)方法(用于Hook當前類下的所有方法),它有一個重載函數接收四個參數,
findAndHookMethod(類名全路徑,類加載器,方法名,回調函數),其中回調函數除了使用
XC_MethodHook()之外,還有XC_MethodReplacement()。對于有參數的函數需要帶上參數的字節碼。在0x03的地方就是四個參數的findAndHookMethod。
因此,Hook普通方法的代碼如下:
XposedHelpers.findAndHookMethod(clazz, "test", new XC_MethodHook(){ public void beforeHookedMethod(MethodHookParam param){ Log.d("Lvmeng","Lvmeng===============before"); } public void afterHookedMethod(MethodHookParam param){ Log.d("Lvmeng","Lvmeng=============after"); } }); |
其中beforeHookedMethod 會在調用原方法前執行,如果使用setResult則跳過原方法,并返回setResult參數中的值。
afterHookedMethod 會在調用原方法后執行,setResult可改變返回值。
replaceHookedMethod 會完全替換原方法,即原方法不執行,且返回值可以直接return,setResult不生效。
然后將寫好的xposed編譯安裝到xposed后,勾選上寫好的xposed模塊,并重啟手機,然后運行app,打開ddms,點擊button按鈕,查看ddms中日志情況如下,可以發現test()函數已經被成功hook,并且添加上兩條日志信息

0x03 Hook獲取參數與返回值
Hook獲取參數是方法中要傳入的參數,我們也是可以在beforeHookedMethod和afterHookedMethod方法中獲取我們的參數值,其hook代碼如下:
XposedHelpers.findAndHookMethod(clazz, "publicFunc",String.class, new XC_MethodHook(){ public void beforeHookedMethod(MethodHookParam param){ Log.d("Lvmeng","Lvmeng===============before"); Log.d("before-獲取參數", ""+param.args[0]); } public void afterHookedMethod(MethodHookParam param){ Log.d("Lvmeng","Lvmeng=============after"); Log.d("after-獲取參數", ""+param.args[0]); } }); |
其中,我們hook的方法是publicFunc,查看代碼可以發現該方法是接收參數的,如圖所示:

然后安裝運行后的日志信息如下:

Hook獲取返回值一般都是在afterHookedMethod方法中,Hook的代碼如下:
public void afterHookedMethod(MethodHookParam param){
Log.d("Lvmeng", ""+param.getResult());
}
在這里不再進行演示獲取返回值,有興趣的小伙伴可以下去自行測試。
0x04 Hook構造函數
Hook構造函數可分為有參構造函數前、無參構造函數前、有參構造函數后和無參構造函數后。這里Hook構造函數使用的是XposedHelpers下的findAndHookConstructor,詳細代碼如下:
XposedHelpers.findAndHookConstructor(clazz, new XC_MethodHook() { public void beforeHookedMethod(MethodHookParam param) throws Throwable { Log.d("===================", "這是無參構造函數前"); } public void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d("===================", "這是無參構造函數后"); XposedHelpers.setIntField(param.thisObject, "publicInt", 20000000); } }); XposedHelpers.findAndHookConstructor(clazz, String.class, new XC_MethodHook() { public void beforeHookedMethod(MethodHookParam param) throws Throwable { Log.d("===================", "這是有參構造函數前"); param.args[0] = "= - ="; } public void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d("===================", "這是有參構造函數后"); } }); |
然后安裝運行后的Hook日志如下:
