Hook构造函数

xiaoeryu Lv5

本章主要是配置一下Xposed开发环境,以及对构造函数进行一个简单的hook。梳理一下Xposed插件开发流程

Xposed开发环境配置

本次开发环境

设备:pixel XL

系统:Android 10

开发平台:Ubuntu 22.04

IDE:Android Studio 2022.3

开发语言:Java

手机环境配置:Magisk(26)和LSPosed(1.9.2)使用的最新版,安装教程在之前的章节里面写过了不再赘述

新建项目

手机环境配置好了之后,用Android Studio创建一个新的项目:先配置好Android Studio的代理

  • 项目名可以随便起个喜欢的

修改配置:

首先我们引入Xposed的库,这里我们需要在settings.gradle里修改一下

maven { url 'https://api.xposed.info/' }

之后,进入app目录下面的build.gradle引入xposed的依赖

compileOnly 'de.robv.android.xposed:api:82'

声明模块

        <!-- 是否为Xposed模块 -->
        <meta-data
            android:name="xposedmodule"
            android:value="true"/>
        <!-- 模块的简介(在框架中显示) -->
        <meta-data
            android:name="xposeddescription"
            android:value="我是Xposed模块test05" />
        <!-- 模块最低支持的Api版本 一般填54即可 -->
        <meta-data
            android:name="xposedminversion"
            android:value="54"/>

模块编写

创建一个入口类

public class MainHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        Log.i("MainHook", lpparam.packageName);
        XposedBridge.log("MainHook->app packagename" + lpparam.packageName);

    }
}

然后我们还需要定义一下入口类:

创建一个assets文件夹,并创建一个文件名叫xposed_init

  • 可以定义多个入口

测试一下

可以输入命令重启一下手机

adb reboot

在Android Studio的Logcat中可以查看到调用结果

Hook构造函数

我们先写一个简单的app

测试用例

主要内容就是几个构造函数:分别为带参数和不带参数的,然后再调用一下

public class Student {
    String name = null;
    String id = null;
    int age = 0;
    public Student(){
        name = "default";
        id = "default";
        age = 10;
    }
    public Student(String name){
        this.name = name;
        id = "default";
    }
    public Student(String name, String id){
        this.name = name;
        this.id = id;
    }
    public Student(String name, String id, int age){
        this.name = name;
        this.id = id;
        this.age = age;
    }
}
  • 将这个测试项目编译完成后先安装在手机上

接下来开始我们对构造函数的hook

Hook源码

hook我们需要用到findAndHookConstructor这个方法,看源码它有两种实现方式,一种需要传入class一种直接传入类名字符串就可以,下面试一下这两种方式。

无参构造函数

Class StudentClass = classLoader.loadClass("com.xiaoeryu.xposedhook01.Student");

// 使用XposedHelpers.findAndHookConstructor进行构造函数的hook
// StudentClass 是目标类的 Class 对象

XposedHelpers.findAndHookConstructor(StudentClass, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        super.beforeHookedMethod(param);
        // 在目标构造函数执行之前的逻辑
        XposedBridge.log("xiaoeryu->beforeHookedMethod");
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        // 在目标构造函数执行之后的逻辑
        XposedBridge.log("xiaoeryu->afterHookedMethod");
    }
});

有参的构造函数

Class StudentClass = classLoader.loadClass("com.xiaoeryu.xposedhook01.Student");

// 参数写为 参数类型.class
XposedHelpers.findAndHookConstructor(StudentClass, String.class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        super.beforeHookedMethod(param);
        // 获取参数
        Object[] args = param.args;
        String name = (String) args[0];
        XposedBridge.log("com.xiaoeryu.xposedhook01.Student(String)->beforeHookedMethod: " + name);
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        XposedBridge.log("com.xiaoeryu.xposedhook01.Student(String)->afterHookedMethod");
    }
});

有参构造函数的另一种调用方式:传入完整类名

// 也可以直接以字符串形式传入完整类名
XposedHelpers.findAndHookConstructor("com.xiaoeryu.xposedhook01.Student", loadPackageParam.classLoader, String.class, String.class, int.class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        super.beforeHookedMethod(param);
        Object[] args = param.args;
        String name = (String) args[0];
        // 改变参数的值
        args[1] = "2050";
        args[2] = 200;
        String id = (String) args[1];
        int age = (int) args[2];
        XposedBridge.log("com.xiaoeryu.xposedhook01.Student(String, String, int)->beforeHookedMethod: " + name + "--" + id + "--" + age);
    }

    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        // 经过测试构造函数的返回对象是使用thisObject获取,而不是使用getResult()获取,这是因为构造函数都是void类型
        Object thisObj = param.thisObject;
        Object returnObj = param.getResult();
        XposedBridge.log( thisObj + "---" + returnObj);
        XposedBridge.log("com.xiaoeryu.xposedhook01.Student(String, String, int)->afterHookedMethod");
    }
});

代码主要就上面这些,然后过一遍它的执行流程

  1. 将我们要测试的目标app先安装再设备上

  2. 然后将我们的xposed插件安装上,并且在LSPosed中勾选我们要hook的目标app

  3. 之后我们在勾选系统框架的时候会提示需要重启才能生效,我们点击重启即可或者自己手动重启也一样

  4. 然后我们就可以在Android Studio的Logcat界面看到我们插件的执行情况

本章的XposedHook都比较简单,主要是过一遍Xposed插件的编写流程,后面几章会涉及到如果是加壳的app或者动态下发的dex等等,在这些情况下我们应该怎么去写hook插件

  • 标题: Hook构造函数
  • 作者: xiaoeryu
  • 创建于 : 2023-12-02 17:26:26
  • 更新于 : 2023-12-03 10:18:20
  • 链接: https://github.com/xiaoeryu/2023/12/02/Hook构造函数/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论