首页
社区
课程
招聘
[原创] 某DEX_VMP安全分析与还原
2021-12-16 14:55 39355

[原创] 某DEX_VMP安全分析与还原

2021-12-16 14:55
39355

目录:

一.思路整理
二.某VMP入口特征
三.定位VMP字节码
四.分割VMP字节码
五.还原为SMALI
六.攻击面总结
七.深入VMP还原的一些问题
八.调试与工具总结

一.思路整理

还原VMP需要哪些铺垫?

(1)定位VMP字节码
(2)分割VMP字节码
(3)还原成SMALI

(1)为什么要找VMP字节码的位置?

因为如果目标方法的字节码地址,都找不到,还原也就没法展开了.

 

(2)为什么要分割VMP字节码?

如果要反汇编成smali,
起码要知道这条smali对应的字节码一共几个字节.

在确定一条指令占几个字节后,
还要知道这几个字节中,
谁是操作码,谁是操作数.

 

(3)还原为SMALI

有了前两步铺垫,最终我们可以解读一条完整的smali的含义.

 

二.某安卓VMP入口特征(2021.8月样本)

跳板方法

 

进入native后的参数处理逻辑

 

为了处理不同类型的返回值, 定义了多个jni方法

 

对应jni函数入口指令情况

 

三.定位VMP字节码

逻辑

根据上述逻辑,则一定存在函数F,向F输入index可得到对应codeitem_addr
F(index) == codeitem_addr

我们看一下这个函数,从index到codeitem_addr的过程
(0x2dce->0xcac85880)

 

 

如何在十几万数量级的汇编中定位到这段代码的?

通过Trace记录REG信息,
用到了两个关键数值,0x2dce(index)与0xcac85880(codeitems),
标记两个数值出现的中间区间即可.

 

 

展开上面的定位方式的两个前提条件:

我们已经有了关键数据0x2dce,但还需要知道另一个提前条件,
即codeitem是0xcac85880,所以这个信息是从哪得知的?
这里是本章的关键.

如何分析出codeitem的地址是0xcac85880?

(1) 已知明文
(2) 沙箱日志获取切入点
(3) JNI参数回溯
(4) 内存访问统计

(1)已知明文

目标APP内很多的onCreate()方法,其内部普遍调用了,
NBSTraceEngine.startTracing();以及super.onCreate()

 

我们选一个被vmp保护了的onCreate()作为分析目标, ZxWebViewActivity.onCreate()

(2) 沙箱日志获取切入点

① ZxWebViewActivity.onCreate内必定存在NBSTraceEngine.startTracing();以及super.onCreate()
② startTracing为静态方法,会被编译器编译为invoke-static
③ super.onCreate()为超类调用,会被编译器编译为invoke-super
④我们猜测vmp对invoke-static模拟实现借助了JNI函数,
所以我们触发ZxWebViewActivity.onCreate()执行,截取其调用序列,效果如下:

 

大致逻辑为

 

 

(3) JNI参数startTracing来源回溯

我们在trace中找到这条GetStaticMethodID()的出现位置,
然后作为起点向上展开回溯,希望找到其参数”startTracing”的最早出处,
如果有自动化的脚本和条件可进行污点分析,由于逻辑不是很复杂,这里人工回溯完成.

 

具体过程省略……
在trace中对参数”startTracing”来源进行一番回溯,
最终发现了一个起到决定性作用的偏移值0x000081de.
可以简单理解成,它以base+0x000081de的形式确立的参数”startTracing”.

结论:
如果0x000081de是那个起到决定性意义的数值,
那么毫无疑问0x000081de来自codeitem.

在trace中找到0x81de的出现位置,
发现它来自于内存位置0xcac858a8.

 

(4) 内存访问统计

0x81de来自0xcac858a8,
由于这个地址可能是codeitem,
因此我们检索一下,trace中对这片内存区域的访问情况
0xcac858a8取前5个高位,忽略后3个地位,即检索对0xcac85???的访问

 

找到19条指令, 而对0xcac85???的访问,最早的第一条指令,出现在编号5691的位置,
对应的内存地址为0xcac85890,说明这里是ZxWebViewActivity.onCreate()第一条字节码.

由于codeitem第一条字节码之前0x10个字节还存在一些固定内容,
所以0xcac85890-0x10取得codeitem地址0xcac85880,
即codeitem的地址是0xcac85880

 

 

四.分割VMP字节码

现在已经有了某厂vmp codeitems全部内容,
但是还没法反汇编成smali,

因为还不知道,
第一条指令一共占几个字节,
第二条指令一共占几个字节,
依次......

dalvik指令是不等长,
反汇编成smali的话,
起码要知道这条smali对应的字节码一共几个字节
在知道了每条指令占几个字节后,
还要知道这几个字节中,
谁是操作码,谁是操作数.

通过观察codeitem的内存段的读取情况,可以达到这个目的

 

如何快速区分出操作码和操作数?

一般opcode后面会有一个EOR解密指令,
以及一串类似定位handle的CMP指令操作,
而operand没有,这就为区分opcode和operand提供了特征依据.

 

opcode解密逻辑?

由eor指令向上回key出现的位置,
即可确定key的来源,
以及解密逻辑.

大致逻辑:
off1 = sub( codeitem当前指令地址, codeitem基址 )
off2 = lsl( off1, 1)
key = load( base + off2 )
de_opcode = xor(en_opcode, key)

五.VMP字节码还原为SMALI

1 标准dalvik指令反汇编过程
2 VMP指令反汇编过程
3 还原VMP所有指令需要什么?
4 没有opcode对照表时,如何展开还原?

1 标准dalvik指令反汇编过程

 

2 VMP指令反汇编过程

由于使用了已知明文条件作为切入点,
已知分析目标ZxWebViewActivity.onCreate()中,
必定会调用startTracing()方法,
即必定存在invoke-static {v0}, method@00da6f // ...startTracing

又通过上面的分析得知关键值81de出现在这条invoke-static中,
且充当操作数的角色,那么按照我们按照标准invoke-static反汇编规则进行解析,
就可以得到结论.

 

 

 

 

.

VMP指令由标准指令基础上修改而来,有哪些异同?

 

3 还原VMP所有指令需要什么?

4 没有opcode对照表时如何展开还原?

(1)接口猜测法
(2)参数推导法
(3)标准dalvik指令格式的信息利用
(4)人肉逆向法(略)

(1)接口猜测法

method相关的invoke系列指令,可以通过JNI执行情况猜测.
Field相关的get set系列指令,也可以通过JNI执行情况猜测.

 

(2)参数推导法

方法调用前,会先准备参数,
通常是声明类型的指令,
可以很大程度缩小猜测的候选指令范围.

 

(3)标准dalvik指令格式的信息利用

由于vmp指令是由dalvik标准指令略微修改/变异而来,
只做了较小的改动,仍然保留了BIT位分布特征这样信息.
在做还原时,可以利用这些信息,一定程度缩小候选范围.
https://source.android.com/devices/tech/dalvik/instruction-formats
https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions

六.攻击面总结

1 分析路径
2 攻击面总结 && 启示

1 分析路径

2 攻击面总结 && 启示

(1) 被VMP的方法内部存在已知明文指令.
(2) VMP的实现高度依赖JNI函数,通过HOOK拿到其调用信息,是非常有效的切入点与突破口.
(3) codeitems的连续性,集中存储的特性,通过内存访问统计最终被发现.
(4) vmp指令由标准dalvik指令基础上略改而来,整体仍然保留了很多可用信息,
对于一些内部逻辑比较简单的方法,可以以较小成本还原.

(1) 被VMP的方法内部存在已知明文指令.

(2) VMP的实现高度依赖JNI函数,通过HOOK拿到其调用信息,是非常有效的切入点与突破口.

(3) codeitems的连续性,集中存储的特性,通过内存访问统计最终被发现.

(4)某vmp指令由标准dalvik指令基础上略改而来,整体仍然保留了很多可用信息

七.深入VMP还原的一些问题

八.调试与工具总结

核心问题:

获取程序完整的执行&&数据信息 (trace).

目前公开的主流的获取trace的方案:

1 GDB调试
2 FridaStalker编译执行
3 脱机unicorn模拟执行

主流的获取trace的方案的弊端和缺陷:

1 IDA / GDB:
速度极慢,且会遭遇反调试

2 FridaStalker
不支持arm指令的thumb模式,且BUG多,
遭遇vmp.so中的花指令时,基本无法正常使用.

3 PC上脱机unicorn模拟执行
vmp.so中存在大量jni call和system call,需要手动实现它们,unicorn才能完成运行.

基于以上问题的尝试:

实现原始APP进程环境 && 原始context中,
通过unicorn构造虚拟化CPU,
执行目标function,获得trace,
无已知检测和对抗手段,简单过anti.

基于trace进行离线分析:

1 trace形态可视化
文本 / json / 数据库 / EXCEL可视化表格 / 动态CFG图

2 基本的分析
地址含义解析 调用符号识别

3 程序分析
污点分析 相似性分析等..

 

 

 

 


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2021-12-16 18:02 被爱吃菠菜编辑 ,原因:
收藏
点赞45
打赏
分享
打赏 + 15.00雪花
打赏次数 3 雪花 + 15.00
 
赞赏  hackdaliu   +5.00 2022/07/05 支持大佬
赞赏  pareto   +5.00 2021/12/20 精品文章~
赞赏  orz1ruo   +5.00 2021/12/16 精品文章~
最新回复 (30)
雪    币: 3685
活跃值: (3869)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2021-12-16 16:11
2
0
坐等加精
雪    币: 3488
活跃值: (2862)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
StriveMario 2021-12-16 17:02
3
0
太吊了吧... 掉头发系列
雪    币: 177
活跃值: (5351)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
看雪高研 2021-12-16 17:14
4
0
棒棒的,已经将vmp课程的内容融会贯通,给你个大大的赞
雪    币: 19786
活跃值: (4862)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
浅笑不语 2021-12-16 19:24
5
0
真大佬
雪    币: 3835
活跃值: (4164)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
krash 4 2021-12-16 19:45
6
0
大佬6,excel还能这么用,是我没想到的.
雪    币: 3819
活跃值: (5615)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huangjw 2021-12-16 20:23
7
0
very goods
雪    币: 145
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Ive_406746 2021-12-17 15:09
8
0
牛逼了
雪    币: 163
活跃值: (504)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刘lhhh 2021-12-17 16:25
9
0
厉害了。libjni.so,Fix:Opcode、MethodID、StringID  xxx...... 还是头发要紧点
雪    币: 5350
活跃值: (5354)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
GitRoy 3 2021-12-17 17:36
10
0
整理的太好了,给大佬点赞!
雪    币: 3262
活跃值: (2669)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
xhyeax 2021-12-17 21:11
11
0

学习了,膜拜大佬Orz

最后于 2021-12-18 12:49 被xhyeax编辑 ,原因:
雪    币: 498
活跃值: (3776)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
哆啦噩梦 2021-12-17 22:49
12
0
太肝了,小心头发阿老哥
雪    币: 989
活跃值: (943)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SomeMx 2021-12-18 16:57
13
0
真心厉害  第一次看完了
雪    币: 8283
活跃值: (4811)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
v0id_ 2021-12-18 21:02
14
0
mark
雪    币: 6571
活跃值: (3823)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 4 2021-12-19 09:55
15
0
雪    币: 3879
活跃值: (2291)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_jeivadez 2021-12-20 00:02
16
0
学习了,感谢大佬的教程
雪    币: 623
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_imwmavdj 2021-12-20 00:32
17
0
 大开眼界
雪    币: 4
活跃值: (282)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
程IT龙 2021-12-20 11:06
18
0
分析得非常不错啊,不过往后面还原的路还挺长的。
另外如果 操作码 切换成双 byte,或者 每个包映射随机的情况下,感觉难度又是翻倍了。
同时 数据如果离散化存储 ,难度也会增加。LZ这成片的数据分析功底确实很强!!
雪    币: 461
活跃值: (304)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Youngs 2021-12-20 11:24
19
0
雪    币: 463
活跃值: (2536)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
pareto 2021-12-20 16:52
20
0

1

最后于 2023-2-6 13:40 被pareto编辑 ,原因:
雪    币: 797
活跃值: (1056)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
bambooqj 2021-12-20 21:05
21
0
看不懂但是感觉好流弊
雪    币: 2649
活跃值: (1541)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hhhaiai 2021-12-24 15:16
22
1
雪    币: 62
活跃值: (566)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万里星河 2021-12-27 14:37
23
0
妙不可言
雪    币: 198
活跃值: (548)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
slbwgslz 2021-12-27 15:30
24
0
实现原始APP进程环境 && 原始context中,
通过unicorn构造虚拟化CPU,
执行目标function,获得trace,
无已知检测和对抗手段,简单过anti.  这个是如何实现的 ?
雪    币: 74
活跃值: (1448)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
菜小基 2021-12-30 18:09
25
0
Orz
游客
登录 | 注册 方可回帖
返回