百趣云 百趣云的博客

Xposed 模块开发入门:从 hook Application 到拿到 Context

为什么第一个 hook 点永远是 Application.onCreate

写 Xposed 模块逆向 App,90% 的功能需要 Context(拿包管理器、访问 SharedPreferences、弹 Toast 调试)。而模块加载时(handleLoadPackage)是没有 Context 的——进程刚启动,Application 都还没创建。所以所有 Xposed 模块的第一个标准动作:hook Application.onCreate,在回调里拿 Context,再干正事

模块骨架

public class MainHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(final LoadPackageParam lpparam) {
        if (!lpparam.packageName.equals("com.target.app")) return;
        // 只 hook 主进程,多进程 App 会触发多次
        if (!lpparam.processName.equals(lpparam.packageName)) return;

        XposedHelpers.findAndHookMethod(Application.class, "onCreate",
            new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) {
                    Context ctx = (Context) param.thisObject;
                    XposedBridge.log("拿到 Context: " + ctx.getPackageName());
                    doWork(ctx, lpparam.classLoader);  // 正事从这里开始
                }
            });
    }
}

精髓一:ClassLoader 是模块开发的第一道坎

lpparam.classLoader目标 App 的类加载器,hook 目标 App 的类必须用它:

// 错误:XposedHelpers.findClass 默认用模块自己的 ClassLoader,找不到目标 App 的类
// 正确:
Class<?> targetClass = XposedHelpers.findClass("com.target.app.SignUtils", lpparam.classLoader);

加固 App 还有第二层坑:壳的 onCreate 执行时,真正的 dex 还没加载,lpparam.classLoader 里找不到业务类。解法是延迟 hook——hook 壳的 attachBaseContext 之后、或 hook ClassLoader.loadClass 等目标类出现时再下手:

XposedHelpers.findAndHookMethod(ClassLoader.class, "loadClass", String.class,
    new XC_MethodHook() {
        @Override
        protected void afterHookedMethod(MethodHookParam param) {
            String name = (String) param.args[0];
            if (name.equals("com.target.app.SignUtils")) {
                Class<?> cls = (Class<?>) param.getResult();
                hookSign(cls);   // 类加载完成的瞬间 hook 它
            }
        }
    });

精髓二:hook 方法的三种姿势与选择

// 1. 无参/已知签名:findAndHookMethod 最简洁
XposedHelpers.findAndHookMethod("com.target.app.SignUtils", lpparam.classLoader,
    "getSign", String.class, new XC_MethodHook() { ... });

// 2. 重载爆炸的方法:遍历所有重载
Class<?> cls = XposedHelpers.findClass("com.target.app.Api", lpparam.classLoader);
XposedBridge.hookAllMethods(cls, "request", new XC_MethodHook() { ... });

// 3. 构造函数也能 hook:拿对象初始化状态
XposedBridge.hookAllConstructors(cls, new XC_MethodHook() { ... });

拿参数、改参数、改返回值:

protected void beforeHookedMethod(MethodHookParam param) {
    String input = (String) param.args[0];       // 拿参数
    param.args[0] = "篡改后的值";                  // 改参数
    // param.setResult("伪造返回");               // 直接短路,原方法不执行
}
protected void afterHookedMethod(MethodHookParam param) {
    Object ret = param.getResult();              // 拿返回值
    param.setResult(ret + "-modified");          // 改返回值
}

精髓三:调试与排错

  1. 日志双写XposedBridge.log() 进 Xposed 日志,android.util.Log 进 logcat。模块崩了先看 Xposed Installer 的日志页,堆栈完整。
  2. 作用域收窄handleLoadPackage 里先判包名再判进程,否则模块会在系统所有进程里加载,又慢又容易崩系统 App。
  3. 资源冲突:模块里引用的第三方库如果和目标 App 版本冲突,会 NoSuchMethodError。用 Gradle 的 compileOnly 或 shadow 重定位包名解决。
  4. EdXposed/LSPosed 的作用域机制:LSPosed 里模块只对勾选的作用域生效,调试时把"系统框架"也勾上能避免一些诡异问题。

总结

  1. 一切从 hook Application.onCreate 拿 Context 开始
  2. 目标类必须用 lpparam.classLoader 加载,加固 App 要延迟 hook
  3. hookAllMethods 应对混淆重载,before/after 分工明确
  4. 日志双写 + 作用域收窄,是稳定性的基本功

交流微信:run1255

By 百趣云 阅读量:2 On