🚀 LSPosed 进阶:掌握主动调用,让你为所欲为!

嗨,各位技术爱好者!

在日常的 LSPosed 模块开发中,我们最常做的就是 findAndHookMethod,在目标方法执行前后搞点“小动作”。但你有没有想过,如果我们不想等 App 自己去调用某个方法,而是想让我们的模块来主动发起调用,应该怎么做呢?

比如,在一个加密函数 encrypt(String text) 前后 Hook,我们只能截获 App 自身发起的加密请求。但如果我们想用这个加密函数来加密我们自己的任意字符串,该怎么办?

答案就是:主动调用

今天,我们就来揭秘 LSPosed 中进行主动调用的“神器”——XposedHelpers 工具类,让你彻底掌握这项指哪打哪的强大技能!

🎯 第一步:准备一个“靶场”App

为了直观地演示,我们先创建一个简单的 Android App作为我们的 Hook 目标。这个 App 里有一个 Person 类,它包含了我们想调用的各种方法。

Person.java

package com.example.hookdemo;

import android.util.Log;

public class Person {
    private static final String TAG = "XposedHook";

    // 构造函数
    public Person() {
        Log.d(TAG, "Person 的无参构造函数被调用");
    }

    // 1. 普通成员方法(非静态)
    public void print(String name, int age, String address) {
        Log.d(TAG, "--- 调用普通方法 ---");
        Log.d(TAG, "姓名: " + name + ", 年龄: " + age + ", 地址: " + address);
    }

    // 2. 静态方法
    public static void print(String name, int age) {
        Log.d(TAG, "--- 调用静态方法 ---");
        Log.d(TAG, "姓名: " + name + ", 年龄: " + age);
    }
    
    // 3. 内部类
    public class People {
        public People() {
            Log.d(TAG, "内部类 People 的构造函数被调用");
        }
        
        public void print(String name, int age, String address) {
            Log.d(TAG, "--- 调用内部类方法 ---");
            Log.d(TAG, "内部类姓名: " + name + ", 年龄: " + age + ", 地址: " + address);
        }
    }
}

这个类非常适合我们接下来的演练,它包含了普通方法、静态方法和内部类,涵盖了绝大多数场景。

🛠️ 第二步:LSPosed 模块实战演练

现在,让我们编写 LSPosed 模块代码,在 App 启动时,主动去调用 Person 类里的方法。

我们的核心武器就是 de.robv.android.xposed.XposedHelpers

1. 调用普通方法(非静态)

要调用一个非静态方法,需要分三步走:

  1. 找到这个类 (Class 对象)。
  2. 创建这个类的一个实例 (Object 对象)。
  3. 通过这个实例调用它的方法。
// 在你的 handleLoadPackage 方法中
// 1. 找到 Person 类的 Class 对象
Class<?> Person_clazz = XposedHelpers.findClass("com.example.hookdemo.Person", lpparam.classLoader);

// 2. new 一个 Person 对象实例
Object person_obj = XposedHelpers.newInstance(Person_clazz);

// 3. 调用它的 print 方法
// 参数:实例对象, 方法名, 参数1, 参数2, 参数3...
XposedHelpers.callMethod(person_obj, "print", "张三", 100, "火星");

代码解析

  • findClass(className, classLoader): 根据类名和类加载器,找到目标的 Class 对象。
  • newInstance(class, args...): 调用类的构造函数创建一个实例。这里我们调用的是无参构造。
  • callMethod(object, methodName, args...): 在指定的对象实例上,调用指定名称和参数的方法。
2. 调用静态方法

调用静态方法就简单多了,因为它不依赖于任何对象实例,可以直接通过 Class 对象调用。

// 直接通过 Class 对象调用静态方法
// 参数:Class对象, 方法名, 参数1, 参数2...
XposedHelpers.callStaticMethod(Person_clazz, "print", "李四", 99);

代码解析

  • callStaticMethod(class, methodName, args...): 直接调用一个类的静态方法。注意,第一个参数是 Class 对象,而不是实例对象。
3. 挑战内部类(非静态)

调用内部类的方法稍微复杂一点,因为非静态内部类的实例化依赖于一个外部类的实例

步骤如下:

  1. 获取外部类的实例(我们上面已经创建了 person_obj)。
  2. 通过类加载器找到内部类的 Class 对象。注意内部类的表示方式是 外部类$内部类
  3. 实例化内部类,此时需要把外部类的实例作为构造函数的第一个参数传入。
  4. 调用内部类实例的方法。
// 1. 找到内部类的 Class 对象
// 注意 $ 符号的用法
Class<?> PeopleClass = XposedHelpers.findClass("com.example.hookdemo.Person$People", lpparam.classLoader);

// 2. 实例化内部类
// 第一个参数是内部类的 Class 对象
// 第二个参数是它所依赖的外部类实例!
Object people_obj = XposedHelpers.newInstance(PeopleClass, person_obj);

// 3. 调用内部类的方法
XposedHelpers.callMethod(people_obj, "print", "张三(内部)", 100, "火星");

💡 关键点
实例化非静态内部类时,XposedHelpers.newInstance 的第二个参数必须是外部类的实例。这是 Java 语法的规定,XposedHelpers 只是帮我们简化了这个反射过程。

📜 完整模块代码示例

下面是整个 LSPosed 模块入口的完整代码,你可以直接复制使用:

package com.example.myxposedmodule;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HookEntry implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        // 只对我们的目标 App 生效
        if (!lpparam.packageName.equals("com.example.hookdemo")) {
            return;
        }

        XposedBridge.log("模块已加载到目标 App: " + lpparam.packageName);

        try {
            // 1. 找到 Person 类的 Class 对象
            Class<?> Person_clazz = XposedHelpers.findClass("com.example.hookdemo.Person", lpparam.classLoader);
            XposedBridge.log("成功找到 Person Class: " + Person_clazz);

            // --- 主动调用非静态方法 ---
            XposedBridge.log(">>> 准备调用非静态方法...");
            Object person_obj = XposedHelpers.newInstance(Person_clazz);
            XposedHelpers.callMethod(person_obj, "print", "张三", 100, "火星");
            XposedBridge.log("<<< 非静态方法调用完毕!");

            // --- 主动调用静态方法 ---
            XposedBridge.log(">>> 准备调用静态方法...");
            XposedHelpers.callStaticMethod(Person_clazz, "print", "李四", 99);
            XposedBridge.log("<<< 静态方法调用完毕!");

            // --- 主动调用内部类方法 ---
            XposedBridge.log(">>> 准备调用内部类方法...");
            Class<?> PeopleClass = XposedHelpers.findClass("com.example.hookdemo.Person$People", lpparam.classLoader);
            // 实例化内部类时,传入外部类实例 person_obj
            Object people_obj = XposedHelpers.newInstance(PeopleClass, person_obj);
            XposedHelpers.callMethod(people_obj, "print", "张三(内部)", 100, "火星");
            XposedBridge.log("<<< 内部类方法调用完毕!");

        } catch (Throwable t) {
            XposedBridge.log("发生错误: " + t);
        }
    }
}

当你激活此模块并启动“靶场”App后,查看 Logcat 日志(筛选 Xposed),你将看到所有主动调用都成功执行了!

总结

今天我们学习了如何使用 XposedHelpers 来主动调用目标 App 的方法,总结一下关键函数:

  • XposedHelpers.findClass(): 寻找类。
  • XposedHelpers.newInstance(): 创建对象实例。
  • XposedHelpers.callMethod(): 调用普通(非静态)方法。
  • XposedHelpers.callStaticMethod(): 调用静态方法。

掌握了主动调用,你的 LSPosed 模块就不再只是一个被动的“观察者”,而是一个可以主动出击的“玩家”。无论是模拟用户操作、测试加密函数,还是触发隐藏功能,都变得轻而易举。

希望这篇文章能帮你打开一扇新的大门,快去试试吧!


Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐