首页
社区
课程
招聘
一个自定义classloader的函数抽取壳样本
发表于: 2020-11-9 19:18 7347

一个自定义classloader的函数抽取壳样本

2020-11-9 19:18
7347

题目出自2W班7月第三题

题目要求:基于frida实现的fart的一个版本是通过对ClassLink类中的LoadMethod函数进行hook实现对函数粒度的脱壳的。请编写基于xposed实现的fart版本插件,能够实现对函数粒度的脱壳

根据题目要求,可以知道,我们通过hook LoadMethod即可得到DexFile进而得到basesize,即可dump出dex。如果有函数抽取,即遍历所有的类得到codeitem后还原即可。

本次实践分为两个部分,一个即是原始思路,照葫芦画瓢参照FART的脱壳思路去编写代码,遇到困难暂时没法解决的时候,转变思路二,改用FART配合xposed去实现。

下面是解题过程:

首先我们可以分析frida-fart是如何实现demp dex的。
图片描述

图片描述

图片描述

粗略分析一下就是

那么我们在so层也可以画葫芦试试
测试安卓版本为8.1
部分代码如下

上述看起来一步一步的确是可以拿得到codeitem,然后进一步拿得到ins的。
但是有一个问题我一直没法解决,就是某些方法会报access violation 异常。我通过搜索发现这个是底层发出来的异常,软件层貌似没法catch。

通过使用frida-fart我发现frida版本的也有这样的问题,但是frida这边可以通过try catch捕捉,让程序继续行走。

图片描述

因为暂时无法解决这个问题,所以我放弃这个方向。尝试用fart进行dump。

这里偷懒,就直接用寒冰大佬的xp+fart rom继续dump,就没有自己编译源码了。这里环境android6.0

那么这时候思路就转变了,通过hook loadMethod方法可以拿到artmethod,
而根据fart代码,dumpArtMethod这个方法,传入artmethod即可dump。

上述通过so层调用FART的dumpArtMethodFunction方法,可以dump出dex,以及classlist。这是FART自带的功能。

而在java层,我们需要遍历所有类。
首先hook掉DexClassLoader和PathClassLoader的构造函数,并将classloader存起来。
因为是自定义的Xposed,而所以名字为XcustomBridge。其实这里就是Xposed,仅供参考,不可照抄

紧接着加载我们的so,并遍历所有的classloader,执行loadClass操作。

将dump下来后bin文件批量恢复后,即可查看到,函数已经恢复了。
图片描述

但是如果点多几个函数查看
会发现部分函数并没有复原

图片描述

那么通过回想,我们可以得知,还原的代码其实都是app启动过程中调用过的方法,所以dump下来后,是包含代码的。因此这个壳也是函数抽取壳,而且恢复后不会复原。

而查看FART dump出来的ins文件,发现也缺了很多数据,那么这里可以猜测是某个环节出了问题导致没有dump出来。
然后通过回溯error log 可以发现是classloader的锅

那么这里我们知道了这个app有自定义的classloader。
图片描述

根据提示,我们可以发现这是一个直接继承于classloader的类。
那么来看看通常我们是如何获取classlist的。

我们是通过获得BaseDexClassLoader的pathList字段从而进一步往下获取classList的。但是由于我们现在是直接继承于classloader,所以我们要想办法获取classlist。

那么这里就有两种方法可以实现了。
第一个,fart使用过程中是dump classlist出来。

因此这里我们直接遍历文件,然后loadClass即可。

接下来我们对dex方法体进行批量恢复后,可以看到,函数都恢复了。

图片描述

少部分没有恢复的函数,是因为这个classloader没有找到类,报class not found。接下来我们可以将所有classloader都跑一遍这个list即可

方法二
其实fart也是解析DexFile从而拿到classlist的。
既然有了整个dexFile文件,那么有啥不能解析的呢。

在这里我们可以一层一层的不断获取不断遍历,就可以拿到我们想要的classname
图片描述

拿到classname后我们就可以用这个去遍历loadClass后再dump dex即可。

可以看到这个题目最后想要说的就是自定义classloader如何进行函数抽取还原,那么这里我们需要熟悉Dexfile的文件结构以及了解classloader如何使用

 
 
 
 
 
 
 
 
void *pVoid = old_loadmethod3(thiz, thread, dex_file, it, klass, artmethod);
    __android_log_print(5, "hookso", "pVoid ptr:%p", pVoid);
 
    获取base和size
    const DexHeader *base = dex_file.pHeader;
    size_t size = dex_file.pHeader->fileSize;
    获取code item offset和method idx
    uint32_t codeItemOffset = artmethod->dex_code_item_offset_;
    uint32_t idx = artmethod->dex_method_index_;
    hook prettymethod方法 主动调用获得方法名
    const std::string &string = prettyMethodFunction(artmethod, artmethod,
                                                     true);
    通过偏移可以拿到codeitem
    long codeItemAddr = (long) base + codeItemOffset;
    CodeItem *codeItem = (CodeItem *) codeItemAddr;
    这部分代码可以直接dump dex出来
int pid = getpid();
    char dexFilePath[100] = {0};
    sprintf(dexFilePath, "/sdcard/xxxxx/%p %d LoadMethod.dex", base, size);
    mkdir("/sdcard/xxxxx", 0777);
 
    int fd = open(dexFilePath, O_CREAT | O_RDWR, 666);
    if (fd > 0) {
        ssize_t i = write(fd, base, size);
        if (i > 0) {
            close(fd);
        }
    }
    ...
void *pVoid = old_loadmethod3(thiz, thread, dex_file, it, klass, artmethod);
    __android_log_print(5, "hookso", "pVoid ptr:%p", pVoid);
 
    获取base和size
    const DexHeader *base = dex_file.pHeader;
    size_t size = dex_file.pHeader->fileSize;
    获取code item offset和method idx
    uint32_t codeItemOffset = artmethod->dex_code_item_offset_;
    uint32_t idx = artmethod->dex_method_index_;
    hook prettymethod方法 主动调用获得方法名
    const std::string &string = prettyMethodFunction(artmethod, artmethod,
                                                     true);
    通过偏移可以拿到codeitem
    long codeItemAddr = (long) base + codeItemOffset;
    CodeItem *codeItem = (CodeItem *) codeItemAddr;
    这部分代码可以直接dump dex出来
int pid = getpid();
    char dexFilePath[100] = {0};
    sprintf(dexFilePath, "/sdcard/xxxxx/%p %d LoadMethod.dex", base, size);
    mkdir("/sdcard/xxxxx", 0777);
 
    int fd = open(dexFilePath, O_CREAT | O_RDWR, 666);
    if (fd > 0) {
        ssize_t i = write(fd, base, size);
        if (i > 0) {
            close(fd);
        }
    }
    ...
 
 
 
 
 
先执行原来的loadMethod逻辑
void *pVoid = old_loadmethod3(thiz, thread, dex_file, it, klass, artmethod);
    __android_log_print(5, "hookso", "pVoid ptr:%p", pVoid);
    然后通过so层hook dumpArtmethod函数,并将参数传入
    try {
        dumpArtMethodFunction(artmethod);
    }catch (...){
 
    }
先执行原来的loadMethod逻辑
void *pVoid = old_loadmethod3(thiz, thread, dex_file, it, klass, artmethod);
    __android_log_print(5, "hookso", "pVoid ptr:%p", pVoid);
    然后通过so层hook dumpArtmethod函数,并将参数传入
    try {
        dumpArtMethodFunction(artmethod);
    }catch (...){
 
    }
 
XcustomBridge.hookAllConstructors(DexClassLoader.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    final ClassLoader classLoader = (ClassLoader) param.thisObject;
                    XcustomBridge.log("DexClassLoader:" + classLoader.toString());
 
 
 
                    mClassLoaders.add(classLoader);
 
                }
            });
 
            XcustomBridge.hookAllConstructors(PathClassLoader.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    final ClassLoader classLoader = (ClassLoader) param.thisObject;
                    XcustomBridge.log("PathClassLoader:" + classLoader.toString());
 
 
 
                    mClassLoaders.add(classLoader);
                }
            });
XcustomBridge.hookAllConstructors(DexClassLoader.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    final ClassLoader classLoader = (ClassLoader) param.thisObject;
                    XcustomBridge.log("DexClassLoader:" + classLoader.toString());
 
 
 
                    mClassLoaders.add(classLoader);
 
                }
            });
 
            XcustomBridge.hookAllConstructors(PathClassLoader.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    final ClassLoader classLoader = (ClassLoader) param.thisObject;
                    XcustomBridge.log("PathClassLoader:" + classLoader.toString());
 
 
 
                    mClassLoaders.add(classLoader);
                }
            });
XcustomHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    XcustomBridge.log("attach after");
 
                    mContext = (Context) param.args[0];
 
 
                    XcustomHelpers.callMethod(Runtime.getRuntime(), "doLoad", "/system/lib/libnative-lib.so", mContext.getClassLoader());
 
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(30 * 1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                Log.e("hook1", Log.getStackTraceString(e));
                            }
 
 
                            for (int i = 0; i < mClassLoaders.size(); i++) {
                                ClassLoader classLoader = mClassLoaders.get(i);
                                TestClassloader(classLoader);
                            }
 
                            fart();
                        }
                    }).start();
 
 
 
                }
            });
XcustomHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
 
                    XcustomBridge.log("attach after");
 
                    mContext = (Context) param.args[0];
 
 
                    XcustomHelpers.callMethod(Runtime.getRuntime(), "doLoad", "/system/lib/libnative-lib.so", mContext.getClassLoader());
 
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(30 * 1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                Log.e("hook1", Log.getStackTraceString(e));
                            }
 
 
                            for (int i = 0; i < mClassLoaders.size(); i++) {
                                ClassLoader classLoader = mClassLoaders.get(i);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//