某DEX_VMP安全分析与还原

VSole2022-01-16 16:40:28

思路整理

还原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指令反汇编过程

由于使用了已知明文条件作为切入点,已知分析目标ZxWebViewActivity.onCreate()中,必定会调用startTracing()方法,

即必定存在invoke-static {v0}, method@00da6f // ...startTracing

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

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

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

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

(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) 被VMP的方法内部存在已知明文指令。

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

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

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

深入VMP还原的一些问题

略。

调试与工具总结

核心问题:

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

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

① GDB调试

② FridaStalker编译执行

③ 脱机unicorn模拟执行

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

① IDA / GDB

速度极慢,且会遭遇反调试。

② FridaStalker

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

③ PC上脱机unicorn模拟执行

vmp.so中存在大量jni call和system call,需要手动实现它们,unicorn才能完成运行。

基于以上问题的尝试:

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

基于trace进行离线分析:

① trace形态可视化

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

② 基本的分析

地址含义解析 调用符号识别

③ 程序分析

污点分析 相似性分析等

 

字节码汇编指令
本作品采用《CC 协议》,转载必须注明作者和本文链接
文中使用的示例代码可以从 这里 获取。的功能是在终端打印出hello这6个字符(包括结尾的?编译它们分别生成libtest.so和?存在严重的内存泄露问题,每调用一次say_hello函数,就会泄露1024字节的内存。
汇编语言是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。Smali汇编基础Smali语言最早是由JesusFreke发布在Google Code上的一个开源项目,并不是拥有官方标准的语言。因此也将Smali语言称作Android虚拟机的反汇编语言。基本类型Smali基本数据类型中包含两种类型,原始类型和引用类型。而在Smali中则是以LpackageName/objectName的形式表示对象类型。
前言最近一段时间在研究Android加壳和脱壳技术,其中涉及到了一些hook技术,于是将自己学习的一些hook技术进行了一下梳理,以便后面回顾和大家学习。主要是进行文本替换、宏展开、删除注释这类简单工作。所以动态链接是将链接过程推迟到了运行时才进行。
结果分析Hook前Hook后,我们的弹窗本该是hello的但是hook后,程序流程被我们修改了。760D34B2 55 push ebp760D34B3 8BEC mov ebp,esp通过这两条指令,函数就可以在堆栈中为局部变量分配存储空间,并在函数执行过程中保存和恢复现场。这样做的好处是可以避免局部变量和其他函数之间的冲突,同时也可以提高函数的可读性和可维护性。
Frida工作原理学习
2022-07-12 16:28:29
frida是一款便携的、自由的、支持全平台的hook框架,可以通过编写JavaScript、Python代码来和frida_server端进行交互,还记得当年用xposed时那种写了一大堆代码每次修改都要重新打包安装重启手机、那种调试调到头皮发麻的痛苦,百分之30的时间都是在那里安装重启安装重启。
系统安全第44篇介绍经典的静态特征提取工具CAPA,希望对您有所帮助
BPF之路二(e)BPF汇编
2021-12-28 16:18:32
原始的BPF又称之为class BPF(cBPF), BPF与eBPF类似于i386与amd64的关系
VMPWN的入门系列-1
2023-07-27 09:45:00
今天的文章有点长,图片比较多,请耐心阅读5.1 实验一 VMPWN15.1.1 题目简介这是一道基础的VM相关题目,VMPWN的入门级别题目。
vmp 相关的问题
2021-11-19 16:58:50
为新版本的符合一个叫做寄存器轮转的问题所以他可能jmp ebp,jmp edi等等的。
如果要反汇编成smali,起码要知道这条smali对应的字节一共几个字节。在确定一条指令占几个字节后,还要知道这几个字节中,谁是操作码,谁是操作数。有了前两步铺垫,最终我们可以解读一条完整的smali的含义。
VSole
网络安全专家