如何用OLLVM来保护你的关键代码

admin 2023年5月16日07:58:54评论89 views字数 4058阅读13分31秒阅读模式

点击上方蓝字关注我们噢~

如何用OLLVM来保护你的关键代码


对于一些重要APP或者包含有核心功能的APP,在产品发布之前,通常需要采用一定手段对代码进行混淆处理,而java层面的代码逻辑很容易被逆向分析。因此,很多敏感的业务逻辑都会使用Native原生代码的方式进行编写。

本文将介绍如何使用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系统中的比重就得到了更大的提升。

如何用OLLVM来保护你的关键代码


LLVM命名最早源自于底层虚拟机(Low Level Virtual Machine)的缩写,但是现在,LLVM所代表的基本和虚拟机没有关系了,也不再作为一个缩写使用了,而是直接作为一个名字使用。

LLVM核心库提供了与编译器相关的支持,可以作为多种语言编译器的后台来使用,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成LLVM可以被看作是一系列的编译器和工具链技术的集合,而且它们是模块化并且是可重用的

Clang是LLVM的一个编译器前端,它支持C、C++等编程语言

Clang对源程序进行词法分析和语义分析,并将分析结果转换为Abstract Syntax Tree(抽象语法树),最后使用LLVM作为后端代码的生成器。

Clang的开发目标是提供一个可以替代GCC的前端编译器。即LLVM可以认为是一个编译器的后端,而Clang是一个编译器的前端。



02

OLLVM原理


LLVM 是一个优秀的编译器框架,它采用经典的三段式设计。前端可以使用不同的编译工具对代码文件做词法分析以形成抽象语法树 AST,然后将分析好的代码转换成 LLVM 的中间表示 IR(intermediate representation)。

中间部分的优化器只对中间表示 IR 操作,通过一系列的 Pass 对 IR 做优化,后端负责将优化好的 IR 解释成对应平台的机器码。

LLVM 的优点在于,中间表示 IR 代码编写良好,而且不同的前端语言最终都转换成同一种的 IR。
如何用OLLVM来保护你的关键代码如何用OLLVM来保护你的关键代码
LLVM IR 是 LLVM 的中间表示,优化器就是对 IR 进行操作的,具体的优化操作由一些列的 Pass 来完成,当前端生成初级 IR 后,Pass 会依次对 IR 进行处理,最终生成后端可用的 IR。下图可以说明这个过程。
如何用OLLVM来保护你的关键代码
如何用OLLVM来保护你的关键代码

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的混淆方式


OLLVM默认支持 -fla -sub -bcf 三个混淆参数,这三个参数可以单独使用,也可以配合着使用。

-fla 参数表示使用控制流平展(Control Flow Flattening)模式
-sub参数表示使用指令替换(Instructions Substitution)模式
-bcf参数表示使用控制流伪造(Bogus Control Flow)模式

此外,OLLVM支持对单个函数进行混淆,即Functions annotations模式。


如何用OLLVM来保护你的关键代码

控制流平展(Control Flow Flattening)模式


控制流平展模式可以完全改变程序原本的控制流图。如下示例代码是简单的 if-else 分支语句,正常编译后其控制流图在IDA中,是正常的 if-else 分支,使用 -mllvm -fla 参数混淆后,在 IDA中显示的控制流图如下图所示。


如何用OLLVM来保护你的关键代码


经 FLA 模式混淆后,程序的执行流程已经被打乱,出现许多代码分支。通过仔细对比程序混淆前后,可以发现上图着色区域是相对应的,也就是说,FLA 模式只会去更改代码分支,而不会对单个代码块做处理。


如何用OLLVM来保护你的关键代码

指令替换(Instructions Substitution)模式


指令替换模式主要是将正常的运算操作(+,-,&,| 等)替换成功能相等但表述更复杂的形式。比如,对于表达式 a = b + c,它的等价式可以有 a = - (-b - c), a = b - (-c) 或 a = -(-b) + c 等,原表达式可以替换成任意相等式,或者通过随机数在多个相等式中做选择。

SUB 模式目前只支持整数运算操作,支持 + , - , & , | 和 ^ 操作,还是比较局限的。编译时,使用 -mllvm -sub 参数即可。

如何用OLLVM来保护你的关键代码

如何用OLLVM来保护你的关键代码


如何用OLLVM来保护你的关键代码

控制流伪造(Bogus Control Flow)模式


控制流伪造模式也是对程序的控制流做操作,不同的是,BCF 模式会在原代码块的前后随机插入新的代码块,新插入的代码块不是确定的,然后新代码块再通过条件判断跳转到原代码块中。

更要命的是,原代码块可能会被克隆并插入随机的垃圾指令。

这么多不确定性,就导致对同一份代码多次做 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%

如何用OLLVM来保护你的关键代码

如何用OLLVM来保护你的关键代码

BCF混淆后



04

OLLVM的使用方法


环境信息
操作系统:ubuntu18.04 64bit
NDK:android-ndk-r10e

LLVM:3.6.1


编译ollvm
首先下载并编译ollvm源码
git clone -b llvm-3.6.1 https://github.com/obfuscator-llvm/obfuscator.git
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE:String=Release ../obfuscator/
make -j5
编译好的目录如下,编译好的二进制程序都存放在 build/bin 目录下。

如何用OLLVM来保护你的关键代码


如何用OLLVM来保护你的关键代码
配置编译工具链


按照 ndk 编译工具链的组织结构,我们照样子新建一条工具链即可。

在 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来保护你的关键代码

至此,新增加的具备 OLLVM 混淆的编译工具链就添加完成了,在编译 native 程序时,在 Android.mk 和 Application.mk 中配置编译参数即可。


如何用OLLVM来保护你的关键代码

ollvm使用


在 Application.mk 中指定编译器名字,NDK_TOOLCHAIN_VERSION := obfuscator3.6

如何用OLLVM来保护你的关键代码


在 Android.mk 中设置混淆参数,LOCAL_CFLAGS += -mllvm -sub -mllvm -bcf -mllvm -fla
如何用OLLVM来保护你的关键代码 如何用OLLVM来保护你的关键代码

使用ollvm混淆编译后反编译效果:

如何用OLLVM来保护你的关键代码

如何用OLLVM来保护你的关键代码

进一步扩展


经过OLLVM编译处理后的so文件将极大提高分析难度,但是目前混淆后so的字符串表中依然会泄漏少量文本信息。

如果需要进一步针对字符串表混淆处理,可以参考上海交通大学密码与计算机安全实验室维护的LLVM混淆框架“孤挺花(https://github.com/GoSSIP-SJTU/Armariris)”。它提供了字符串加密,控制流扁平化和指令替换等功能。感兴趣读者朋友们可以进一步了解。

如何用OLLVM来保护你的关键代码


更多精彩阅读
如何用OLLVM来保护你的关键代码

一文读懂 | 内置安全成熟度模型BSIMM
万物互联时代已经来临,你怎么能错过OWASP Internet of Things呢?
ATT&CK for Mobile 你了解多少?




长按关注  更多安全技术干等你发现 如何用OLLVM来保护你的关键代码

如何用OLLVM来保护你的关键代码


好文!在看吗?点一下鸭!

原文始发于微信公众号(vivo千镜):如何用OLLVM来保护你的关键代码

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月16日07:58:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   如何用OLLVM来保护你的关键代码https://cn-sec.com/archives/904394.html

发表评论

匿名网友 填写信息