在 02 中,贴了一张图,里面涵盖了加固的绝大部分知识。现在我们稍微展开说一下其中几个,也是后续会深入学习的,其中一些还需要单独成系列才行。
分为 Java 层与 Native 层混淆。
Java 层的混淆主要分为两种:
字符串
Proguard 混淆类名,方法名,字段名
比如:
https://github.com/MegatronKing/StringFog?tab=readme-ov-file
原理也很简单:
加密前:
String a = "This is a string!";
加密后:
String a = StringFog.decrypt(new byte[]{-113, 71...}, new byte[]{-23, 53});
就是将常量字符串替换为一个运行时解密的函数调用。
字符串混淆都是看着恶心,实际意义不大,如果你会 frida 或者 xposed,直接 hook 这个 decrypt 函数就可以得到所有解密后的字符串了。
Native 层的混淆与 Java 层类似。
它也有字符串混淆,一般也是写一个方法进行运行时解密,同样 hook 解密方法即可。或者是在 init 与 init_array 阶段解密。
https://bbs.kanxue.com/thread-252257.htm
有个开源项目提供了字符串混淆,名字很有意思——孤挺花:
https://github.com/GoSSIP-SJTU/Armariris
还有控制流混淆OLLVM,需要单独开一个系列。
简单理解一下,就是程序运行逻辑都是由控制流决定的。一个正常的程序分支不会太多,逆向起来也很简单。OLLVM 的作用就是生成很多的虚假分支,将真实的逻辑切片,混到这些虚假分支里面,反编译后的逻辑,看起来非常头大。如下图:
这是一个混淆程度不算深的代码,就算这样,看起来也很头疼了,所以需要将汇编指令进行处理,我们在系列里面进行讨论。
花指令:就是在代码中加入一些无意义的指令,这样 ida 分析的时候会出错。不过这种绕过也比较简单,就是 dump 内存中的 so,或者针对性的处理一下就行。
jdax 对抗:修改 dex 内容,比如我之前做过的一种,将 method 的 flag 改成 native 标识,这样 jadx 会将它当成一个真正的 native 方法,就不会反编译方法内容。
Dex 加固:
函数性抽取壳:就是将 Dex 里面的 CodeItem 指令提取出来,储存到别的地方,加密,然后运行的时候再设置回方法里面。
Dex2C:将 dex 反编译成 smali 后,分析 smali 语法树,生成的对应的 C 代码,利用 JNI 来完成逻辑调用,最后的到 so 文件。
DEXVMP:对原来的smail代码做替换,然后用自己的解释器“执行”替换后的代码,实现的功能和原smail代码一样!
https://geneblue.github.io/2019/09/13/android/sec--android-dex-vmp/
ARMVMP:将 so 指令换成自己定义的指令,使用自己的虚拟机来执行自定义指令,实现同样的逻辑。
https://cloud.tencent.com/developer/article/1847027
VMP 也是得单独开一个系列的。
二手的程序员
主要研究Android逆向相关的知识。文章均会同步到博客,且持续修订:lyldalek.top
公众号