硕士生
 
- 金币
- 530
- 好评
- 22
- 信誉
- 112
|
本帖最后由 秋菱 于 2026-6-6 20:12 编辑
前言
本人小白一枚,想尝试学习一些加固,在身边朋友的推荐下选择了这个壳子.恰巧最近论坛上也有很多大佬发布了自己的分析贴(比如乐子人大佬的帖子),只是复现下来后发现后续的dex vmp相关帖子比较少(很不幸只找到了爱吃菠菜大佬的这篇帖子,不过因为年代久远甚至指令结构都不同了),于是写篇帖子记录一下.
新人发帖,如有错误还望大佬指出.
帖子使用的样本不方便说出来,不过是今年的.(因为据说这个样本保护项开得多)
有人让我设置点隐藏内容提升热度,所以我就设置了
Java层特征

可以看到被vmp保护的方法调用了Lcom/fort/andjni/JniLib;类的一个native方法

JniLib类中有很多种不同的native函数,显然是通过不同的函数签名来处理不同返回值的跳板函数. 既然这个类加载了libdexjni.so,那么这些native函数大概率就是被这个so注册的.
Native层初探
通过BinaryNinja加载so(这里把so基址设为了0x12000000),尝试在函数表中搜索Java_来定位,发现没有结果.
扫了一眼导出表

虽然有些明显的名称混淆,但JNI_OnLoad这些关键函数还在,导出表应该是没有被保护的.
既然静态注册搜不到,那么这些native函数必然是动态注册的了.
直接来到JNI_OnLoad:

发现函数不可解析,应该是被保护了.
往上查找.init.array:


对应的地址完全是空的,那么只可能是在更早执行的.init进行解密了.
先从dynamic里找到init地址


sub_125617dc分配了一块内存并复制了arg2的数据,数据大小被存储在了arg1 + 0x28.
而sub_1256150c主要是进行了数据解压(疑似还有其他操作,但我这个样本并没有执行到,就没去分析):

解压算法是nrv2d,以上数据均来自init函数最开始的参数0x12561b48:

具体逻辑搞清楚了,修复就简单了.可选择:
1.直接使用支持nrv2d的库对0x120096d8处大小0x33dfd的数据进行解压;
2.在init函数运行完后直接dump下0x120096d8处大小0x7e500的数据.
得到解压数据后直接塞回so文件对应位置即可.
这里需要补充一段,完成这步之后BinaryNinja已经可以正常解析函数了,但是后面在使用ida分析so时发现虽然导入表和导出表正确,但ida未能将符号对应的函数解析完整:

简单分析发现这是因为这个so的section被动了手脚:

节中将一个很大的区域标记成SHT_NOBITS扰乱了ida的分析,只需把type改成SHT_NULL(0)或者SHT_PROGBITS(1)即可使ida正常解析.
虚拟机入口分析
解压数据回填后,JNI_OnLoad已经可以正常反编译了,映入眼帘的便是三个函数调用.

挨个翻了一下,发现前两个函数都有很明显的控制流:

而第三个函数看上去非常清晰,并且一眼就能看到很多关键数据(为了方便直观这里稍微分析了一下):

既然前两个函数不太好看,那么就先分析第三个函数好了.
这个函数很简单,首先sub_12010028初始化了一些全局对象:

初始化完成后就注册了JniLib类的native函数:

既然要找的函数已经在这了,不妨直接进去看看吧:

sub_12017adc就是虚拟机的入口了,这里命名为vm_entrance.
由上图不难看出,这个函数的签名大概是(JNIEnv* env, jobjectArray args, void* result)
到了这里,先回顾一下函数的入参:

jobjectArray第0位是jclass,若为实例方法则第1位是实例的jobject,最后一位jint是vm函数的idx.

入口函数先获取了jobjectArray最后一位的Integer,然后调用了intValue函数读到jint传给j__lSSO05lI$I5IllOl_0lS$_lllIII__l$IOlI55$O550IS__lS5$:

而这个函数通过vm_idx去查了表data_1255ff48,因此这个表里一定存储着所有vm方法的数据.
交叉引用可以看到另一个函数对这个表进行了很多操作,应该就是初始化了:

至于这个函数,我们在上面的流程里其实已经见过了,正是JNI_OnLoad调用的第一个函数.
既然终究是躲不过的话,就只好顶着控制流简单看一下喽:

这个表里的结构体大小是0x28,通过一些函数读取数据,读取格式是MessagePack:

这里偷懒用frida在这个函数初始化完后去遍历表data_1255ff48(这里只处理了libDexHelper.so的检测,libdexjni.so应该是没有检测的),根据打印出的数据,大概猜测结构体结构:
- struct method_info __packed
- {
- uint32_t idx;
- uint32_t code_item_size;
- void* code_item;
- uint32_t reg_count;
- uint32_t ins;
- uint32_t outs;
- uint32_t is_static;//这个没去验证,纯经验猜测
- char* shorty;
- };
复制代码 *注:这里的code_item是我先入为主瞎取的名字,并不是真正的标准code_item,因为这个vmp的字节码很像code_item的结构,具体长这样:

而code_item_size则是这段字节码数据的size.
后面会对其进行详细分析,这个命名我感觉还是比较贴合的,就是有点容易混淆,因此提一嘴.
重新回到vm_entrance函数,可以看到在栈上重新排了一个结构体:


最终传入了函数sub_12018544.
sub_12018544大概扫了眼,应该是整理vm方法的参数,给包装类拆箱:

这里创建了一个大小0x48的结构体,与寄存器有关,偏移0x8处的列表用于存储寄存器


最终来到函数j__lIl_0ll5OIlIlISl00lI_lI5lIll$I$IIlIl00I$lIIIl5S0S5$

跳到这个函数后binaryninja就有点不好使了,加载了半天也没加载好,控制流混淆得很严重:

并且函数体量奇大,根据以上种种,不难猜到这个就是解释器函数了.
面对这一望无际的工作量,死磕明显不太现实.
尝试过写反混淆插件,但只能处理些简单的,效果不尽人意,若要兼容更多情况,插件工程量也相当大.
反混淆无果后,决定依靠trace. 试了下frida trace感觉不太稳定,经常会闪退,最后选择了unidbg trace.
虚拟机解释器分析
简单看了一下,这个so的依赖相当少,甚至没有对libDexHepler.so的依赖:

因此unidbg应该不难运行起来,事实也的确如此:
- JNIEnv->FindClass([Z) was called from RWX@0x120170e4[libdexjni.so]0x170e4
- JNIEnv->NewGlobalRef(class [Z) was called from RWX@0x120170f8[libdexjni.so]0x170f8
- JNIEnv->FindClass([B) was called from RWX@0x12014e44[libdexjni.so]0x14e44
- JNIEnv->NewGlobalRef(class [B) was called from RWX@0x12014e58[libdexjni.so]0x14e58
- JNIEnv->FindClass([S) was called from RWX@0x1201503c[libdexjni.so]0x1503c
- JNIEnv->NewGlobalRef(class [S) was called from RWX@0x12015050[libdexjni.so]0x15050
- JNIEnv->FindClass([C) was called from RWX@0x12014000[libdexjni.so]0x14000
- JNIEnv->NewGlobalRef(class [C) was called from RWX@0x12014014[libdexjni.so]0x14014
- JNIEnv->FindClass([I) was called from RWX@0x12010320[libdexjni.so]0x10320
- JNIEnv->NewGlobalRef(class [I) was called from RWX@0x12010334[libdexjni.so]0x10334
- JNIEnv->FindClass([J) was called from RWX@0x12010628[libdexjni.so]0x10628
- JNIEnv->NewGlobalRef(class [J) was called from RWX@0x1201063c[libdexjni.so]0x1063c
- JNIEnv->FindClass([F) was called from RWX@0x12010494[libdexjni.so]0x10494
- JNIEnv->NewGlobalRef(class [F) was called from RWX@0x120104a8[libdexjni.so]0x104a8
- JNIEnv->FindClass([D) was called from RWX@0x120112b4[libdexjni.so]0x112b4
- JNIEnv->NewGlobalRef(class [D) was called from RWX@0x120112c8[libdexjni.so]0x112c8
- JNIEnv->FindClass(java/lang/Class) was called from RWX@0x120112f8[libdexjni.so]0x112f8
- JNIEnv->NewGlobalRef(class java/lang/Class) was called from RWX@0x1201130c[libdexjni.so]0x1130c
- JNIEnv->FindClass(java/lang/Object) was called from RWX@0x12010574[libdexjni.so]0x10574
- JNIEnv->NewGlobalRef(class java/lang/Object) was called from RWX@0x12010588[libdexjni.so]0x10588
- JNIEnv->FindClass(java/lang/reflect/Field) was called from RWX@0x120105e4[libdexjni.so]0x105e4
- JNIEnv->NewGlobalRef(class java/lang/reflect/Field) was called from RWX@0x120105f8[libdexjni.so]0x105f8
- JNIEnv->FindClass(java/lang/String) was called from RWX@0x12015fb8[libdexjni.so]0x15fb8
- JNIEnv->NewGlobalRef(class java/lang/String) was called from RWX@0x12015fcc[libdexjni.so]0x15fcc
- JNIEnv->FindClass(java/lang/reflect/Proxy) was called from RWX@0x12015d14[libdexjni.so]0x15d14
- JNIEnv->NewGlobalRef(class java/lang/reflect/Proxy) was called from RWX@0x12015d28[libdexjni.so]0x15d28
- JNIEnv->FindClass(java/lang/reflect/AccessibleObject) was called from RWX@0x120100d4[libdexjni.so]0x100d4
- JNIEnv->NewGlobalRef(class java/lang/reflect/AccessibleObject) was called from RWX@0x120100e8[libdexjni.so]0x100e8
- JNIEnv->FindClass(com/fort/andjni/JniLib) was called from RWX@0x12010734[libdexjni.so]0x10734
- JNIEnv->NewGlobalRef(class com/fort/andjni/JniLib) was called from RWX@0x12010748[libdexjni.so]0x10748
- JNIEnv->FindClass(java/lang/Boolean) was called from RWX@0x12014f24[libdexjni.so]0x14f24
- JNIEnv->NewGlobalRef(class java/lang/Boolean) was called from RWX@0x12014f38[libdexjni.so]0x14f38
- JNIEnv->FindClass(java/lang/Byte) was called from RWX@0x12014ea0[libdexjni.so]0x14ea0
- JNIEnv->NewGlobalRef(class java/lang/Byte) was called from RWX@0x12014eb4[libdexjni.so]0x14eb4
- JNIEnv->FindClass(java/lang/Character) was called from RWX@0x12014dd0[libdexjni.so]0x14dd0
- JNIEnv->NewGlobalRef(class java/lang/Character) was called from RWX@0x12014de4[libdexjni.so]0x14de4
- JNIEnv->FindClass(java/lang/Short) was called from RWX@0x1201428c[libdexjni.so]0x1428c
- JNIEnv->NewGlobalRef(class java/lang/Short) was called from RWX@0x120142a0[libdexjni.so]0x142a0
- JNIEnv->FindClass(java/lang/Integer) was called from RWX@0x120106a8[libdexjni.so]0x106a8
- JNIEnv->NewGlobalRef(class java/lang/Integer) was called from RWX@0x120106bc[libdexjni.so]0x106bc
- JNIEnv->FindClass(java/lang/Long) was called from RWX@0x120107c8[libdexjni.so]0x107c8
- JNIEnv->NewGlobalRef(class java/lang/Long) was called from RWX@0x120107dc[libdexjni.so]0x107dc
- JNIEnv->FindClass(java/lang/Float) was called from RWX@0x12010364[libdexjni.so]0x10364
- JNIEnv->NewGlobalRef(class java/lang/Float) was called from RWX@0x12010378[libdexjni.so]0x10378
- JNIEnv->FindClass(java/lang/Double) was called from RWX@0x12015f4c[libdexjni.so]0x15f4c
- JNIEnv->NewGlobalRef(class java/lang/Double) was called from RWX@0x12015f60[libdexjni.so]0x15f60
- JNIEnv->FindClass(java/lang/AbstractMethodError) was called from RWX@0x1201357c[libdexjni.so]0x1357c
- JNIEnv->NewGlobalRef(class java/lang/AbstractMethodError) was called from RWX@0x12013590[libdexjni.so]0x13590
- JNIEnv->FindClass(java/lang/ArithmeticException) was called from RWX@0x120170a0[libdexjni.so]0x170a0
- JNIEnv->NewGlobalRef(class java/lang/ArithmeticException) was called from RWX@0x120170b4[libdexjni.so]0x170b4
- JNIEnv->FindClass(java/lang/ArrayIndexOutOfBoundsException) was called from RWX@0x120171c8[libdexjni.so]0x171c8
- JNIEnv->NewGlobalRef(class java/lang/ArrayIndexOutOfBoundsException) was called from RWX@0x120171dc[libdexjni.so]0x171dc
- JNIEnv->FindClass(java/lang/ArrayStoreException) was called from RWX@0x12017128[libdexjni.so]0x17128
- JNIEnv->NewGlobalRef(class java/lang/ArrayStoreException) was called from RWX@0x1201713c[libdexjni.so]0x1713c
- JNIEnv->FindClass(java/lang/ClassCastException) was called from RWX@0x12015d88[libdexjni.so]0x15d88
- JNIEnv->NewGlobalRef(class java/lang/ClassCastException) was called from RWX@0x12015d9c[libdexjni.so]0x15d9c
- JNIEnv->FindClass(java/lang/ClassCircularityError) was called from RWX@0x120101e0[libdexjni.so]0x101e0
- JNIEnv->NewGlobalRef(class java/lang/ClassCircularityError) was called from RWX@0x120101f4[libdexjni.so]0x101f4
- JNIEnv->FindClass(java/lang/ClassNotFoundException) was called from RWX@0x12011360[libdexjni.so]0x11360
- JNIEnv->NewGlobalRef(class java/lang/ClassNotFoundException) was called from RWX@0x12011374[libdexjni.so]0x11374
- JNIEnv->FindClass(java/lang/ClassFormatError) was called from RWX@0x1201126c[libdexjni.so]0x1126c
- JNIEnv->NewGlobalRef(class java/lang/ClassFormatError) was called from RWX@0x12011280[libdexjni.so]0x11280
- JNIEnv->FindClass(java/lang/Error) was called from RWX@0x12015ddc[libdexjni.so]0x15ddc
- JNIEnv->NewGlobalRef(class java/lang/Error) was called from RWX@0x12015df0[libdexjni.so]0x15df0
- JNIEnv->FindClass(java/lang/ExceptionInInitializerError) was called from RWX@0x12014d0c[libdexjni.so]0x14d0c
- JNIEnv->NewGlobalRef(class java/lang/ExceptionInInitializerError) was called from RWX@0x12014d20[libdexjni.so]0x14d20
- JNIEnv->FindClass(java/io/FileNotFoundException) was called from RWX@0x12017184[libdexjni.so]0x17184
- JNIEnv->NewGlobalRef(class java/io/FileNotFoundException) was called from RWX@0x12017198[libdexjni.so]0x17198
- JNIEnv->FindClass(java/io/IOException) was called from RWX@0x120108d8[libdexjni.so]0x108d8
- JNIEnv->NewGlobalRef(class java/io/IOException) was called from RWX@0x120108ec[libdexjni.so]0x108ec
- JNIEnv->FindClass(java/lang/IllegalAccessError) was called from RWX@0x12015e78[libdexjni.so]0x15e78
- JNIEnv->NewGlobalRef(class java/lang/IllegalAccessError) was called from RWX@0x12015e8c[libdexjni.so]0x15e8c
- JNIEnv->FindClass(java/lang/IllegalAccessException) was called from RWX@0x12013520[libdexjni.so]0x13520
- JNIEnv->NewGlobalRef(class java/lang/IllegalAccessException) was called from RWX@0x12013534[libdexjni.so]0x13534
- JNIEnv->FindClass(java/lang/IllegalArgumentException) was called from RWX@0x12013fa4[libdexjni.so]0x13fa4
- JNIEnv->NewGlobalRef(class java/lang/IllegalArgumentException) was called from RWX@0x12013fb8[libdexjni.so]0x13fb8
- JNIEnv->FindClass(java/lang/IllegalMonitorStateException) was called from RWX@0x120102bc[libdexjni.so]0x102bc
- JNIEnv->NewGlobalRef(class java/lang/IllegalMonitorStateException) was called from RWX@0x120102d0[libdexjni.so]0x102d0
- JNIEnv->FindClass(java/lang/IllegalStateException) was called from RWX@0x1201414c[libdexjni.so]0x1414c
- JNIEnv->NewGlobalRef(class java/lang/IllegalStateException) was called from RWX@0x12014160[libdexjni.so]0x14160
- JNIEnv->FindClass(java/lang/IllegalThreadStateException) was called from RWX@0x12014f68[libdexjni.so]0x14f68
- JNIEnv->NewGlobalRef(class java/lang/IllegalThreadStateException) was called from RWX@0x12014f7c[libdexjni.so]0x14f7c
- JNIEnv->FindClass(java/lang/IncompatibleClassChangeError) was called from RWX@0x120140c4[libdexjni.so]0x140c4
- JNIEnv->NewGlobalRef(class java/lang/IncompatibleClassChangeError) was called from RWX@0x120140d8[libdexjni.so]0x140d8
- JNIEnv->FindClass(java/lang/InstantiationError) was called from RWX@0x12010230[libdexjni.so]0x10230
- JNIEnv->NewGlobalRef(class java/lang/InstantiationError) was called from RWX@0x12010244[libdexjni.so]0x10244
- JNIEnv->FindClass(java/lang/InstantiationException) was called from RWX@0x12014044[libdexjni.so]0x14044
- JNIEnv->NewGlobalRef(class java/lang/InstantiationException) was called from RWX@0x12014058[libdexjni.so]0x14058
- JNIEnv->FindClass(java/lang/InternalError) was called from RWX@0x1201433c[libdexjni.so]0x1433c
- JNIEnv->NewGlobalRef(class java/lang/InternalError) was called from RWX@0x12014350[libdexjni.so]0x14350
- JNIEnv->FindClass(java/lang/InterruptedException) was called from RWX@0x120104e8[libdexjni.so]0x104e8
- JNIEnv->NewGlobalRef(class java/lang/InterruptedException) was called from RWX@0x120104fc[libdexjni.so]0x104fc
- JNIEnv->FindClass(java/lang/LinkageError) was called from RWX@0x12010868[libdexjni.so]0x10868
- JNIEnv->NewGlobalRef(class java/lang/LinkageError) was called from RWX@0x1201087c[libdexjni.so]0x1087c
- JNIEnv->FindClass(java/lang/NegativeArraySizeException) was called from RWX@0x12010920[libdexjni.so]0x10920
- JNIEnv->NewGlobalRef(class java/lang/NegativeArraySizeException) was called from RWX@0x12010934[libdexjni.so]0x10934
- JNIEnv->FindClass(java/lang/NoClassDefFoundError) was called from RWX@0x12010530[libdexjni.so]0x10530
- JNIEnv->NewGlobalRef(class java/lang/NoClassDefFoundError) was called from RWX@0x12010544[libdexjni.so]0x10544
- JNIEnv->FindClass(java/lang/NoSuchFieldError) was called from RWX@0x12014d74[libdexjni.so]0x14d74
- JNIEnv->NewGlobalRef(class java/lang/NoSuchFieldError) was called from RWX@0x12014d88[libdexjni.so]0x14d88
- JNIEnv->FindClass(java/lang/NoSuchFieldException) was called from RWX@0x120103e4[libdexjni.so]0x103e4
- JNIEnv->NewGlobalRef(class java/lang/NoSuchFieldException) was called from RWX@0x120103f8[libdexjni.so]0x103f8
- JNIEnv->FindClass(java/lang/NoSuchMethodError) was called from RWX@0x12014fac[libdexjni.so]0x14fac
- JNIEnv->NewGlobalRef(class java/lang/NoSuchMethodError) was called from RWX@0x12014fc0[libdexjni.so]0x14fc0
- JNIEnv->FindClass(java/lang/NullPointerException) was called from RWX@0x1201080c[libdexjni.so]0x1080c
- JNIEnv->NewGlobalRef(class java/lang/NullPointerException) was called from RWX@0x12010820[libdexjni.so]0x10820
- JNIEnv->FindClass(java/lang/OutOfMemoryError) was called from RWX@0x12013604[libdexjni.so]0x13604
- JNIEnv->NewGlobalRef(class java/lang/OutOfMemoryError) was called from RWX@0x12013618[libdexjni.so]0x13618
- JNIEnv->FindClass(java/lang/RuntimeException) was called from RWX@0x120142d0[libdexjni.so]0x142d0
- JNIEnv->NewGlobalRef(class java/lang/RuntimeException) was called from RWX@0x120142e4[libdexjni.so]0x142e4
- JNIEnv->FindClass(java/lang/StackOverflowError) was called from RWX@0x1201419c[libdexjni.so]0x1419c
- JNIEnv->NewGlobalRef(class java/lang/StackOverflowError) was called from RWX@0x120141b0[libdexjni.so]0x141b0
- JNIEnv->GetMethodID(java/lang/Class.getField(Ljava/lang/String;)Ljava/lang/reflect/Field;) => 0xd585d5a3 was called from RWX@0x12015164[libdexjni.so]0x15164
- JNIEnv->GetMethodID(java/lang/Class.getDeclaredField(Ljava/lang/String;)Ljava/lang/reflect/Field;) => 0x987c467d was called from RWX@0x120152c4[libdexjni.so]0x152c4
- JNIEnv->GetMethodID(java/lang/reflect/Field.get(Ljava/lang/Object;)Ljava/lang/Object;) => 0x7abc2552 was called from RWX@0x120155ac[libdexjni.so]0x155ac
- JNIEnv->GetMethodID(java/lang/reflect/Field.getBoolean(Ljava/lang/Object;)Z) => 0xfae67c5e was called from RWX@0x12015828[libdexjni.so]0x15828
- JNIEnv->GetMethodID(java/lang/reflect/Field.getByte(Ljava/lang/Object;)B) => 0x35776224 was called from RWX@0x12015a80[libdexjni.so]0x15a80
- JNIEnv->GetMethodID(java/lang/reflect/Field.getShort(Ljava/lang/Object;)S) => 0xaf19c8c3 was called from RWX@0x12015ce0[libdexjni.so]0x15ce0
- JNIEnv->GetMethodID(java/lang/reflect/Field.getChar(Ljava/lang/Object;)C) => 0x50a94c97 was called from RWX@0x12012668[libdexjni.so]0x12668
- JNIEnv->GetMethodID(java/lang/reflect/Field.getInt(Ljava/lang/Object;)I) => 0x82f4a366 was called from RWX@0x12012890[libdexjni.so]0x12890
- JNIEnv->GetMethodID(java/lang/reflect/Field.getLong(Ljava/lang/Object;)J) => 0xd72cad38 was called from RWX@0x12012ae4[libdexjni.so]0x12ae4
- JNIEnv->GetMethodID(java/lang/reflect/Field.getFloat(Ljava/lang/Object;)F) => 0xba8696d6 was called from RWX@0x12012d44[libdexjni.so]0x12d44
- JNIEnv->GetMethodID(java/lang/reflect/Field.getDouble(Ljava/lang/Object;)D) => 0xfe53f3d was called from RWX@0x12012fb0[libdexjni.so]0x12fb0
- JNIEnv->GetMethodID(java/lang/reflect/Field.set(Ljava/lang/Object;Ljava/lang/Object;)V) => 0xf25f2330 was called from RWX@0x12013270[libdexjni.so]0x13270
- JNIEnv->GetMethodID(java/lang/reflect/Field.setBoolean(Ljava/lang/Object;Z)V) => 0xc42cc02e was called from RWX@0x120134f8[libdexjni.so]0x134f8
- JNIEnv->GetMethodID(java/lang/reflect/Field.setChar(Ljava/lang/Object;C)V) => 0xb43f5b1f was called from RWX@0x12016270[libdexjni.so]0x16270
- JNIEnv->GetMethodID(java/lang/reflect/Field.setByte(Ljava/lang/Object;B)V) => 0x6933f390 was called from RWX@0x120164b8[libdexjni.so]0x164b8
- JNIEnv->GetMethodID(java/lang/reflect/Field.setShort(Ljava/lang/Object;S)V) => 0x3c37f3fb was called from RWX@0x12016710[libdexjni.so]0x16710
- JNIEnv->GetMethodID(java/lang/reflect/Field.setInt(Ljava/lang/Object;I)V) => 0x256c9664 was called from RWX@0x12016958[libdexjni.so]0x16958
- JNIEnv->GetMethodID(java/lang/reflect/Field.setFloat(Ljava/lang/Object;F)V) => 0x9e64b90e was called from RWX@0x12016b9c[libdexjni.so]0x16b9c
- JNIEnv->GetMethodID(java/lang/reflect/Field.setLong(Ljava/lang/Object;J)V) => 0xfe28280c was called from RWX@0x12016e10[libdexjni.so]0x16e10
- JNIEnv->GetMethodID(java/lang/reflect/Field.setDouble(Ljava/lang/Object;D)V) => 0xe7ac6ddb was called from RWX@0x12017064[libdexjni.so]0x17064
- JNIEnv->GetMethodID(java/lang/reflect/Field.setAccessible(Z)V) => 0xcb19eff2 was called from RWX@0x12014440[libdexjni.so]0x14440
- JNIEnv->GetMethodID(java/lang/reflect/AccessibleObject.setAccessible(Z)V) => 0xc15280ab was called from RWX@0x120144f0[libdexjni.so]0x144f0
- JNIEnv->GetMethodID(java/lang/String.<init>([B)V) => 0xd5642694 was called from RWX@0x1201464c[libdexjni.so]0x1464c
- JNIEnv->GetMethodID(java/lang/String.intern()Ljava/lang/String;) => 0x38d73d3 was called from RWX@0x12014714[libdexjni.so]0x14714
- JNIEnv->GetMethodID(java/lang/Object.getClass()Ljava/lang/Class;) => 0xb529717c was called from RWX@0x1201495c[libdexjni.so]0x1495c
- JNIEnv->GetMethodID(java/lang/Class.getName()Ljava/lang/String;) => 0x4a974877 was called from RWX@0x12014a40[libdexjni.so]0x14a40
- JNIEnv->GetStaticMethodID(java/lang/reflect/Proxy.isProxyClass(Ljava/lang/Class;)Z) => 0x7698fdb9 was called from RWX@0x12014cc0[libdexjni.so]0x14cc0
- JNIEnv->GetStaticMethodID(com/fort/andjni/JniLib.InvokeObject([Ljava/lang/Object;)Ljava/lang/Object;) => 0xac6fba43 was called from RWX@0x12011700[libdexjni.so]0x11700
- JNIEnv->GetStaticMethodID(com/fort/andjni/JniLib.getAllSuperClassesAndInterfaces(Ljava/lang/Class;)[Ljava/lang/Class;) => 0x2c346997 was called from RWX@0x12011b04[libdexjni.so]0x11b04
- JNIEnv->GetStaticMethodID(java/lang/Boolean.valueOf(Z)Ljava/lang/Boolean;) => 0x1d8c249f was called from RWX@0x12011cc0[libdexjni.so]0x11cc0
- JNIEnv->GetStaticMethodID(java/lang/Byte.valueOf(B)Ljava/lang/Byte;) => 0x25bc8287 was called from RWX@0x12011e40[libdexjni.so]0x11e40
- JNIEnv->GetStaticMethodID(java/lang/Character.valueOf(C)Ljava/lang/Character;) => 0xba1ae606 was called from RWX@0x12011fec[libdexjni.so]0x11fec
- JNIEnv->GetStaticMethodID(java/lang/Short.valueOf(S)Ljava/lang/Short;) => 0xe91382b0 was called from RWX@0x12012184[libdexjni.so]0x12184
- JNIEnv->GetStaticMethodID(java/lang/Integer.valueOf(I)Ljava/lang/Integer;) => 0x8f152ce2 was called from RWX@0x12012338[libdexjni.so]0x12338
- JNIEnv->GetStaticMethodID(java/lang/Float.valueOf(F)Ljava/lang/Float;) => 0xdac25823 was called from RWX@0x120137fc[libdexjni.so]0x137fc
- JNIEnv->GetStaticMethodID(java/lang/Double.valueOf(D)Ljava/lang/Double;) => 0xca7b90a5 was called from RWX@0x12013984[libdexjni.so]0x13984
- JNIEnv->GetStaticMethodID(java/lang/Long.valueOf(J)Ljava/lang/Long;) => 0x1a324bff was called from RWX@0x12013b0c[libdexjni.so]0x13b0c
- INFO [com.github.unidbg.spi.Dlfcn] (Dlfcn:31) - Find symbol "dvmDecodeIndirectRef" failed: handle=0x0, LR=RWX@0x12013c8c[libdexjni.so]0x13c8c
- INFO [com.github.unidbg.spi.Dlfcn] (Dlfcn:31) - Find symbol "dvmFindStaticFieldHier" failed: handle=0x0, LR=RWX@0x12013e34[libdexjni.so]0x13e34
- JNIEnv->GetMethodID(java/lang/Integer.intValue()I) => 0x5d9f068b was called from RWX@0x12013ed8[libdexjni.so]0x13ed8
- JNIEnv->GetMethodID(java/lang/Short.intValue()I) => 0xa3b9250d was called from RWX@0x12013f70[libdexjni.so]0x13f70
- JNIEnv->GetMethodID(java/lang/Character.charValue()C) => 0x71f71ced was called from RWX@0x12010ae4[libdexjni.so]0x10ae4
- JNIEnv->GetMethodID(java/lang/Byte.intValue()I) => 0x4d014b99 was called from RWX@0x12010b80[libdexjni.so]0x10b80
- JNIEnv->GetMethodID(java/lang/Boolean.booleanValue()Z) => 0x31f67dab was called from RWX@0x12010d20[libdexjni.so]0x10d20
- JNIEnv->GetMethodID(java/lang/Long.longValue()J) => 0x44606195 was called from RWX@0x12010e84[libdexjni.so]0x10e84
- JNIEnv->GetMethodID(java/lang/Float.floatValue()F) => 0x6ff98ad7 was called from RWX@0x12010ff8[libdexjni.so]0x10ff8
- JNIEnv->GetMethodID(java/lang/Double.doubleValue()D) => 0x8acb0bf9 was called from RWX@0x12011178[libdexjni.so]0x11178
- JNIEnv->FindClass(android/os/Build$VERSION) was called from RWX@0x1201732c[libdexjni.so]0x1732c
- JNIEnv->GetStaticFieldID(android/os/Build$VERSION.SDK_INTI) => 0x1e4ff4f1 was called from RWX@0x12017354[libdexjni.so]0x17354
- JNIEnv->GetStaticIntField(class android/os/Build$VERSION, SDK_INT => 0x17) was called from RWX@0x1201736c[libdexjni.so]0x1736c
- JNIEnv->FindClass(com/fort/andjni/JniLib) was called from RWX@0x1200fea4[libdexjni.so]0xfea4
- JNIEnv->RegisterNatives(com/fort/andjni/JniLib, RW@0x1255fe50[libdexjni.so]0x55fe50, 10) was called from RWX@0x1200ff58[libdexjni.so]0xff58
- RegisterNative(com/fort/andjni/JniLib, cV([Ljava/lang/Object;)V, RWX@0x12017770[libdexjni.so]0x17770)
- RegisterNative(com/fort/andjni/JniLib, cI([Ljava/lang/Object;)I, RWX@0x120177c4[libdexjni.so]0x177c4)
- RegisterNative(com/fort/andjni/JniLib, cL([Ljava/lang/Object;)Ljava/lang/Object;, RWX@0x1201781c[libdexjni.so]0x1781c)
- RegisterNative(com/fort/andjni/JniLib, cS([Ljava/lang/Object;)S, RWX@0x12017874[libdexjni.so]0x17874)
- RegisterNative(com/fort/andjni/JniLib, cC([Ljava/lang/Object;)C, RWX@0x120178cc[libdexjni.so]0x178cc)
- RegisterNative(com/fort/andjni/JniLib, cB([Ljava/lang/Object;)B, RWX@0x12017924[libdexjni.so]0x17924)
- RegisterNative(com/fort/andjni/JniLib, cJ([Ljava/lang/Object;)J, RWX@0x1201797c[libdexjni.so]0x1797c)
- RegisterNative(com/fort/andjni/JniLib, cZ([Ljava/lang/Object;)Z, RWX@0x120179d4[libdexjni.so]0x179d4)
- RegisterNative(com/fort/andjni/JniLib, cF([Ljava/lang/Object;)F, RWX@0x12017a2c[libdexjni.so]0x17a2c)
- RegisterNative(com/fort/andjni/JniLib, cD([Ljava/lang/Object;)D, RWX@0x12017a84[libdexjni.so]0x17a84)
复制代码
整个运行流程非常清晰,可以依据这个来补sub_12010028中的结构体.
这里我为了方便选择调用0号函数(这张图好像是第三次出现了233)

- vm.resolveClass("com/fort/andjni/JniLib").callStaticJniMethod(emulator, "cV([Ljava/lang/Object;)V", new ArrayObject(vm.resolveClass("android/app/Activity"), vm.resolveClass("android/app/Activity").newObject(null), vm.resolveClass("android/os/Bundle").newObject(null), DvmInteger.valueOf(vm, 0)));
复制代码
因为函数简单(毕竟类都叫BlankActivity了),没有复杂逻辑,只补了几个简单函数就跑完了,整个流程被顺利trace下来.
毕竟是vmp,接下来的首要任务是先找到insns.
这里通过定位我命名的那个code_item结构然后偏移0x10即为insns,而code_item又在j__lSSO05lI$I5IllOl_0lS$_lllIII__l$IOlI55$O550IS__lS5$函数返回的结构体中:


在trace中搜索0x12018194:
- [libdexjni.so 0x018194] [f80300aa] 0x12018194: "mov x24, x0" x0=0x12893030 => x24=0x12893030
复制代码 得到结构体内存地址0x12893030,再查找其偏移0x8处的code_item读取:

- [libdexjni.so 0x018228] [080740f9] 0x12018228: "ldr x8, [x24, #8]" ; mem[READ] abs=0x12893038 x24=0x12893030 => x8=0x128ac000
复制代码 对比一下code_item的标准结构(这里不去关注后面的try_item)
- struct code_item {
- uint16_t registers_size;
- uint16_t ins_size;
- uint16_t outs_size;
- uint16_t tries_size;
- uint32_t debug_info_off;
- uint32_t insns_size;
- uint16_t insns[insns_size];
- }
复制代码
前0x10字节的确非常符合code_item的结构,并且可以验证偏移0xc处的0x30正是insns_size(这段数据没有try_item,长度共0x70,符合0x10+0x30*2),因此后面0x60字节即为insns.
查找对0x128ac010处的读取:
- [libdexjni.so 0x04e5cc] [090140b9] 0x1204e5cc: "ldr w9, [x8]" ; mem[READ] abs=0x128ac010 x8=0x128ac010 => w9=0x9c2e
复制代码
读出了0x00009c2e四个字节,低16位被拿去查表0x12098a30,结果是0x12098a30 + (0x8d6c << 3)) = 0x120e6ba0
然后从这个位置读出了一个地址,最后br跳过去了

至于这个目标地址...依然在解释器函数之内:

(0x12029578-0x1206e068,这函数实在太大了)
而高16位则是
- [libdexjni.so 0x04e5d0] [e9ab0af9] 0x1204e5d0: "str x9, [sp, #0x1550]" ; mem[WRITE] abs=0xe4ffe500 x9=0x9c2e sp=0xe4ffcfb0 => x9=0x9c2e
- ->
- [libdexjni.so 0x038d24] [e8ab4af9] 0x12038d24: "ldr x8, [sp, #0x1550]" ; mem[READ] abs=0xe4ffe500 sp=0xe4ffcfb0 => x8=0x9c2e
- [libdexjni.so 0x038d28] [085d1053] 0x12038d28: "ubfx w8, w8, #0x10, #8" w8=0x9c2e => w8=0x0
- [libdexjni.so 0x038d2c] [e8a70af9] 0x12038d2c: "str x8, [sp, #0x1548]" ; mem[WRITE] abs=0xe4ffe4f8 x8=0x0 sp=0xe4ffcfb0 => x8=0x0
- ->
- [libdexjni.so 0x056770] [e8a74af9] 0x12056770: "ldr x8, [sp, #0x1548]" ; mem[READ] abs=0xe4ffe4f8 sp=0xe4ffcfb0 => x8=0x0
- [libdexjni.so 0x056774] [083d4092] 0x12056774: "and x8, x8, #0xffff" x8=0x0 => x8=0x0
- [libdexjni.so 0x056778] [e11742f9] 0x12056778: "ldr x1, [sp, #0x428]" ; mem[READ] abs=0xe4ffd3d8 sp=0xe4ffcfb0 => x1=0x35ef1869
- [libdexjni.so 0x05677c] [e9b34af9] 0x1205677c: "ldr x9, [sp, #0x1560]" ; mem[READ] abs=0xe4ffe510 sp=0xe4ffcfb0 => x9=0x134d1080
- [libdexjni.so 0x056780] [217928f8] 0x12056780: "str x1, [x9, x8, lsl #3]" ; mem[WRITE] abs=0x134d1080 x1=0x35ef1869 x9=0x134d1080 x8=0x0 => x1=0x35ef1869
复制代码 通过高16位查询了一个表并写入了一个值.
低16位的查表跳转,很像是在解释指令;而高16位的查表写入,则像是对寄存器的操作.
但是标准的opcode明明是uint8_t,这里却是uint16_t,难不成魔改了?
简单翻了一下表0x12098a30,发现其中元素大多为0,但非0元素全部指向解释器函数内部,加大了uint16_t的vmcode的可能性.
为了验证,直接查一下第0xffff位的元素地址,看看这个表是否真的有这么大:
0x12098a30 + (0xffff << 3) = 0x12118a28

结果非常神奇,恰好达到了一个数据分界处,0x12118a28之上的部分即为跳转表,之下的部分则是其他数据,所以这个表的确有0xffff个元素,涵盖了整个uint16_t范围.
种种迹象表明,vmcode就是uint16_t类型的,因此这个vmp必然存在魔改.
跳转表得到后,使用unidbg对整个表范围的读取进行监听:
- emulator.traceRead(0x12098a30, 0x12118a28);
复制代码 得到结果:
- Memory READ at 0x120e6ba0, data size = 8, data value = 0x000000001206588c, PC=RWX@0x1204e5e0[libdexjni.so]0x4e5e0, LR=RWX@0x12050708[libdexjni.so]0x50708
- Memory READ at 0x120df590, data size = 8, data value = 0x00000000120449fc, PC=RWX@0x1204b05c[libdexjni.so]0x4b05c, LR=RWX@0x1205081c[libdexjni.so]0x5081c
- Memory READ at 0x120bdb80, data size = 8, data value = 0x0000000012065158, PC=RWX@0x120553a4[libdexjni.so]0x553a4, LR=RWX@0x12031234[libdexjni.so]0x31234
- Memory READ at 0x120f24d0, data size = 8, data value = 0x0000000012044d90, PC=RWX@0x1202e93c[libdexjni.so]0x2e93c, LR=RWX@0x12051cfc[libdexjni.so]0x51cfc
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x120570c8[libdexjni.so]0x570c8, LR=RWX@0x12056044[libdexjni.so]0x56044
- Memory READ at 0x12116fa8, data size = 8, data value = 0x000000001205cba4, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
- Memory READ at 0x120aba20, data size = 8, data value = 0x0000000012064fd8, PC=RWX@0x12064ae8[libdexjni.so]0x64ae8, LR=RWX@0x12049f78[libdexjni.so]0x49f78
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x12053570[libdexjni.so]0x53570, LR=RWX@0x12049f78[libdexjni.so]0x49f78
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
- Memory READ at 0x120bc770, data size = 8, data value = 0x0000000012065708, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
复制代码 对读取的地址进行逆向操作,还原出vmcode:
vmcode = (address - 0x12098a30) >>> 3
逐个翻译得:0x9c2e、0x8d6c、0x4a2a、0xb354、0x5b4d、0xfcaf、0x25fe、0x5b4d、0x5b4d、0x47a8.
并以此为特征将指令分割:

现在vmcode已知了,接下来想要分析指令操作,还有必不可少的一步:寄存器监听.
在上文有一个地方我们看到了对寄存器内存的分配:

unidbg断点可得分配的内存地址为0x134d1080,而这个方法的registers_size为4,因此监听:
- emulator.traceRead(0x134d1080, 0x134d10a0);
- emulator.traceWrite(0x134d1080, 0x134d10a0);
复制代码 其中0x134d1080为v0寄存器、0x134d1088 v1、0x134d1090 p0、0x134d1098 p1

可以清楚看到先对寄存器进行了一些初始化,写入了p0(this)和p1(android/os/Bundle)的值.
Memory READ at 0x120e6ba0后开始运行第一条指令,在v0寄存器上写入了值0x000000004bb4de6a;第二条指令在v1寄存器写入值0x000000002f8f5f62,并且两条指令执行的作用看上去出奇一致,都是在初始化一个jstring,不过vmcode不同.
从log中可以猜到,这两个值正是来自Memory WRITE上方的JNIEnv->NewGlobalRef.
这里凭空出现了一个字符串,自然要搞清来由.
直接跳转到上方jni调用的地址处,发现是从j__l$I0lOll00SOlSI_ISl50IO0lOI_Ol$_IIIlIIlIl5IIll5IS5$读取的

跟过去发现又是在查表:

先不急着去追数据,先打印一下用于查表的idx:
- emulator.getBackend().hook_add_new(new CodeHook() {
- @Override
- public void hook(Backend backend, long address, int size, Object user) {
- System.out.printf("idx:%#x\n", backend.reg_read(Unicorn.UC_ARM64_REG_X0).intValue());
- }
- @Override
- public void onAttach(UnHook unHook) {
- }
- @Override
- public void detach() {
- }
- }, 0x1200cea0, 0x1200cea0, null);
复制代码
再回头看一眼insns,这不就在这嘛:

所以这两字节就是用于查字符串表的索引喽.
交叉引用一下字符串表,依旧是熟悉的感觉:

看到这里,你可能已经猜到了,没错,这就是JNI_OnLoad调用的第二个函数.(之前跳过的函数最后都没逃过qwq)

依然是通过MessagePack解析二进制数据,并且这个函数初始化的数据不只有这一个表,函数中一共对五个表进行了初始化:

依旧是等这个函数运行完后,使用unidbg直接打印出表,然后猜测含义,这里直接给出分析结果:






结构体:
- struct dvm_string __packed
- {
- char* string;
- uint64_t len;
- };
- struct dvm_method __packed
- {
- char* class_name;
- char* method_args;
- char* method_name;
- };
- struct dvm_method2 __packed
- {
- char* class_name;
- char* method_sig;
- char* method_name;
- char* method_shorty;
- uint64_t zero;
- };
复制代码
看了这么多,至于被解析的数据在哪,在函数开头有这么一个调用:

这个函数就是对so中一段数据进行lz4解压,所以来源就很明显了.

现在数据来源都清楚了,那么写入v0还是v1是怎么决定的呢,其实就是vmcode后面的两字节,也就是之前追踪的“0x00009c2e的高16位”:

第一条指令是0x00,所以写入v0寄存器;第二条指令是0x01,写入v1寄存器.
至于最后0x8a08和0x6e4d那两字节数据,在trace中也没有读取的记录,只读了个半字
- [libdexjni.so 0x038d1c] [01094079] 0x12038d1c: "ldrh w1, [x8, #4]" ; mem[READ] abs=0x128ac014 x8=0x128ac010 => w1=0x4f9
复制代码
应该是用于对齐的无用数据了(后面同样有大量这种数据).
因此这两条指令翻译过来就是
- const-string v0, "BlankActivity"
- const-string v1, "onCreate"
复制代码
然后再来看下一条,这条指令显然是在调用com/albert/xchatkit/d.b(Ljava/lang/String;Ljava/lang/String;)V方法

不出意外要用到刚才解析出来的method表.
为了省事,直接把四个表(有一个表不存在这样的查表函数,因此是四个)的读取全部hook一下:

- emulator.getBackend().hook_add_new(new CodeHook() {
- @Override
- public void hook(Backend backend, long address, int size, Object user) {
- System.out.printf("g_string_list2:%#x\n", backend.reg_read(Unicorn.UC_ARM64_REG_X0).intValue());
- }
- @Override
- public void onAttach(UnHook unHook) {
- }
- @Override
- public void detach() {
- }
- }, 0x1200cea0, 0x1200cea0, null);
- emulator.getBackend().hook_add_new(new CodeHook() {
- @Override
- public void hook(Backend backend, long address, int size, Object user) {
- System.out.printf("g_int_list:%#x\n", backend.reg_read(Unicorn.UC_ARM64_REG_X0).intValue());
- }
- @Override
- public void onAttach(UnHook unHook) {
- }
- @Override
- public void detach() {
- }
- }, 0x1200ceec, 0x1200ceec, null);
- emulator.getBackend().hook_add_new(new CodeHook() {
- @Override
- public void hook(Backend backend, long address, int size, Object user) {
- System.out.printf("g_method_list:%#x\n", backend.reg_read(Unicorn.UC_ARM64_REG_X0).intValue());
- }
- @Override
- public void onAttach(UnHook unHook) {
- }
- @Override
- public void detach() {
- }
- }, 0x1200cf38, 0x1200cf38, null);
- emulator.getBackend().hook_add_new(new CodeHook() {
- @Override
- public void hook(Backend backend, long address, int size, Object user) {
- System.out.printf("g_method_list2:%#x\n", backend.reg_read(Unicorn.UC_ARM64_REG_X0).intValue());
- }
- @Override
- public void onAttach(UnHook unHook) {
- }
- @Override
- public void detach() {
- }
- }, 0x1200cf84, 0x1200cf84, null);
复制代码 重新运行一下得到method idx是0x6c3


由于调用的jni函数是CallStaticVoidMethodA,因此这条指令应该是invoke-static,并且从寄存器读取或者结合前两条指令可以得出两个入参jstring是v0和v1.
现在这条指令被魔改成了这样,尝试找一下其中是否存在规律.
invoke-static原是35c格式的,如果要写出原指令的字节码,应是(我的图做得好烂啊hhhhh):

有没有发现有点眼熟?忽视掉用于对齐的垃圾数据:

除了opcode变成了二字节的vmcode,其他数据简直一模一样!
所以这条invoke指令也就被还原了:
- invoke-static {v0, v1}, Lcom/albert/xchatkit/d;->b(Ljava/lang/String;Ljava/lang/String;)V
复制代码
后面的指令根据trace大概看了下,和上述逻辑均相同,都是由标准结构塞入一些对齐数据来魔改的,本质和标准结构类似.
这里给出trace、vm字节码以及还原对照:
第四条指令:
trace:
- Memory READ at 0x120f24d0, data size = 8, data value = 0x0000000012044d90, PC=RWX@0x1202e93c[libdexjni.so]0x2e93c, LR=RWX@0x12051cfc[libdexjni.so]0x51cfc
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1204f910[libdexjni.so]0x4f910, LR=RWX@0x12051cfc[libdexjni.so]0x51cfc
- Memory READ at 0x134d1080, data size = 8, data value = 0x000000003bd94634, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1205f96c[libdexjni.so]0x5f96c
- Memory READ at 0x134d1088, data size = 8, data value = 0x0000000074294adb, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1098, data size = 8, data value = 0x0000000017baae6e, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- g_method_list2:0x40
- JNIEnv->FindClass(android/app/Activity) was called from RWX@0x1205f990[libdexjni.so]0x5f990
- JNIEnv->FindClass(java/lang/Class) was called from RWX@0x1205f9ac[libdexjni.so]0x5f9ac
- JNIEnv->GetMethodID(java/lang/Class.isInterface()Z) => 0x789061df was called from RWX@0x1205f9d0[libdexjni.so]0x5f9d0
- JNIEnv->CallBooleanMethodV(class android/app/Activity, isInterface() => true) was called from RWX@0x12018df0[libdexjni.so]0x18df0
- JNIEnv->GetMethodID(android/app/Activity.onCreate(Landroid/os/Bundle;)V) => 0x2f2ecda8 was called from RWX@0x1204adc4[libdexjni.so]0x4adc4
- Memory READ at 0x134d1098, data size = 8, data value = 0x0000000017baae6e, PC=RWX@0x1202b0b8[libdexjni.so]0x2b0b8, LR=RWX@0x1204adc4[libdexjni.so]0x4adc4
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1204e57c[libdexjni.so]0x4e57c, LR=RWX@0x1204adc4[libdexjni.so]0x4adc4
- JNIEnv->CallNonVirtualVoidMethodA(android.app.Activity@43d7741f, android/app/Activity, onCreate(android.os.Bundle@17baae6e)) was called from RWX@0x12055d44[libdexjni.so]0x55d44
复制代码- 字节码:54 B3 20 00 40 00 82 5E 32 00 D7 FA
- 0xb354 -> opcode:invoke-super
- 0x(00)20 -> registerCount=2, regG=0
- 0x0040 -> g_method_list2 idx[android/app/Activity.onCreate(Landroid/os/Bundle;)V]
- 0x5e82 -> padding
- 0x0032 -> regC=2(p0), regD=3(p1), regE=0, regF=0
- 0xfad7 -> padding
- Smali:invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V;
复制代码
第五条指令:
trace:
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x120570c8[libdexjni.so]0x570c8, LR=RWX@0x12056044[libdexjni.so]0x56044
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1205da04[libdexjni.so]0x5da04, LR=RWX@0x12056044[libdexjni.so]0x56044
- Memory READ at 0x134d1080, data size = 8, data value = 0x000000003bd94634, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x12062f18[libdexjni.so]0x62f18
- Memory READ at 0x134d1088, data size = 8, data value = 0x0000000074294adb, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1098, data size = 8, data value = 0x0000000017baae6e, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- g_method_list2:0x3a
- JNIEnv->FindClass(android/app/Activity) was called from RWX@0x12062f3c[libdexjni.so]0x62f3c
- JNIEnv->GetMethodID(android/app/Activity.getWindow()Landroid/view/Window;) => 0x4333f814 was called from RWX@0x120327b4[libdexjni.so]0x327b4
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x12055a5c[libdexjni.so]0x55a5c, LR=RWX@0x1204bc14[libdexjni.so]0x4bc14
- JNIEnv->CallObjectMethodA(android.app.Activity@43d7741f, getWindow() => android.view.Window@130f889) was called from RWX@0x1205ee14[libdexjni.so]0x5ee14
复制代码- 字节码:4D 5B 10 00 3A 00 55 9B 02 00 73 66
- 0x5b4d -> opcode:invoke-virtual
- 0x(00)10 -> registerCount=1, regG=0
- 0x003a -> g_method_list2 idx[android/app/Activity.getWindow()Landroid/view/Window;]
- 0x9b55 -> padding
- 0x0002 -> regC=2(p0), regD=0, regE=0, regF=0
- 0x6673 -> padding
- Smali:invoke-virtual {p0}, Landroid/app/Activity;->getWindow()Landroid/view/Window;
复制代码
第六条指令:
trace:
- Memory READ at 0x12116fa8, data size = 8, data value = 0x000000001205cba4, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
- Memory WRITE at 0x134d1098, data size = 8, data value = 0x000000000130f889, PC=RWX@0x12049f68[libdexjni.so]0x49f68, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
复制代码- 字节码:AF FC 03 00
- 0xfcaf -> opcode:move-result-object
- 0x0003 -> reg=3(p1)
- Smali:move-result-object p1
复制代码
第七条指令:
trace:
- Memory READ at 0x120aba20, data size = 8, data value = 0x0000000012064fd8, PC=RWX@0x12064ae8[libdexjni.so]0x64ae8, LR=RWX@0x12049f78[libdexjni.so]0x49f78
- Memory WRITE at 0x134d1080, data size = 8, data value = 0x0000000000280400, PC=RWX@0x12035028[libdexjni.so]0x35028, LR=RWX@0x12049f78[libdexjni.so]0x49f78
复制代码- 字节码:FE 25 00 00 00 04 5B CE 28 00 FD 58
- 0x25fe -> opcode:const
- 0x(00)00 -> reg=0(v0)
- 0x0400 -> low 16 bits
- 0xce5b -> padding
- 0x0028 -> high 16 bits
- 0x58fd -> padding
- Smali:const v0, 0x00280400
复制代码
第八条指令:
trace:
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x12053570[libdexjni.so]0x53570, LR=RWX@0x12049f78[libdexjni.so]0x49f78
- Memory READ at 0x134d1098, data size = 8, data value = 0x000000000130f889, PC=RWX@0x1205da04[libdexjni.so]0x5da04, LR=RWX@0x12049f78[libdexjni.so]0x49f78
- Memory READ at 0x134d1080, data size = 8, data value = 0x0000000000280400, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x12062f18[libdexjni.so]0x62f18
- Memory READ at 0x134d1088, data size = 8, data value = 0x0000000074294adb, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1098, data size = 8, data value = 0x000000000130f889, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- g_method_list2:0x301
- JNIEnv->FindClass(android/view/Window) was called from RWX@0x12062f3c[libdexjni.so]0x62f3c
- JNIEnv->GetMethodID(android/view/Window.addFlags(I)V) => 0x3448735f was called from RWX@0x120327b4[libdexjni.so]0x327b4
- Memory READ at 0x134d1080, data size = 8, data value = 0x0000000000280400, PC=RWX@0x1202ed4c[libdexjni.so]0x2ed4c, LR=RWX@0x1204bc14[libdexjni.so]0x4bc14
- Memory READ at 0x134d1098, data size = 8, data value = 0x000000000130f889, PC=RWX@0x12055a5c[libdexjni.so]0x55a5c, LR=RWX@0x1204bc14[libdexjni.so]0x4bc14
- JNIEnv->CallVoidMethodA(android.view.Window@130f889, addFlags(0x280400)) was called from RWX@0x1205eec8[libdexjni.so]0x5eec8
复制代码- 字节码:4D 5B 20 00 01 03 F5 4D 03 00 E5 23
- 0x5b4d分析前面已经给出
- Smali:invoke-virtual {p1, v0}, Landroid/view/Window;->addFlags(I)V
复制代码
第九条指令:
trace:
- Memory READ at 0x120c6498, data size = 8, data value = 0x00000000120651c0, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1205da04[libdexjni.so]0x5da04, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
- Memory READ at 0x134d1080, data size = 8, data value = 0x0000000000280400, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x12062f18[libdexjni.so]0x62f18
- Memory READ at 0x134d1088, data size = 8, data value = 0x0000000074294adb, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- Memory READ at 0x134d1098, data size = 8, data value = 0x000000000130f889, PC=RWX@0x1206e2fc[libdexjni.so]0x6e2fc, LR=RWX@0x1206e308[libdexjni.so]0x6e308
- g_method_list2:0x2d
- JNIEnv->FindClass(android/app/Activity) was called from RWX@0x12062f3c[libdexjni.so]0x62f3c
- JNIEnv->GetMethodID(android/app/Activity.finish()V) => 0xa8352854 was called from RWX@0x120327b4[libdexjni.so]0x327b4
- Memory READ at 0x134d1090, data size = 8, data value = 0x0000000043d7741f, PC=RWX@0x12055a5c[libdexjni.so]0x55a5c, LR=RWX@0x1204bc14[libdexjni.so]0x4bc14
- JNIEnv->CallVoidMethodA(android.app.Activity@43d7741f, finish()) was called from RWX@0x1205eec8[libdexjni.so]0x5eec8
复制代码- 字节码:4D 5B 10 00 2D 00 48 1E 02 00 1C 66
- 0x5b4d分析前面已经给出
- Smali:invoke-virtual {p0}, Landroid/app/Activity;->finish()V
复制代码
第十条指令:
trace:
- Memory READ at 0x120bc770, data size = 8, data value = 0x0000000012065708, PC=RWX@0x12052584[libdexjni.so]0x52584, LR=RWX@0x1205f1cc[libdexjni.so]0x5f1cc
复制代码- 字节码:A8 47 F4 62
- 0x47a8 -> opcode:return-void
- 0x62f4 -> padding
- Smali:return-void
复制代码
所以这个函数还原下来就是:
- const-string v0, "BlankActivity"
- const-string v1, "onCreate"
- invoke-static {v0, v1}, Lcom/albert/xchatkit/d;->b(Ljava/lang/String;Ljava/lang/String;)V
- invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V;
- invoke-virtual {p0}, Landroid/app/Activity;->getWindow()Landroid/view/Window;
- move-result-object p1
- const v0, 0x00280400
- invoke-virtual {p1, v0}, Landroid/view/Window;->addFlags(I)V
- invoke-virtual {p0}, Landroid/app/Activity;->finish()V
- return-void
复制代码
因为所选函数本身比较简单,所以还原起来并不复杂,如果包含一些跳转指令的话也许会复杂一些,不过大概原理应该就是这些啦.
总结
整个运行流程还是比较常规的,解压释放text代码段,JNI_OnLoad初始化全部vm数据并注册跳板函数,跳板函数通过idx查数据进行一些初始化进入解释器解释执行.
比较有意思的就是vm的字节码进行了一些魔改,好像每个指令长度都变成了之前的两倍(不确定,但帖子中见到的都符合),添加了很多用于对齐的随机数据,是我见到的第一个魔改了指令结构的dex vmp.
大概是对这个vmp的整体进行了一通简单的分析,不过因为控制流以及自身能力的缘故,可能有很多东西我没能看到,就交给其他大佬来作补充吧~
|
-
查看全部评分
总评分:好评 +6
金币 +10
|