• android脱壳第二发:grpc-dumpdex加修复


    上一篇我写的dex脱壳,写到银行类型的app的dex修复问题,因为dex中被抽取出来的函数的code_item_off 的偏移所在的内存,不在dex文件范围内,所以需要进行一定的修复,然后就停止了。本来不打算接着搞得,但是写了个框架总得有点真正实用的东西。

    内存中所有dex遍历

    我们所要做的是脱壳,即找到保护的dex,有些dex直接在当前classloader中,有些是自定义classloader然后加载的dex,所以如何找到所有的classloader那,java代码可是没有提供过这种功能。但是frida提供了这种功能,通过符号导出调用虚拟机底部函数对所有类进行遍历(这个不多写了,以前写过)

    jobjectArray getClassLoaders(JNIEnv *env, jint targetSdkVersion) {

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    JavaVM *javaVM;

    env->GetJavaVM(&javaVM);

    JavaVMExt *javaVMExt = (JavaVMExt *) javaVM;

    void *runtime = javaVMExt->runtime;

    LOGV("runtime ptr: %p, vmExtPtr: %p", runtime, javaVMExt);

    LOGV("std::unique_ptr size: %d",  sizeof (std::unique_ptr));

    LOGV("get_heap_to_jvm_offset size: %d",  get_heap_to_jvm_offset());

    const int MAX = 5000;

    int offsetOfVmExt = findOffset(runtime, 0, MAX, (void*) javaVMExt);

    LOGV("offsetOfVmExt: %d", offsetOfVmExt);

    int head_offset = offsetOfVmExt-get_heap_to_jvm_offset()+sizeof (void*);

    LOGV("head_offset: %d", head_offset);

    void * heap = (char*)runtime + head_offset;

    AndroidRunAPI* androidRunApi = AndroidRunAPI::getInstance();

    LOGV("1");

    androidRunApi->partialRuntime = static_cast*>(heap);

    getAndroidSystemFunction();

    LOGV("1");

    LookupClassesVisitor visitor(env, javaVMExt);

    LOGV("1 %p",androidRunApi->VisitClassLoaders);

    androidRunApi->VisitClassLoaders(androidRunApi->partialRuntime->class_linker_,&visitor);

    LOGV("1");

    std::vector  vectorObject =  visitor.getVecObj();

    jclass  ClassLoader_cls = env->FindClass("java/lang/ClassLoader");

    LOGV("2");

    for (auto it = vectorObject.begin(); it != vectorObject.end(); /* no increment here */) {

        jboolean re =  env->IsInstanceOf(*it,ClassLoader_cls);

        if(!re){

            it = vectorObject.erase(it);

        } else{

            ++it;

        }

    }

    jobjectArray objectArray = env->NewObjectArray(vectorObject.size(), ClassLoader_cls, NULL);

    for(int i=0;i++){

        env->SetObjectArrayElement(objectArray, i, vectorObject[i]);

    }

    return objectArray;

    }
    我们能遍历系统中所有的类,找到所有类加载,然后通过类加载器找到dex文件(有些cdex文件是系统文件)

    用smali开源项目修dex code_item_off错误的文件
    越来越懒了,不想多bb了,本来还想多写点扫盲和基础知识点的,懒得写了,直接上才艺。

    就上个图片这里,dex文件的code_item 是超过了文件大小的,对于这种是没有办法修复的
    花了半个月将grpc项目修了一下 

    连接和使用方式跟以前一样,但是具体的代码在test中
    ● dumpDexFixCodeItem
    从内存中dump dex的codeitem形成修复文件,传入baksmali中作为修复参数

    ● dumpDexToPC 直接dumpdex 到本地目录
    直接将dex dump到电脑上体验一站式dexdump

    ● dumpDexToAndroidLocal
    dumpdex到android上,因为太大的apk中,dex文件过大内存直接爆了比如银行。

    ● baksmali
    调用的smali,传入dex和需要修的codeitem可以将dex反编译成smali,然后将codeitem 也反编译进去

    ● smali
    将 baksmali 编译出来的 smali工程编译为dex

    使用顺序

    ● 使用dumpDexToPC 和 dumpDexToAndroidLocal 向dump dex文件
    ● 使用dumpDexFixCodeItem dump dex文件的code_item 到修复文件中
    ● 使用baksmali 传入dex文件和 code_item 修复文件反编译为smali工程
    ● 使用smali 将smali 工程反编译为dex

    效果图

    这个上次的文章中某银行dex最终的修复结果

    使用中存在的问题
    ● dump出来的dex文件格式有问题:可能是cdex文件,也有可能是dex文件格式已经被破坏,如果是dex文件格式被破坏,可以通过自己编写更早时期的dex加载时dump来找到dex文件
    ● dumpDexToPC 导致程序崩溃了,这是因为文件太大内存爆满了,用dumpDexToAndroidLocal 手动去下载吧。
    ● 修复失败,修完了以后函数仍然找不到,我目前是用的是类加载,如果抽取函数是通过类加载还原的,这种方式是可以dump出code_item的,如果函数是通过必须要执行函数实体一次才能还原的话,这个可能需要你想办法让函数执行,并且确保被抽取的函数已经还原了,没有再次加密回去。
    ● baksmail 反编译中会剥离调试信息,参数名。smali回编译经过修改会忽略某些函数没有执行实体的错误。

    废话

    相比fart还是差了半截,活太多了只能先到这,不过比fart优雅多了,毕竟优雅永不过时

    future

    如果你想接着研究,但是又不知道该怎么继续研究下去,不知道我这个方向是不是死胡同,那我给点建议。
    ● 修复,如果逆向继续研究修复,用smali编译来编译去优雅程度还是有所欠缺的,而且我写的不完善要一个类一个类的还原,这方面我建议去看看dexmaker这类动态生成dex的源码,在内存中动态生成dex进行修复,或者android源码dex优化部分(我在调试dump debug模式的dex的时候发现dex和apk安装中的dex是不太一样的,查了一下说是优化了)
    ● dump dex,我目前采用的是程序运行中间dump,这个时候dex容易被破坏,可以hook开始的位置dumpdex
    ● dump code item ,这个是个坑,如果是函数运行一次还原还好一点,但是我不太确定是否有非常恶心的那些,比如不断覆盖重复运行,或者运行完再次加密,只要他能牺牲效率什么都做得出来,自己保重。

     

  • 相关阅读:
    JVM之初识垃圾收集器
    初识jetson tx2
    10.3使用Servlet写一个表白墙网站
    Flutter 教程之 如何在app中启用 Google 支付
    14.一元二次方程组,有实根输出实根,没有实根输出虚根
    2022-01-27-JavaScript
    Android Jetpack-Compose相关
    NR paging
    docker容器创建的流程详解
    【Python从0到1】第四篇:使用库
  • 原文地址:https://blog.csdn.net/wei_java144/article/details/138173632