点击上方蓝字关注我哦
前情提要
qian qing ti yao
所有关于脱壳相关信息的汇总版
1.动态加载
这种动态加载技术不足之处在于:1.这一解压释放机制就给攻击者留下直接获取对应文件的机会;2.可以通过hook虚拟机关键函数,进行dump出原始的dex文件数据。
2.不落地加载
文件级别的加解密技术主要有两种实现方案:1.通过拦截系统的IO相关函数,在这些系统的函数中进行透明加解密。2.直接调用虚拟机提供的函数,进行不落地的加载。
3.指令抽取
这一指令抽取技术的不足之处在于:1.使用大量的虚拟机内部结构,会出现兼容性问题;2.使用android虚拟机进行函数内容的执行,无法对抗自定义虚拟机;3.它跟虚拟机的JIT优化出现冲突,达不到最佳的性能表现。
4.指令转换
它主要通过实现自定义Android虚拟机的解释器,由于自定义解释器无法对Android系统内的其他函数进行直接调用,所有必须使用java的jni接口进行调用。
1.dex文件内的函数被标记为native,内容被抽离并转换为一个符合jni要求的动态库。2.dex文件内的函数被标记为native,内容被抽离并转换为自定义的指令格式。并通过实现自定义接收器,进行执行代码。它主要通过虚拟机提供的jni接口和虚拟机进行交互。
5.虚拟机源码保护
通过利用虚拟机技术保护App中的所有代码,包括java、Kotlin、C/C++等多种代码,虚拟机技术主要是通过把核心代码编译成中间的二进制文件,随后生成独特的虚拟机源码,保护执行环境和只有在该环境下才能执行的运行程序。通过基于llvm工具链实现ELF文件的vmp保护。通过虚拟机保护技术,让ELF文件拥有独特的可变指令集,大大提高了指令跟踪,逆向分析的强度和难度。
6.dex2c
编译原理 , 通过 词法 句法 分析 , 将 Java 代码 进行了 等价的语义转换 , 转为了 C 代码 , 基本无法完全恢复为 Java 代码 ;
区别
1.如果函数是 非 Native 函数 , 并且 函数体 无效 , 说明这是 函数抽取 加壳 ;
2.如果函数是 Native 函数 , 说明这是 VMP 加壳 或者 Dex2C 加壳 ;
3.函数的 注册地址相同 , 并且 函数逻辑相似 , 则使用的是 VMP 加壳 ;
4.函数的 注册地址不同 , 并且 函数逻辑不相似 , 则使用的是 Dex2C 加壳 ;
7.混合加固
Dex2C与VMP
Dex2C与ollvm
指令混淆的方案,结合 VMP
Android启动流程:
加载BootLoader --> 初始化内核 --> 启动init进程 --> init进程fork出Zygote进程 --> Zygote进程fork出SystemServer进程
app启动流程
ActivityThread启动流程
初始化————>Application的构造函数————>Application.attachBaseContext()————>Application.onCreate()函数
App加载应用解析
① BootClassLoader加载系统核心库。
② PathClassLoader加载APP自身dex。
③ 进入APP自身组件,解析AndroidManifest.xml,然后查找Application代理。
④ 调用声明Application的attachBaseContext()对源程序进行动态加载或解密。
⑤ 调用声明Application的onCreate()对源程序进行动态加载或解密。
⑥ 进入MainActivity中的attachBaseContext(),然后进入onCreate()函数,执行源程序代码。
整体壳加载
1.OpenDexFilesFromOat DexFile::Open DexFile::OpenFile
2.getDexFile()获取到ArtMethod所属的DexFile对象的这种一级间接法-通过Thread的getCurrentMethod()函数首先获取到ArtMethod-getDexFile获取到ArtMethod对象所属的DexFile的二级间接法。
抽取壳
抽取指令流程:
-
解析原始dex文件格式,保存所有方法的代码结构体信息。
-
通过传入需要nop的类名及方法,检索到其代码结构体信息。
-
通过该信息获取方法体中的指令个数和偏移地址,构造相应数量的nop指令,覆盖原始指令。
-
重新计算dex文件的checksum和signature信息,写回头部信息中。
指令还原流程:
-
在native层hook libdvm.so中的系统函数dexFindClass,获取类结构体信息。
-
获取类中所有的方法信息,通过指定方法名进行过滤,获取该方法的代码结构体信息。
-
获取该方法被抽取的指令集,修改方法对应的内存地址为可读属性,还原指令。
vmp壳原理
vmp 是修改 pe文件中的汇编指令为一种 “伪指令” ,这些伪指令被虚拟机引擎解析,代替cpu去执行这些指令(如JVM和.NET),一般一条正常指令会对应多条伪指令(多是些无意义的跳转),所以被 vmp 加壳的程序速度会变慢。
壳加固与脱壳
第一代脱壳法
-
缓存脱壳法:
第一代的某些加固产品,安装包是加密压缩的,安装后回在data/dalvik-cache目录下生成解密的odex文件,这时候只需要获取odex文件进行做为分析的突破点。
-
内存 dump脱壳法
通过工具:IDA Pro + dumpDEX
1、通过/proc/%d/maps获取内存映射
2、在内存中查找关键字 dex.035或dex.036
3、手动dump查找到的数据。
-
动态调试脱壳法
1、通过基于IDA的android_server的代理方式进行附加app。
2、再IDA中下dvmDexFileOpenPartial 断点,确认要dump的起始地址和大小。
3、用ida的脚本方式进行dump出原始数据。
-
HOOK脱壳法
Hook脱壳法一般都是基于frida和xposed这两个框架进行做hook操作的。
这种hook脱壳法:先需要进行分析app应用,找到可以进行hook的函数,
然后在选择用的顺手的、适用的frida或xposed框架进行 hook。
(xposed是java编译,适用于java层hook;frida适用于java层和native层hook)。
通过对关键函数dvmDexFileOpenPartial进行hook实现脱壳。
也可以通过xposed框架hook ClassLoader的loadClass函数实现脱壳。
第二代抽取脱壳法
类加载之前恢复 : 在类加载到内存之前 , 将之前抽取出来的指令 恢复 回去 ; ( 比较简单 ) ;
运行时恢复 : 函数运行时 , 通过 HOOK 修改运行时的函数的指令逻辑 ;
AppSpear搜集内存中的运行时Dalvik数据结构(Dalvik Data Structure,以下简称DDS)来重新组装一个正常的Dex文件。
DexHunter是在Android系统代码调用函数dvmDefineClass(Dalvik下的函数)进行类加载之前,主动地一次性加载并初始化Dex文件所有的类。
Fupk3首先遍历gDvm中的dvmUserDexFiles结构,获取所有cookie; 其次对内存中的Dex文件,遍历触发函数,并通过在解析器处插桩,截取解密后的code_item,获取code_item后直接返回不执行该函数。
Fart的脱壳点①初始化函数<clinit> - Execute => dumpDexFileByExecute
②其他正常函数=> DexFile_dumpMethodCode => myfartInvoke => Invoke => dumpArtMethod
手动:
函数抽取壳
frida dex dump或者maps寻找dex
nop填充修复 dump dex内存
修复dex:elf-dump-fix
绕过checksum:jadx-gui -Pdex-input.verify-checksum=no XXX.dex
dex checksum修复:
so解密
等管理 app 运行后,从内存中 dump 出来 so 文件,dump 使用的工具仍是 elf-dump-fix
第三代vmp脱壳
(1)定位VMP字节码
codeitem获取
(1) 已知明文
已知调用方法:
onCreate()
(2) 沙箱日志获取切入点
调用序列追踪入参
(3) JNI参数回溯
调用方法-最早入参点的内存
(4) 内存访问统计
最早入参点的内存来源-针对此处查询访问-寻找第一条指令
(5)分割VMP字节码
一般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)
(6)还原成SMALI
感谢网上各位大哥的分享
白嫖信息不容
如有侵权请联系我
方便的话扫下方二维码关注
原文始发于微信公众号(SQ安全渗透):脱壳姿势大全-汇总版
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论