目录:
一.思路整理 二.某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字节码
[注意]看雪招聘,专注安全领域的专业人才平台!
最后于 2021-12-16 18:02
被爱吃菠菜编辑
,原因: