方舟编译器来了,apk里的代码都变成so文件了,还怎么做加固?
热烈欢迎方舟编译器上线开源!
根据华为发布的方舟编译器架构图可看出,应用方舟编译器后,输出变成了二进制文件,并添加编译器运行时库后最终链接成可执行文件。类 Linux 系统的可执行文件一般是指无后缀的二进制文件(对应 Windows 下的 .exe 文件)和 .so 文件(对应 Windows 下的 .dll 文件)。华为官方表示方舟编译器能够将系统操作流畅度提升 24%、系统响应力提升 44%、第三方应用操作流畅度提升 60%。如此大的性能提升,简直是一统江湖之势。所谓:优化尽头谁为峰,一见方舟道成空!
有鉴于安卓平台各种黑产极为猖狂,一般的应用软件开发者都要将自己的 apk 软件包做加固之后再发布。而讲到 apk 加固,主要是对 dex 文件做加密。dex 是 Android 平台上(Dalvik/Art 虚拟机)的可执行文件, 相当于 Windows 平台中的 exe 文件, 每个 Apk 安装包中都有 dex 文件, 里面包含了该 app 的所有代码, 通过反编译工具可以获取到相应的 java 源码。dex 文件加密就是 apk 加固的核心问题。那么问题来了,方舟编译器直接把 Java 代码变本地代码( .so 文件)了,apk 加固的重心必将转到 so 文件加壳。那么我们有现成的 so 加壳技术吗?现有的 so 加壳技术能保证我们的应用安全吗?援引现有的基于 dex 的 apk 加壳技术,将 so 库加壳也做一下分代介绍
分代 | 原理 | 破解方法 |
---|---|---|
1.1 | 对so文件整体加密,创建Loader, so文件运行时loader先运行,对密文解密,恢复原程序 | 难度*,直接挂钩,dump内存中的明文即可得到so文件,简单修复即可。 |
1.2 | 函数级加密。将每个函数单独加密,将原函数替换为中转函数,中转函数做解密,并将原函数的明文写回原地址 | 难度*,需要将各个函数运行一遍后再dump,并修复 |
1.3 | 函数级加密。将每个函数单独加密,将原函数替换为中转函数,中转函数做解密,并将原函数的明文分配在堆上 | 难度**,需要对运行过程做分析,将加密函数挂钩,并找出对应的明文地址,再dump+修复 |
2 | 类ollvm代码混淆 基于苹果的开源LLVM框架,魔改clang编译器,在编译过程的IR(中间代码)层面做混淆操作。让软件开发商换用魔改版clang编译器。得到混淆后的so文件。常见的混淆手段见附录。 | 难度***,仅对代码做了变形,并没有隐藏代码,只是代码里多了很多的垃圾,复杂了很多,增加了算法分析的难度。不能防止反编译,基本上用ida可以反编译成C语言代码,很容易分析。 |
2.5 | 基于LLVM的代码虚拟化。用LLVM基础库构造虚拟机指令handler,规避后端指令多样性,在不涉及具体CPU的前提下实现虚拟化。由于方舟编译器是开源的,并且也有中间的IR表示,可以想见同样原理的混淆和虚拟化技术也会纷纷涌现。 | 难度***+,与混淆相比,代码逻辑隐藏较深,但一般handler可以反编译成C语言,分析难度不高。但代码逻辑隐藏到了虚拟指令中,算法还原较为复杂。 |
3 | 本地代码混淆。直接对so文件中的二进制代码进行混淆。2代壳中所用的手段在此同样可用。针对不同的指令要单独开发一套混淆方法,不具备2代的平台普适性。但是由于是汇编/字节码级别的混淆,可任意插入各种不常用的指令,手段更灵活,代码更复杂。 | 难度****,各种你想不到的指令和应用都可能出现。ida基本不能反编译成C语言代码。虽然没有真的将代码隐藏起来,但各种地址变换和跳转指令结合,根本没有一个好的方法找到目标代码。破解难度比ollvm上升一个级别。 |
4 | 本地代码虚拟化。直接对so文件中的二进制代码进行虚拟化。 | 难度*****,同时具备2.5和3的特点,破解极难。想想就头疼。 |
商业化产品分析
- 1代:upx
- 2代:基于ollvm的互联网产品:梆梆、爱加密、360、腾讯、网易、百度… 所谓安全编译器都是
- 2.5 梆梆(SI2S安全编译器)、深思数盾(Virbox Compiler)
- 3代:深思数盾-VirboxProtector
- 4代:无。
总结
世界上从来没有无缘无故的爱,也没有无缘无故的恨。任何高大上的技术都不是空中楼阁。方舟编译器横空出世极大改变了安卓生态环境,但我们也不必因此而惊慌失措。安全技术公司深厚的技术积累足以应对因此而带来的变局。
附录
- ollvm常见混淆手段
- 控制流扁平化 这个模式主要是把一些if-else语句,嵌套成do-while语句
- 指令替换 这个模式主要用功能上等效但更复杂的指令序列
- 虚假控制流程 这个模式主要嵌套几层判断逻辑,一个简单的运算都会在外面包几层if-else 参考文档:《OLLVM代码混淆移植与使用》