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里面的开关,重新关闭再打开后生效,如果未生效,尝试重启。

相关推荐
yzzzzzzzzzzzzzzzzz16 分钟前
初识javascript
前端·javascript
excel1 小时前
硬核 DOM2/DOM3 全解析:从命名空间到 Range,前端工程师必须掌握的底层知识
前端
专注API从业者8 小时前
Python + 淘宝 API 开发:自动化采集商品数据的完整流程
大数据·运维·前端·数据挖掘·自动化
烛阴9 小时前
TypeScript高手密技:解密类型断言、非空断言与 `const` 断言
前端·javascript·typescript
样子201810 小时前
Uniapp 之renderjs解决swiper+多个video卡顿问题
前端·javascript·css·uni-app·html
Nicholas6810 小时前
flutterAppBar之SystemUiOverlayStyle源码解析(一)
前端
黑客飓风10 小时前
JavaScript 性能优化实战大纲
前端·javascript·性能优化
emojiwoo12 小时前
【前端基础知识系列六】React 项目基本框架及常见文件夹作用总结(图文版)
前端·react.js·前端框架
张人玉12 小时前
XML 序列化与操作详解笔记
xml·前端·笔记
杨荧12 小时前
基于Python的宠物服务管理系统 Python+Django+Vue.js
大数据·前端·vue.js·爬虫·python·信息可视化