android二代抽取壳的一些脱壳方法

修改rom

通过修改android源码自定义脱壳机,选择合适的时机通过主动调用加载apk中的类,然后再挑选合适的时机对dex文件进行dump。

主动调用

当一个app启动的时候会调用handleBindApplication函数,此函数会调用Application的attachBaseContext函数和Application的OnCreate函数。可以在handleBindApplication函数调用前或者此函数开头调用函数创建一个线程,因为加壳apk一般会在Application的attachBaseContext函数中通过DexClassLoader和PathClassLoader类自定义classloader并加载原始apk/dex文件,所以线程中可以轮询通过反射获取到应用程序默认classloader(mClassloader),需要轮询执行的原因是handleBindApplication还没有调用Application的attachBaseContext函数之前的mClassLoader还是壳自身的classloader,需要在壳代码修复mClassLoader后才能获取到原apk/dex的classloader。

//通过反射获取LoadedApk对象
Class ActivityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = ActivityThreadClass.getDeclaredMethod("currentActivityThread");
Object ActivityThreadObject = currentActivityThreadMethod.invoke(null);
Field mPackagesField = ActivityThreadClass.getDeclaredField("mPackages");
mPackagesField.setAccessible(true);
ArrayMap mPackages = (ArrayMap) mPackagesField.get(ActivityThreadObject);
WeakReference wr = (WeakReference) mPackages.get(this.getPackageName());
//通过反射获取LoadedApk对象的mClassLoader字段
Class LoadedApkClass = Class.forName("android.app.LoadedApk");
Field mClassLoaderField = LoadedApkClass.getDeclaredField("mClassLoader");
mClassLoaderField.setAccessible(true);
ClassLoader mClassLoader = mClassLoaderField.get(wr.get());

这里还有一种特殊情况就是原始apk/dex自己还会自定义classloader并加载其他dex文件,如果这个dex文件也进行了函数抽取那么需要获取他的classloader并进行主动调用使函数回填。这里可以通过第三方ART hook框架对DexClassLoader和PathClassLoader类的构造函数进行hook并获取到返回值就是自定义的classloader,然后再进行主动调用使其函数进行自动回填。

主动调用就是通过获取到classloader对应的DexPathList,进一步获取到所有的DexFile对象,通过调用DexFile的entries等方法枚举dex文件中所有的类名称,使用classloader调用loadclass进行主动加载。

dex Dump

通常修改一些native层的函数进行dexdump,只要native函数能够获取到native层DexFile对象就可以对dex文件进行dump。这里使用LoadMethod函数,此函数再dex文件中的函数被加载到虚拟机中时被调用,当然还有其他很多函数都可以。

不修改rom

不修改源码的情况下通常通过frida调试器进行主动调用和dex的dump,缺点是frida很容易被检测到。

主动调用

frida提供了enumerateClassLoaders这个API可以过去到apk中所有的classloader,这样的话就可以通过frida脚本枚举所有classloader,通过得到classloader对应的所有DexFile对象并调用entries枚举dex文件中的所有类名称进行主动加载。

function dealwithClassLoader(classloaderobj) {
    if (Java.available) {
        Java.perform(function () {
            try {
                var dexfileclass = Java.use("dalvik.system.DexFile");
                var BaseDexClassLoaderclass = Java.use("dalvik.system.BaseDexClassLoader");
                var DexPathListclass = Java.use("dalvik.system.DexPathList");
                var Elementclass = Java.use("dalvik.system.DexPathList$Element");
                var basedexclassloaderobj = Java.cast(classloaderobj, BaseDexClassLoaderclass);
                var tmpobj = basedexclassloaderobj.pathList.value;
                var pathlistobj = Java.cast(tmpobj, DexPathListclass);
                var dexElementsobj = pathlistobj.dexElements.value;
                if (dexElementsobj != null) {
                    for (var i in dexElementsobj) {
                        var obj = dexElementsobj[i];
                        var elementobj = Java.cast(obj, Elementclass);
                        tmpobj = elementobj.dexFile.value;
                        var dexfileobj = Java.cast(tmpobj, dexfileclass);
                        const enumeratorClassNames = dexfileobj.entries();
                        while (enumeratorClassNames.hasMoreElements()) {
                            var className = enumeratorClassNames.nextElement().toString();
                            if(-1 != className.indexOf("com.reverccqin")){
                                console.log("start loadclass->", className);
                                var loadclass = classloaderobj.loadClass(className);
                                console.log("after loadclass->", loadclass);
                            }
                        }
                    }
                }
            } catch (e) {
                console.log(e)
            }
        });
    }
}

dex Dump

dex Dump的话就通过frida hook LoadMethod等方法。

关于主动调用脱壳的对抗

检测主动调用的脱壳行为

因为主动调用主要是通过获取到对应的classloader,并调用loadclass将所有的类都主动加载一遍使其自动进行函数的回填。这就可以通过apk中编写一个永远不会使用的类,因为这个类永远都不会使用,所以apk可以通过调用entries枚举classloader中所有的类并判断此类是否被加载,如果被加载说明存在主动调用的脱壳行为,APK直接闪退

绕过检测

可以再进行主动调用的过程中对特定类进行过滤不进行主动加载,也可以通过hook entries欺骗apk的检测代码。

posted @ 2023-01-06 14:05  怎么可以吃突突  阅读(612)  评论(0编辑  收藏  举报