xposed 04 - 方法调用与加壳app处理

本文主要讨论如何在 xposed 模块中调用app中的方法,以及如何 hook 加壳的 app。

调用app中的方法

主要依靠 xposed 提供的几个 api,使用起来类似反射,不过比反射要简单的多。

静态方法

public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Object... args)

public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Class<?>[] parameterTypes, java.lang.Object... args)

需要的参数:

  • 类名

  • 方法名

  • 方法参数类型,是数组,比如有两个参数,形式应为:java.lang.Class<?>[] parameterTypes = {String.class, int.class}; ,也可以不传,xposed 会自动匹配参数类型。

  • 方法参数值

实例方法

public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Object... args)

public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Class<?>[] parameterTypes, java.lang.Object... args)

参数与调用静态方法就第一个参数不一样,显然实例方法需要对象,静态方法需要类对象。

构造方法

public static java.lang.Object newInstance(java.lang.Class<?> clazz, java.lang.Object... args)

public static java.lang.Object newInstance(java.lang.Class<?> clazz, java.lang.Class<?>[] parameterTypes, java.lang.Object... args)

需要的参数:

  • 类名

  • 方法参数类型,是数组,比如有两个参数,形式应为:java.lang.Class<?>[] parameterTypes = {String.class, int.class}; ,也可以不传,xposed 会自动匹配参数类型。

  • 方法参数值

加壳app的hook

想要hook加壳app中的方法,需要先知道两个基础知识:

  • 加壳原理

  • 脱壳

脱壳现在有很多的开源项目与脚本,fart,dexdump 都可以完成,只不过可能有些app做了 frida 特征识别,导致脱不下来,这个后面会说到。

加壳的原理其实也不难,简单来说就是,开发者编写的app被藏起来了,展示给我们看的只是包着app的一个壳,所以我们无法看到里面的app内容。但是一个重要的点是,app始终是要运行的,既然要运行,那么壳就会将它包着的app内容给拿出来,所以只要抓住这个点就能很好的理解脱壳。

至于加壳,就是相当于先将 app 给加密,然后在某个时机再解密出来,让其运行。具体可以看下面这些文章:

https://bbs.kanxue.com/thread-254555.htm

https://bbs.kanxue.com/thread-252630.htm

https://bbs.kanxue.com/thread-254028.htm

实战

看一个例子,材料已上传到 p23 (lebo.apk)。

使用jadx打开,发现里面没有 Activity 等类:

 

看AndroidManifest.xml里面,有很多类都找不到:

 

这说明该 apk 被加壳了。

那么,如果我们想hook com.zw.lebo.SplashView 这个类,在它的 onCreate 方法里面弹一个 toast,该如何做呢?

我们先尝试按照之前的方法,直接使用 findAndHookMethod 看看效果:

if (loadPackageParam.packageName.equals("com.f0208.lebo")) {
    XposedHelpers.findAndHookMethod(
            "com.zw.lebo.SplashView",
            loadPackageParam.classLoader,
            "onCreate",
            Bundle.class,
            new XC_MethodHook() {

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Toast.makeText((Context) param.thisObject, "a5right", Toast.LENGTH_SHORT).show();
                }
            });
}

打开 app,运行,发现会提示错误:

de.robv.android.xposed.XposedHelpers$ClassNotFoundError: java.lang.ClassNotFoundException: com.zw.lebo.MainActivity
 at de.robv.android.xposed.XposedHelpers.findClass(XposedHelpers.java:71)
 at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:260)
 at com.example.edxposedtest.Xposed04.handleLoadPackage(Xposed04.java:17)
 at de.robv.android.xposed.IXposedHookLoadPackage$Wrapper.handleLoadPackage(IXposedHookLoadPackage.java:37)
 at de.robv.android.xposed.callbacks.XC_LoadPackage.call(XC_LoadPackage.java:61)
 at de.robv.android.xposed.callbacks.XCallback.callAll(XCallback.java:117)
 at com.elderdrivers.riru.edxp._hooker.impl.LoadedApkGetCL.afterHookedMethod(LoadedApkGetCL.java:61)
 at de.robv.android.xposed.MethodHooker.handleHookedMethod(MethodHooker.java:94)
 at EdHooker_d80f73e34da17c301b40feab7995d5a6a0b56621.hook(Unknown Source:45)
 at android.app.LoadedApk.getResources(LoadedApk.java:954)
 at android.app.ContextImpl.createAppContext(ContextImpl.java:2270)

这就是我们之前提到过的,需要传递对应的类加载器才能正确地找到类。

我们可以看看这个类加载器加载的 dex 里面有哪些类:

public void getClassLoaderClassList(ClassLoader classLoader) {
    //private final DexPathList pathList;
    XposedBridge.log("start deal with classloader:" + classLoader);
    Object pathListObj = XposedHelpers.getObjectField(classLoader, "pathList");
    //private final Element[] dexElements;
    Object[] dexElementsObj = (Object[]) XposedHelpers.getObjectField(pathListObj, "dexElements");
    for (Object i : dexElementsObj) {
        //private final DexFile dexFile;
        Object dexFileObj = XposedHelpers.getObjectField(i, "dexFile");
        //private Object mCookie;
        Object mCookieObj = XposedHelpers.getObjectField(dexFileObj, "mCookie");
        //private static native String[] getClassNameList(Object cookie);
        Class DexFileClass = XposedHelpers.findClass("dalvik.system.DexFile", classLoader);

        String[] classList = (String[]) XposedHelpers.callStaticMethod(DexFileClass, "getClassNameList", mCookieObj);
        for (String classname : classList) {
            XposedBridge.log(dexFileObj + "---" + classname);
        }
    }
    XposedBridge.log("end deal with classloader:" + classLoader);

}

这个代码就不细说了,与Android的类加载机制有关,做过Android开发的应该会比较清楚。

具体的分析过程,可以自己去寻找源码。按照自己测试机的版本去看,因为不同的版本有些逻辑或者字段可能会不一样。

贴一个source查看网站:

http://aospxref.com/

打印一下,发现里面的类确实没有 Activity 相关的类,都是壳的类:

I  start deal with classloader:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk"],nativeLibraryDirectories=[/data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/lib/arm, /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]]
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.BuildConfig
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$attr
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$dimen
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$drawable
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$id
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$menu
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$string
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R$style
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.example.helloworld.R
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.f0208.lebo.MyWrapperProxyApplication
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.StubShell.TxAppEntry
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.Bugly
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.BuglyStrategy$a
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.BuglyStrategy
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.CrashModule
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.a
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.b
I  /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk---com.tencent.bugly.yaq.crashreport.BuglyHintException

这就说明app壳只负责加载壳代码,那么app代码什么时候加载呢?自然是当app要运行的时候,几乎所有壳都是处理的 application,所以当 application 的 onCreate 方法执行完之后,下一步要展示app界面的时候,壳肯定要将app的代码释放出来。

那么,是如何释放的呢?这就又与Android的机制相关了,做过插件化开发的都知道有一个类叫做 LoadedApk,它描述的是一个已经加载过的 apk 文件,它里面有一个类加载器,就是用来加载 apk 里面的代码的。当壳释放完app代码后,类加载器也需要修正回来,不然就加载不到app代码了。

所以,当 Application 的 onCreate 方法执行完之后,我们就可以去 ActivityThread 里面的字段里面去拿 LoadedApk 对象,再去获取其类加载即可。

public static ClassLoader getLoadedApkClassloader(XC_MethodHook.MethodHookParam param) {
    ClassLoader currentClassLoader = param.thisObject.getClass().getClassLoader();

    Object currentActivityThread = XposedHelpers.callStaticMethod(
            XposedHelpers.findClass("android.app.ActivityThread", currentClassLoader),
            "currentActivityThread",
            new Class[]{},
            new Object[]{});

    Object mBoundApplication = XposedHelpers.getObjectField(
            currentActivityThread,
            "mBoundApplication");

    Application mInitialApplication = (Application) XposedHelpers.getObjectField(
            currentActivityThread,
            "mInitialApplication");

    Object loadedApkInfo = XposedHelpers.getObjectField(
            mBoundApplication, "info");

    Application mApplication = (Application) XposedHelpers.getObjectField(loadedApkInfo, "mApplication");

    return mApplication.getClassLoader();
}

我们可以看一下这个 classLoader 里面加载的类,与加载类路径:

dalvik.system.PathClassLoader[DexPathList[[dex file "/data/user/0/com.f0208.lebo/files/prodexdir/00O000ll111l_0.dex", dex file "/data/user/0/com.f0208.lebo/files/prodexdir/00O000ll111l_1.dex", zip file "/data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk"],nativeLibraryDirectories=[/data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/lib/arm, /data/app/com.f0208.lebo-3LhDNfPVIAqO1p49M_Rvww==/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]]

可以看到dex的路径是释放在了 files 文件夹里面。

重新启动app运行,就可以正常弹出 toast 了,这样我们就做到了 hook 加壳的 app。

总结

上面说的这个方法还是比较通用的。只要找准classLoader,对加壳app的hook也不难。

  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
xposedinstaller-magisk.apk 是一种用于安卓系统的应用程序。XposedInstaller 是一个开源框架,允许用户对安卓系统进行深度定制和修改。而Magisk则是一个用于Root安卓设备的工具。 XposedInstaller 提供了一种非常灵活的方式,使用户能够安装模块来修改和增强安卓系统的功能。用户可以通过XposedInstaller来激活各种模块,并通过模块的定制设置来实现自定义的功能修改。这些功能包括更改系统界面、优化系统性能、增加新的特性等。XposedInstaller 不需要修改系统文件,因此,用户可以在不更改系统的情况下,实现对安卓系统的定制。 Magisk 则是一个用于Root安卓设备的工具。Root是指获取对安卓系统的完全控制权限,使用户可以执行更多高级操作的过程。Magisk 提供了一种相对较安全的方式来Root设备,并且保留了对一些应用程序正常工作的兼容性。通过Magisk,用户可以安装和管理Root权限,以及通过安装模块来定制和优化设备的功能。此外,Magisk 还提供了隐藏Root权限的功能,可以在需要时临时隐藏Root状态,以满足某些应用程序的要求。 XposedInstaller 和 Magisk 可以结合使用,以实现更高级的安卓系统定制。用户可以使用Magisk来Root设备,并通过XposedInstaller来安装和激活各种模块来修改系统功能。这种组合提供了用户对安卓系统广泛的自定义能力,并且相对安全,使用户可以更好地控制和个性化自己的设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值