你好,全栈君。以下是重构后的内容:
大家好,我是你们的朋友全栈君。最近我一直在学习Android加固方面的知识,看了不少论文、技术博客以及一些github上的源代码。下面我会总结一下混淆方面的技术,也算是给想学习加固的同学做一些科普。在文中讲到的论文、资料以及源码,我都会给出相应的链接,供大家进一步去深入学习。后面我会弄成一个系列的文章,如有一些混淆技术没讲到,还希望大家指点,当做是交流学习。
二、Android混淆技术介绍
2.1 控制流平坦化
2.1.1 概念和思路
控制流平坦化,就是在不改变源代码的功能前提下,将C或C++代码中的if、while、for、do等控制语句转换成switch分支语句。这样做的好处是可以模糊switch中case代码块之间的关系,从而增加分析难度。
这种技术的思想是,首先将要实现平坦化的方法分成多个基本块(就是case代码块)和一个入口块,为每个基本快编号,并让这些基本块都有共同的前驱模块和后继模块。前驱模块主要是进行基本块的分发,分发通过改变switch变量来实现。后继模块也可用于更新switch变量的值,并跳转到switch开始处。详细的概念可以参考文献[1]。
其模型如下图所示:
下面用代码来说明左边方法是没有采用控制流平坦化之前的效果,右边是采用了控制流平坦化的效果。
2.1.2 开源项目
目前用的最多的是OLLVM(Obfuscator-LLVM)的开源混淆方案。很多国内加固厂商都可以看到使用它的身影。它提供了三种保护方式:控制流平坦化、虚假控制流和指令替换。其项目地址如下:
2.1.3 对抗
目前对于ollvm的反混淆思路多采用基于符号执行的方法来消除控制流平坦化。这里不做详细分析,详细的分析思路可以参考QuarksLab写的文章[3]。
2.2 花指令
2.2.1 概念和思路
花指令也叫垃圾指令,是指在原始程序中插入一组无用的字节,但又不会改变程序的原始逻辑。程序仍然可以正常运行,然而反汇编工具在反汇编这些字节时会出错。由此造成反汇编工具失效,提高破解难度。
花指令是一种反汇编技术,用于防止程序被反编译。当花指令跟正常指令的开始几个字节被反汇编工具识别成一条指令的时候,才可以使得反汇编工具报错。插入的花指令都是一些随机的但是不完整的指令。这些花指令必须要满足两个条件:在程序运行时,花指令是位于一个永远也不会被执行的路径中;这些花指令也是合法指令的一部分,只不过它们是不完整指令而已。
目前反汇编工具所使用的反汇编算法主要分为两类:线性扫描算法和递归扫描算法。线性扫描依次按顺序逐个地将每一条指令反汇编成汇编指令。递归扫描按顺序逐个反汇编指令,如果某个地方出现了分支,就会把这个分支地址记录下来,然后对这些反汇编过程中碰到的分支进行反汇编。显然,递归扫描的算法反汇编能力更强。
标识符混淆就是对源程序中的包名、类名、方法名和变量名进行重命名,用无意义的标识符来替换,使得破解这分析起来更困难。最常用的就是ProGuard开源工具 。
标识符混淆原理:
要了解这个原理,首先需要对dex文件格式有一定了解。dex文件中的类名、方法名和变量名实际上都对应一个string_id的字符串索引。每个类对应一个class_def_item结构体,其中class_idx指向类名的字符串索引。同样,每个方法也对应一个method_id_item的结构体,其中name_idx指向方法名的字符串索引。字段名也一样,对应一个field_id_item的结构体,其中name_idx指向字段名的字符串索引。因此,只需修改相应的string_id索引表中的字符串,即可实现标识符混淆。具体的实现可以参考文章[10],它还提供了一个dex混淆器的简单原型:DexConfuse。
开源项目:
(1) ProGuard
DexConfuse是一个简单的dex混淆器,可以混淆类名、方法名和字段名。APKFuscator作者通过解析修改Dex文件格式,修改类名,使类名字符个数超过255个,从而使得反汇编器报错。
(2) APKFuscator
APKFuscator是一个商业级的APK混淆器,它可以混淆类名、方法名、字段名、资源ID、布局文件等。它的主要特点是在运行时动态修改DEX文件,使其无法被反编译。
对抗:
文献[8]采用的一种反混淆方式是通过大规模的学习为混淆的APK,然后总结出一个概率模型,通过这个概率模型来识别混淆后的代码。其反混淆流程分为3个步骤:
1. 生成一个依赖关系图,每个节点代表要重命名的元素,每条线代表依赖关系。
2. 导出一些限制规则,这些规则可以保证回复的APK是个正常的APK,且和原APK语义相同。
3. 根据概率模型提供的权重,对混淆的元素的原始名称进行预测和恢复。作者将论文中的反混淆方法做成了一个在线的反混淆工具提供使用。
字符串混淆:
为了避免反汇编后的代码容易被破解者分析读懂,往往会对源程序中一些比较关键的字符串变量进行混淆,提高破解者的分析成本。这里的字符串混淆有两种:Java层的字符串混淆和native层的字符串混淆(即so文件中的字符串混淆)。上面我们介绍了Proguard免费混淆工具,它可以混淆类名、方法名和变量名,但不支持字符串混淆。要使用字符串混淆,需要使用DexGuard商业版混淆器。
编码混淆是一种保护程序源代码的技术,它通过将字符串转换成16进制的数组或者Unicode编码,在使用的时候才恢复成字符串。这样破解者在逆向后看到的是一串数字或者乱码,很难直接分析。以下是一些实现编码混淆的方法:
1. 使用apktool反编译后的smali代码进行混淆。
2. 在native层的代码中使用类似的方式实现对C或C++中的字符串进行混淆。
3. 对于Java层的字符串加密,可以在dex文件中找到要加密的字符串在字符串常量表中的位置,然后对它用加密算法加密。然后在自定义Application的attachBaseContext方法中在运行时对密文进行解密,或者可以在native层加密,提高破解难度。
4. 对于SO文件,可以根据section header table来找到”.rodata”的位置和大小,然后实现对只读常量区进行加密混淆,在运行的时候再调用相应的解密算法解密即可。
此外,还有一些开源项目可以用于字符串混淆,如obfuseSmaliText。对于使用了字符串混淆的程序,只能找到响应的解密函数,调用解密函数去解密就可以恢复明文。
在这篇文章中,我们将探讨Android应用程序混淆技术的各个方面。混淆是一种保护移动应用程序免受逆向工程和恶意代码分析的技术。以下是一些关于Android应用程序混淆技术的参考资料:
1. 《Evaluating malwares obfuscation techniques against antimalware detection algorithms》:本文评估了各种恶意软件混淆技术在反恶意软件检测算法下的表现。
2. 《Dalvik Bytecode Obfuscation on Android》:本文介绍了在Android平台上使用Dalvik字节码混淆的方法。
3. 《Detecting repackaged android apps using server-side analysis》:本文介绍了如何通过服务器端分析来检测重新打包的Android应用程序。
4. 《https://github.com/ysrc/AndroidObfuseDictionary》:这是一个开源的Android混淆字典,可以帮助开发者更有效地进行混淆。
5. 《Statistical Deobfuscation of Android Application》:这篇文章介绍了一种统计解混淆方法,用于对抗混淆技术。
6. 《Android字符串及字典开源混淆实现》:这篇博客介绍了一种基于字符串和字典的开源Android应用程序混淆实现。
7. 《Dex混淆的原理及实现》:本文详细介绍了Dex文件混淆的原理和实现方法。
8. 《Android Code Protection via Obfuscation Techniques Past, Present and Future Directions》:这篇文章总结了过去、现在和未来的Android代码保护混淆技术的发展方向。
9. 《https://mp.weixin.qq.com/s/SRv1Oar87w1iKuDXS4oaew》:这是一篇关于Android字符串及字典开源混淆实现的中文翻译版文章。
10. 《Dex混淆的原理及实现》:本文详细介绍了Dex文件混淆的原理和实现方法。
通过阅读这些文章,开发者可以了解到各种Android应用程序混淆技术的原理、实现方法以及它们在实际应用中的表现。这将有助于开发者更好地保护自己的应用程序免受逆向工程和恶意代码分析的攻击。