xposed 02 - 模块编写与构造函数Hook

本文讨论一下xposed模块编写的步骤,与如何hook构造函数,以及一些需要注意的地方。

Xposed模块编写

跟把大象放冰箱分3步一样,编写xposed模块只需要4步。

第一步

拷贝 XposedBridgeApi.jar 到模块工程的 libs 目录下,放一个 jar 下载链接,其实也可以去作者仓库下载源码自己编译一个jar

github.com/bywhat/Xpos...
github.com/rovo89/Xpos...

第二步

修改 build.gradle 目录,将 libs 下的 jar 添加依赖

less 复制代码
compileOnly fileTree(dir: 'libs', includes: ['*.jar'])

修改 AndroidManifest.xml,在 application 的标签下添加如下 mate 信息:

ini 复制代码
<application
    android:allowBackup="true"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.EdxposedTest"
    tools:targetApi="31" >

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

    <meta-data
        android:name="xposeddescription"
        android:value="edxposed hook learning" />

    <meta-data
        android:name="xposedminversion"
        android:value="54" />

</application>

xposedmodule 表示该apk是不是一个 xposed 模块,肯定要填 true。

xposeddescription 这个描述信息会展示到模块列表的模块信息里面。

xposedminversion 最小的版本,与 libs 下使用的版本一致即可。

第三步

新建一个 hook 类(入口类),入口类必须是 public 的,否则会出现无法访问错误,入口类需要实现 IXposedHookLoadPackage 接口:

java 复制代码
public class Xposed01 implements IXposedHookLoadPackage {

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        ...
    }

}

第四步

建立 assets 目录,在 assets 目录下新建文件 xposed_init 文件,在里面声明你在第3步写的入口类。可以声明多个,优先级是按照编写顺序,也就是哪个先声明,就先生效。

复制代码
com.example.edxposedtest.Xposed01

Hook 构造函数

以下面这个例子为演示,演示代码已传递到 p22。

kotlin 复制代码
package com.example.hooktarge

class HookTarget1 constructor(private val str: String, val id: Long ) {

    constructor() :this("", 0)

    override fun toString(): String {
        return "HookTarget1(str='$str', id=$id)"
    }

}

这里我们写了两个构造函数。我们针对这2个构造函数进行测试。分为两方面的测试,一个是无参数的构造函数,一个是有参数的构造函数。

hook构造参数有两个 api:

typescript 复制代码
public static XC_MethodHook.Unhook findAndHookConstructor(Class<?> clazz, Object... parameterTypesAndCallback) {
    if (parameterTypesAndCallback.length != 0 && parameterTypesAndCallback[parameterTypesAndCallback.length - 1] instanceof XC_MethodHook) {
        XC_MethodHook callback = (XC_MethodHook)parameterTypesAndCallback[parameterTypesAndCallback.length - 1];
        Constructor<?> m = findConstructorExact(clazz, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));
        return XposedBridge.hookMethod(m, callback);
    } else {
        throw new IllegalArgumentException("no callback defined");
    }
}

public static XC_MethodHook.Unhook findAndHookConstructor(String className, ClassLoader classLoader, Object... parameterTypesAndCallback) {
    return findAndHookConstructor(findClass(className, classLoader), parameterTypesAndCallback);
}

可以看到,实际上第二个 api 也是使用了第一个 api。

所以当我们可以直接获取到 hook 类的 class 时,那么就使用第一个 api 更简单,否则使用第二个 api。对于一些加壳的 apk 或者动态加载的 类,我们需要传递特定的 classloader 才能正确的找到类,此时只能使用第二个 api。

hook无参构造函数

java 复制代码
XposedHelpers.findAndHookConstructor("com.example.hooktarge.HookTarget1", loadPackageParam.classLoader, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        super.beforeHookedMethod(param);
        Log.e("Xposed01", "no params beforeHookedMethod");
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        Log.e("Xposed01", "no params afterHookedMethod");
    }
});

由于是 hook 构造方法,所以最后一个参数,我们使用 XC_MethodHook。

它有两个接口方法:

  • beforeHookedMethod 在方法调用之前执行
  • afterHookedMethod 在方法调用之后执行

hook 有参构造函数

其实代码也是与上面差不过的,我们可以先看一下 MethodHookParam 这个类的字段:

typescript 复制代码
// 方法
public Member method;
// 方法所属的对象
public Object thisObject;
// 方法的参数
public Object[] args;
// 方法返回值
private Object result = null;

有了这些字段,我们就可以修改构造函数的参数传递。

同时,parameterTypesAndCallback 这个参数的名字也暗示了hook有参数的方法,需要传递参数类型:

java 复制代码
XposedHelpers.findAndHookConstructor("com.example.hooktarge.HookTarget1", loadPackageParam.classLoader, String.class, long.class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        super.beforeHookedMethod(param);
        Log.e("Xposed01", "params beforeHookedMethod");
        param.args[0] = "abd";
        param.args[1] = 42;
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        Log.e("Xposed01", "params afterHookedMethod");
        Log.e("Xposed01", "thisObject = " + param.thisObject);
        Log.e("Xposed01", "getResult = " + param.getResult());
    }
});

在 app 里面调用一下这些构造函数:

scss 复制代码
HookTarget1()
HookTarget1("a5right", 1)

安装 app 与 模块,我们运行一下看看效果:

csharp 复制代码
E  no params beforeHookedMethod
E  params beforeHookedMethod
E  params afterHookedMethod
E  thisObject = HookTarget1(str='abd', id=42)
E  getResult = null
E  no params afterHookedMethod
E  params beforeHookedMethod
E  params afterHookedMethod
E  thisObject = HookTarget1(str='abd', id=42)
E  getResult = null

可以看到,无参构造函数触发了有参构造函数的调用。

我们在hook代码中修改的参数也生效了。

同时还需要注意到,getResult 返回了空,说明了构造函数是没有返回值的。这个应该好理解,之前在写JVM的时候,就学习过了,new 分两步,第一步分配空间,第二步初始化这个对象:

ini 复制代码
MyObject obj = allocateInstance(MyObjcet.class);
obj.<init>;

所以,如果有需要,请在构造函数的 hook 中使用 thisObject,而不是 getResult。

重新修改代码后,需要在 edposed manager 的module里面的开关,重新关闭再打开后生效,如果未生效,尝试重启。

相关推荐
代码搬运媛7 小时前
Jest 测试框架详解与实现指南
前端
counterxing7 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq8 小时前
windows下nginx的安装
linux·服务器·前端
之歆8 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜8 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai108088 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
kyriewen10 小时前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm10 小时前
元框架的工作原理详解
前端·前端框架
canonical_entropy11 小时前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程
zhangxingchao11 小时前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端