文章目录
参考: https://www.jb51.net/article/133834.htm
1. 动态加载
动态加载是Dex加壳、插件化、热更新的基础
比如阿里的AndFix和HotFix,腾讯的tinker、美团的Robust等热修复框架的基础
什么是动态加载? 为什么要动态加载?
动态加载就是用到的时候再去加载,也叫懒加载,也就意味着用不到的时候不会去加载。
2. ClassLoader修正
动态加载的dex不具备生命周期特征,App中的Activity、Service等组件无法正常工作,只能完成一半函数的调用;
需要对ClassLoader进行修正,App才能够正常运行,两种修正手段;
解决手段1:反射替换成DexClassLoader
修改系统组件类的ClassLoader(mClassLoader),通过反射的方式进行替换,替换成DexClassLoader.
解决手段2:插入DexClassLoader
在PathClassLoader和BootClassLoader中间插入DexClassLoader(双亲委派)
3. 壳史
第一代壳 Dex加密
Dex字符串加密资源加密对抗反编译反调试自定义DexClassLoader
第二代壳 Dex抽取与So加固
对抗第一代壳常见的脱壳法Dex Method代码抽取到外部(通常企业版)Dex动态加载So加密
第三代壳 Dex动态解密与So混淆
Dex Method代码动态解密So代码膨胀混淆对抗之前出现的所有脱壳法
第四代壳 arm vmp(未来)
vmp壳的识别
4.用加固厂商特征:
娜迦: libchaosvmp.so , libddog.solibfdog.so
爱加密:libexec.so, libexecmain.so
梆梆: libsecexe.so, libsecmain.so , libDexHelper.so
360:libprotectClass.so, libjiagu.so
通付盾:libegis.so
网秦:libnqshield.so
百度:libbaiduprotect.so
5. 加壳技术发展
Dex的加固技术发展
1、 dex整体加固:文件加载和内存加载
2、 函数抽取:在函数粒度完成代码的保护
3、 VMP和DEX2C:Java函数Native化
so加固的种类
1、 基于init、init_array以及JNI_Onload函数的加壳
2、基于自定义linker的加壳
6. 加壳技术的识别
整体加固是基础,所有加壳的app必然都有!关键是在于怎么区分函数抽取、VMP以及dex2c甚至是多种技术混合的混合型壳
函数抽取
获取到保护的dex后,函数体的内容是无效的,注意这里说的是无效,而不是无意义。有的app加壳后函数亦然是有意义的,但不是我们想要的;
VMP
获取到保护的dex后,函数的属性由Java属性变为native,典型的由数字的onCreate函数Native化
Dex2C
对Java函数进行语义分析后生成C/C++代码,生成相应的so文件。
如何快速区分apk所采用的保护技术?
是否Native化 | 函数体无效 | |
---|---|---|
函数抽取类壳 | × | √ |
VMP壳 | √ | native化 |
Dex2C壳 | √ | native化 |
如何区分VMP和Dex2C?
注册地址是否相同 | 函数逻辑是否相似 | |
---|---|---|
VMP壳 | √ | √ |
Dex2C壳 | × | × |
7. 各种壳的解决方案
Dex整体加壳的基础防护
1、文件加载:定位解密文件是关键
2、内存加载: 加载的时候和内存起始地址是关键
通用方案:dex打开和优化的流程以及产出的odex、dex2oat编译的流程和生成的oat文件等等
函数抽取是中阶防护
1、类加载和函数执行前的流程解密
2、函数执行中动态自解密
方案:关注被抽取的函数的执行流程是关键! 定位被抽取函数的恢复时机即可!
VMP和dex2c是高级防护
1、VMP:定位解释器是关键,找到映射关系即可恢复;
2、dex2C: 基础是编译原理,进行了等价语义转换,彻底还原难度巨大;
通用解决方案:关注JNI相关的api调用是关键,也是分析VMP和dex2c保护的函数的逻辑的关键;