Android软件加固概述
从2012年开始,移动互联网进入快速发展阶段,Android App开发热潮的兴起,也推动了Android平台软件保护技术的发展。
- 为何做加固
加固代际
根据不同的理解,现在加固代际基本上可以按照五代或者三代去区分。
第一代:动态加载类
原理
-
落地加载
我们拿到需要加密的Apk和自己的壳程序Apk,然后用加密算法对源Apk进行加密再将壳Apk进行合并得到新的Dex文件,最后替换壳程序中的dex文件即可,得到新的Apk,那么这个新的Apk我们也叫作脱壳程序Apk.他已经不是一个完整意义上的Apk程序了,他的主要工作是:负责解密源Apk.然后加载Apk,让其正常运行起来。运行时首先将我们的Dex文件或者Apk文件解密,然后利用DexClassLoader加载器将其加载进内存中,然后利用反射加载待加固的Apk的Appkication,然后运行待加固程序即可。
-
不落地加载
落地加载将Dex文件解密出来会保存到文件中,再通过DexClassLoader加载进内存中,而不落地加载直接重写DexClassLoader使其可以直接加载字节数组,避免写入文件中。我们要做的是重写DexClassLoader,而这涉及到三个函数defineClass、findClass、loadClass,在一个类被加载的时候,会先后调用这三个函数加载一个类,所以我们需要重写这三个函数。系统的DexClassLoader加载Dex进入内存的也必然是通过字节加载的,而在系统so中的libdvm.so中的openDexFile可以直接加载Dex文件,那么现在清楚了,我们可以通过编写so文件调用openDexFile函数加载Dex字节数组,值得注意的是,openDexFile函数返回值为一个int类型的cookie,可以简单理解成一个dex文件的’身份码’,通过该’身份码’即可操控这个dex文件,至于怎么调用该函数,可以通过dlopen和dlsym函数调用。
优劣
特点
Dex字符串加密 资源加密 对抗反编译 对抗调试 Dex动态加载 so加密
第二代:函数抽取类
原理
- 指令抽取
解析原始Dex文件格式,保存所有方法的代码结构体信息,通过传入需要置空指令的方法和类名,检索到其代码结构体信息。通过方法的代码结构体信息获取指令个数和偏移地址,构造空指令集,然后覆盖原始指令,重新计算dex文件的checksum和signature信息,回写到头部信息中。
- 指令还原
native层hook系统函数dexFindClass,获取类结构体信息(dexFindClass函数用于查找类的DexClassDef结构),获取类中所有的方法信息,通过指定方法名进行过滤,获取该方法的代码结构体信息,获取该方法被抽取的指令集,修改方法对应的内存地址为可读属性,直接进行指令还原。
优劣
-
优点
加密粒度变小,加密技术从Dex文件级变为方法级 按需解密,解密操作延迟到某类方法被执行前,如果方法不被执行,则不被解密 解密后的代码在内存不连续,克服了内存被Dump的缺点,有效保护了移动客户端的Java代码 -
缺点
使用大量的虚拟机内部结构,会出现兼容性问题,无法保护所有方法 无法对抗自定义虚拟机 它跟虚拟机的JIT优化出现冲突,达不到最佳的性能表现
特点
除一代有的特点外 内存中无完整、连续的Dex so代码混淆、膨胀
第三代:VMP、Dex2C类
原理
再比如更改关键方法的方法体
无论哪种方法其实都是为了能让壳函数代替原函数去执行 当执行该函数的指令时,解析出指令的OpCode,通过一个巨大的switch case找到处理对应OpCode的函数,然后执行
简单讲就是壳将原本的指令进行一次封装,将原本的指令转换为另一种表现形式
- Dex2C
首先也是将关键代码注册为native函数,主要借助于JNI反射技术,将Java层的方法全部反射为native层,增大分析难度。之后再通过混淆、字符串加密等操作生成so,最后将so进行加固保护。
优劣
特点
除一、二代全部特点外 so代码虚拟化 对抗之前所有的脱壳方法
so加密
section加密
- 原理
将关键方法,存放在自定义的section中,通过解析每个section,将我们自定义的section进行加密。因为so在加载时会优先加载.init_array,所以将解密方法放在.init_array中,获取内存中各个section的起始地址和大小,将需要解密的section还原。
函数加密
特点
由于原本的指令已经被加密成其他的字节,IDA等静态分析工具中会出现大段无法识别的代码
各厂商特征
某梆
lib/libDexHelper.so、lib/libDexHelper-x86.so、
某加密
assets/ijiami.ajm、assets/ijiami.dat、assets/ijm_lib/libexec.so、assets/ijm_lib/libexecmain.so
某企鹅
lib/libshell–super.2019.so、lib/libshella-4.1.0.29.so
某数字
assets/libjiagu.so、assets/libjiagu_x86.so
某迦
assets/libvdog、assets/libvdog64、assets/libvdog-x86
某付盾
lib/libegis.so、lib/libegis-x86.so
脱壳工具
FRIDA-DEXDump
原理
通过Frida在内存中搜索dexn035,因为Dex的头部都会存在一个dexn035的模数,所以通过在内存中搜索dexn035可以搜索到Dex文件。对于一些Dex它们被抹去了头部信息,对于这样的情况,FRIDA-DEXDump也提供了对应的方法,通过遍历当前进程中所有可以读的内存段,通过判断这个段的大小和Dex文件中一些关键区域的关系可以判断是否为一个Dex。
使用
在FRIDA-DEXDumpGitHub中下载代码到本地或者通过pip3 install frida-dexdump
安装
用法就是首先打开,我们需要脱壳的软件,然后执行python main.py -d
程序执行开始检索内存中的Dex
也可以通过python main.py -h
查看它的其他使用方法
最终得到它脱出来的Dex,可以看下它脱壳效果
Youpk
原理
从ClassLinker中遍历所有DexFile对象,在虚拟机中Dex文件都用DexFile对象来表示,并Dump出所有Dex文件。此时只是整体Dump,Dex中的方法还未还原。遍历DexFile中的ClassDef结构,获取到所有Class,主动调用Class中的所有的方法,让程序强制走switch解释器执行,在解释器中添加Hook代码,当方法执行时自动保存CodeItem。根据保存的CodeItem和Dump下来的Dex进行合并,还原Dex中被抽取的指令。
使用
解压相关的镜像,fastboot flash xxx /Download/xxx.img
依次刷入
配置待脱壳的App包名adb shell "echo com.xxx >> /data/local/tmp/unpacker.config"
启动Apk等待脱壳,每隔10秒将自动重新脱壳(已完全dump的dex将被忽略), 当日志打印unpack end时脱壳完成
dump文件路径为/data/data/包名/unpacker,使用adb命令将文件pull出
使用dexfixer.jar修复Dex,java -jar dexfixer.jar /path/unpacker /path/output
还原前
还原后
总结
本文简单地总结了一下Android加固的背景和发展历史,也介绍了一些目前常见的脱壳工具。对于so加密的情况,目前也有许多方法应对,比如ida动态调试dump内存中的so,GG模拟器dump内存,frida dump so,unidbg等等。对于混淆的so,也有jnitrace,unidbg,还有hluwa大佬的大作obpo等工具辅助我们分析。除此以外还有还有一些优秀的脱壳工具如Fart等,我也没有再做介绍了。总之感谢这些大佬们的努力和开源,没有你们就没有白嫖的我们,哈哈…
原文地址:https://blog.csdn.net/u010671061/article/details/134454805
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_27322.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!