由于Xposed 注入的时机是很早的,而壳程序总是又较 App 应用程序最先执行的,所以 Xposed hook 默认使用的是壳的 ClassLoader 而不是应用本身的 ClassLoader,所以是不可能 hook 到应用内部的代码的。

方法1

对于每一个app,android 在加载 dex 文件后会创建一个 Application 类,然后会调用 attach 方法,attach 方法的参数就是上下文 context。attach 方法是 final 方法,不会因为被覆盖而 hook 不到,拿到这个 context 就可以获取对应的 classloader,然后可以顺利 hook 到需要的类。

执行代码后,可以看到首先进入了壳的 context ,然后获取到了壳的 ClassLoader。
等正式进入 App 后,android 会重新加载 App 本身 dex 文件,会创建一个 Application 类,然后会调用 attach 方法,attach 方法的参数就是上下文 context。通过这个 context 获取到的就是 App 本身的 ClassLoader 了。

在通过这个 ClassLoader 找到要 hook 的类,执行后的结果就是成功 hook 到类中的方法。

package com.bmstd.xposed1;

import android.app.Application;
import android.content.Context;

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

public class HookTest implements IXposedHookLoadPackage {

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.packageName.equals("com.cz.babySister")) {
            // 解决多dex文件hook不到问题
            XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            // 获取上下文
                            Context context = (Context) param.args[0];
                            XposedBridge.log("context => " + context);
                            // 类加载器
                            ClassLoader classLoader = context.getClassLoader();
                            XposedBridge.log("classLoader => " + classLoader);

                            // 替换类加载器进行 hook 对应的方法
                            Class<?> aClass = XposedHelpers.findClass("com.cz.babySister.activity.MainActivity", classLoader);
                            XposedBridge.hookAllMethods(aClass, "onCreate", new XC_MethodHook() {
                                @Override
                                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                    super.beforeHookedMethod(param);
                                    XposedBridge.log("MainActivity onCreate called");
                                }
                            });
                        }
                    });
        }
    }
}

方法2:

从动态加载dex hook不到的问题角度去解决 Xposed hook 不到加固的应用
从上面的理论分析得知,重点问题还是在 ClassLoader 的切换。

所以直接使用 java.lang.ClassLoader.loadClass(java.lang.String) 这个方法。

这个方法的功能是:加载具有指定二进制名称的类,成功,然后一个类的对象。

执行代码后,首先找到了壳的类。
然后陆续找到了所有类,并成功进行预想中的 hook。

package com.bmstd.xposed1;

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

public class HookTest implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.packageName.equals("com.cz.babySister")) {
            XposedBridge.log("has hooked!");
            // 解决动态加载dex文件hook不到问题
            XposedHelpers.findAndHookMethod(ClassLoader.class,
                    "loadClass",
                    String.class,
                    new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            // 打印当前已经加载的类
                            XposedBridge.log("clazz => " + param.getResult());
                            Class<?> clazz = (Class<?>) param.getResult();
                            if (clazz != null && clazz.getName().equals("com.cz.babySister.activity.MainActivity")) {
                                XposedBridge.hookAllMethods(clazz, "onCreate", new XC_MethodHook() {
                                    @Override
                                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                        super.beforeHookedMethod(param);
                                        XposedBridge.log("MainActivity onCreate called");
                                    }
                                });
                            }
                        }
                    });
        }
    }
}

方法3(老 适用Zygote):

从应用加载角度解决 Xposed hook 不到加固的应用
App 是通过 Zygote 进程孵化的,通过 ActivityThread.main() 进入 App 。

performLaunchActivity() 函数用于响应 Activity 的操作。

并且 ActivityThread 类中还存在 Application 类型的 mInitialApplication。
mInitialApplication 可以获得当前的 ClassLoader。

package com.bmstd.xposed1;

import android.app.Application;

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

public class HookTest implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.packageName.equals("com.cz.babySister")) {
            Class ActivityThread = XposedHelpers.findClass("android.app.ActivityThread", loadPackageParam.classLoader);
            XposedBridge.hookAllMethods(ActivityThread, "performLaunchActivity", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Application mInitialApplication = (Application) XposedHelpers.getObjectField(param.thisObject, "mInitialApplication");
                    ClassLoader finalClassloader = mInitialApplication.getClassLoader();
                    XposedBridge.log("found classload is => " + finalClassloader.toString());
                    Class<?> MainActivity = XposedHelpers.findClass("com.cz.babySister.activity.MainActivity", finalClassloader);
                    XposedBridge.hookAllMethods(MainActivity, "onCreate", new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            XposedBridge.log("MainActivity onCreate called");
                        }
                    });
                }
            });
        }
    }
}

原文链接