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

发布于:2024-04-30 ⋅ 阅读:(34) ⋅ 点赞:(0)

上一篇我写的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<PartialRuntime13> size: %d",  sizeof (std::unique_ptr<PartialRuntime13>));

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<PartialRuntime *>(heap);

getAndroidSystemFunction();

LOGV("1");

LookupClassesVisitor visitor(env, javaVMExt);

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

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

LOGV("1");

std::vector<jobject>  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<vectorObject.size();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 ,这个是个坑,如果是函数运行一次还原还好一点,但是我不太确定是否有非常恶心的那些,比如不断覆盖重复运行,或者运行完再次加密,只要他能牺牲效率什么都做得出来,自己保重。

 


网站公告

今日签到

点亮在社区的每一天
去签到