其他
如何用OLLVM来保护你的关键代码
点击上方蓝字关注我们噢~
本文将介绍如何使用OLLVM技术,对Android Native原生代码进行混淆处理。混淆处理过的so文件将极大增加逆向分析的难度,保护软件的相关运行逻辑。
01
LLVM介绍
LLVM起源于2000年伊利诺伊大学厄巴纳-香槟分校维克拉姆•艾夫(Vikram Adve)与克里斯•拉特纳(Chris Lattner)的研究发展而成,他们想要为所有静态及动态语言创造出动态的编译技术。
2005年,苹果公司雇用了克里斯•拉特纳(Chris Lattner)及他的团队,为了苹果电脑开发应用程序系统,LLVM为现今Mac OS X及iOS开发工具的一部分。
同时,LLVM现在也是Google的Android系统中的一部分,特别是在Android系统使用了新的运行时ART(Android Runtime)之后,LLVM在Android系统中的比重就得到了更大的提升。
LLVM核心库提供了与编译器相关的支持,可以作为多种语言编译器的后台来使用,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。LLVM可以被看作是一系列的编译器和工具链技术的集合,而且它们是模块化并且是可重用的。
Clang是LLVM的一个编译器前端,它支持C、C++等编程语言。
Clang对源程序进行词法分析和语义分析,并将分析结果转换为Abstract Syntax Tree(抽象语法树),最后使用LLVM作为后端代码的生成器。
Clang的开发目标是提供一个可以替代GCC的前端编译器。即LLVM可以认为是一个编译器的后端,而Clang是一个编译器的前端。
02
OLLVM原理
中间部分的优化器只对中间表示 IR 操作,通过一系列的 Pass 对 IR 做优化,后端负责将优化好的 IR 解释成对应平台的机器码。
LLVM 的优点在于,中间表示 IR 代码编写良好,而且不同的前端语言最终都转换成同一种的 IR。
OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学于2010年6月份发起的一个项目(https://github.com/obfuscator-llvm/obfuscator),该项目旨在提供一套开源的针对LLVM的代码混淆工具,以增加对逆向工程的难度。
OLLVM是基于LLVM实现的,OLLVM的混淆操作就是在中间表示IR层,通过编写Pass来混淆IR,然后后端依据IR来生成的目标代码也就被混淆了。
得益于LLVM的设计,OLLVM适用LLVM支持的所有语言(C, C++, Objective-C, Ada 和 Fortran)和目标平台(x86, x86-64, PowerPC, PowerPC-64, ARM, Thumb, SPARC, Alpha, CellSPU, MIPS, MSP430, SystemZ, 和 XCore)。
03
OLLVM的混淆方式
-fla 参数表示使用控制流平展(Control Flow Flattening)模式-sub参数表示使用指令替换(Instructions Substitution)模式-bcf参数表示使用控制流伪造(Bogus Control Flow)模式
此外,OLLVM支持对单个函数进行混淆,即Functions annotations模式。
控制流平展(Control Flow Flattening)模式
控制流平展模式可以完全改变程序原本的控制流图。如下示例代码是简单的 if-else 分支语句,正常编译后其控制流图在IDA中,是正常的 if-else 分支,使用 -mllvm -fla 参数混淆后,在 IDA中显示的控制流图如下图所示。
经 FLA 模式混淆后,程序的执行流程已经被打乱,出现许多代码分支。通过仔细对比程序混淆前后,可以发现上图着色区域是相对应的,也就是说,FLA 模式只会去更改代码分支,而不会对单个代码块做处理。
指令替换(Instructions Substitution)模式
SUB 模式目前只支持整数运算操作,支持 + , - , & , | 和 ^ 操作,还是比较局限的。编译时,使用 -mllvm -sub 参数即可。
控制流伪造(Bogus Control Flow)模式
更要命的是,原代码块可能会被克隆并插入随机的垃圾指令。
这么多不确定性,就导致对同一份代码多次做 BCF 模式的混淆时,得到的是不同的混淆效果。
可见,BCF 混淆模式还是很强大的,不同于 FLA 那种较确定的混淆模式。使用 BCF 模式编译时配置参数 -mllvm -bcf 即可。
此外,BCF 模式还支持其它几个参数,下面参数与 -mllvm -bcf 参数配合使用:-mllvm -perBCF=20: 对所有函数都混淆的概率是20%,默认100%-mllvm -boguscf-loop=3: 对函数做3次混淆,默认1次-mllvm -boguscf-prob=40: 代码块被混淆的概率是40%,默认30%
BCF混淆后
04
OLLVM的使用方法
环境信息操作系统:ubuntu18.04 64bitNDK:android-ndk-r10e
LLVM:3.6.1
编译ollvm首先下载并编译ollvm源码git clone -b llvm-3.6.1 https://github.com/obfuscator-llvm/obfuscator.gitmkdir buildcd buildcmake -DCMAKE_BUILD_TYPE:String=Release ../obfuscator/make -j5编译好的目录如下,编译好的二进制程序都存放在 build/bin 目录下。
在 toolchains 目录下新建 obfuscator-llvm-3.6 目录,并将llvm-3.6 目录下的 config.mk、setup.mk 和 setup-common.mk 拷贝到 obfuscator-llvm-3.6 目录中,不做任何修改。
然后,把源码编译好的 bin 目录和 lib 目录按照 llvm-3.6 中 prebuilt/linux-x86_64 的目录格式拷贝。
接着,在 toolchains 目录下分别建立 armlinux-androideabi-obfuscator3.6, mipsel-linux-android-obfuscator3.6, x86-obfuscator3.6 目录,注意文件夹的前缀要与原toolchains 中的目录保持一致,然后把 arm-linux-androideabi-clang3.6, mipsel-linux-android-clang3.6, x86-clang3.6 文件夹下的config.mk 和 setup.mk 对应拷贝到上述三个文件夹中.
此时要分别修改 setup.mk 中的 LLVM_NAME ,即将其指定到开始建立的obfuscator-llvm-3.6 目录。
LLVM_NAME := obfuscator-llvm-$(LLVM_VERSION)
至此,新增加的具备 OLLVM 混淆的编译工具链就添加完成了,在编译 native 程序时,在 Android.mk 和 Application.mk 中配置编译参数即可。
ollvm使用
使用ollvm混淆编译后反编译效果:
进一步扩展
如果需要进一步针对字符串表混淆处理,可以参考上海交通大学密码与计算机安全实验室维护的LLVM混淆框架“孤挺花(https://github.com/GoSSIP-SJTU/Armariris)”。它提供了字符串加密,控制流扁平化和指令替换等功能。感兴趣读者朋友们可以进一步了解。
更多精彩阅读
一文读懂 | 内置安全成熟度模型BSIMM
万物互联时代已经来临,你怎么能错过OWASP Internet of Things呢?
ATT&CK for Mobile 你了解多少?
长按关注 更多安全技术干货等你发现