OLLVM简介

OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学于2010年6月份发起的一个项目,该项目旨在提供一套开源的针对LLVM的代码混淆工具,以增加对逆向工程的难度。

OLLVM是基于LLVM实现的,LLVM是一个编译器框架,它也采用经典的三段式设计。前端可以使用不同的编译工具对代码文件做词法分析以形成抽象语法树AST,然后将分析好的代码转换成LLVM的中间表示IR(intermediate representation);中间部分的优化器只对中间表示IR操作,通过一系列的Pass对IR做优化;后端负责将优化好的IR解释成对应平台的机器码。LLVM的优点在于,不同的前端语言最终都转换成同一种的IR。

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)。

OLLVM的几种混淆方式

OLLVM默认支持 -fla -sub -bcf 三个混淆参数,这三个参数可以单独使用,也可以配合着使用。-fla 参数表示使用控制流平展(Control Flow Flattening)模式,-sub参数表示使用指令替换(Instructions Substitution)模式,-bcf参数表示使用控制流伪造(Bogus Control Flow)模式

-sub instruction substitution(指令替换)

-fla control flow flattening(控制流平坦化)

-bcf bogus control flow(控制流伪造)

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

以下分别介绍这几种方式并举例说明:

instruction substitution(指令替换)

指令替换是一种比较简单的混淆方式,OLLVM将一些简单的运算复杂化,但这种方式容易被代码优化给去除,目前OLLVM只实现对整数运算的混淆。

加法混淆

例如 a = b + c 可以被混淆为:

1

2

3

41. a = b - (-c)

2. a = -(-b + (-c))

3. r = rand (); a = b + r; a = a + c; a = a - r

4. r = rand (); a = b - r; a = a + b; a = a + r

减法混淆

例如 a = b-c 可以被混淆为:

1

2

31. a = b + (-c)

2. r = rand (); a = b + r; a = a - c; a = a - r

3. r = rand (); a = b - r; a = a - c; a = a + r

AND运算混淆

a = b & c => a = (b ^ ~c) & b

OR运算混淆

a = b | c => a = (b & c) | (b ^ c)

XOR运算混淆

a = a ^ b => a = (~a & b) | (a & ~b)

如果一种运算对应多种混淆方式,OLLVM将会随机选择一种,以下为使用OLLVM进行指令替换后的前后对比:

源码:1

2

3

4

5int test(int a,int b)

{

int c = a + b;

return c+2;

}

sub前:

sub后

分析汇编指令得出,a+b+2 运算变成了 -(-b-(a+2))

control flow flattening(控制流平坦化)

control flow flattening(控制流平坦化)通过多个case-swich结构将程序的控制流变成扁平形状,打破原有的逻辑结构,增加逆向的难度。

例如对于以下代码:

1

2

3

4

5

6

7

8

9#include

int main(int argc, char** argv) {

int a = atoi(argv[1]);

if(a == 0)

return 1;

else

return 10;

return 0;

}

OLLVM将把它变为如下结构:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22#include

int main(int argc, char** argv) {

int a = atoi(argv[1]);

int b = 0;

while(1) {

switch(b) {

case 0:

if(a == 0)

b = 1;

else

b = 2;

break;

case 1:

return 1;

case 2:

return 10;

default:

break;

}

}

return 0;

}

从代码中可以看到,OLLVM将源代码分割为几个基本块,并放在一个while循环结构中无线循环,程序的流程由变量b控制。

以下是使用OLLVM进行控制混淆后的前后对比:

源码1

2

3

4

5

6

7

8

9#include

int main(int argc, char** argv) {

int a = atoi(argv[1]);

if(a == 0)

return 1;

else

return 10;

return 0;

}

fla之前:

fla之后:

F5之后的代码:

由此可见,fla之后的控制流比较复杂,通过分析fla之后的代码,我们发现代码中的result仅仅受v7的影响,但分析起来着实费力。

bogus control flow(控制流伪造)

bogus control flow通过在源程序的控制流中添加一些基本块,这些基本块仅仅起了连接作用,并不影响实际的执行逻辑。

以下为使用OLLVM进行控制流伪造后的对比:

源码

1

2

3

4

5

6

7

8

9#include

int main(int argc, char** argv) {

int a = atoi(argv[1]);

if(a == 0)

return 1;

else

return 10;

return 0;

}

bcf之前:

![upload successful](/images/pasted-128.png)

bcf之后:

![upload successful](/images/pasted-131.png)

F5之后的代码:

![upload successful](/images/pasted-132.png)

由此看出,bcf的方式在程序中增加了一个代码块,这个代码块对函数返回值没有任何影响,但对于逆向人员来说,增加了其逆向分析的无用功。

Functions annotations

有时候为了提高效率,开发者仅需要对指定的函数进行混淆,OLLVM的Functions annotations模式支持对单个函数进行混淆。比如,想对函数func()使用bcf混淆,只需要给函数func()增加bcf属性即可。

1int func() __attribute((__annotate__(("bcf"))));

OLLVM的fla,sub和bcf三个属性可以搭配使用,只需要添加对应的编译选项即可。

利用OLLVM进行Android native代码混淆

1.下载并编译ollvm1

2

3

4

5$ git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git

$ mkdir build

$ cd build

$ cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/

$ make -j7

2.配置NDK以支持ollvm新建编译链

在 android-ndk-r14b/toolchains 下新建目录 ollvm-4.0/prebuilt/darwin-x86_64(我的环境是mac),把前一步编译生成的结果拷贝到此目录下(主要是bin和lib)

配置编译链

在 android-ndk-r14b/build/core/toolchains 目录下,新建目录 arm-linux-androideabi-clang-ollvm4.0,拷贝目录 arm-linux-androideabi-clang 下的文件 config.mk 与 setup.mk 到 arm-linux-androideabi-clang-ollvm4.0 中,修改setup.mk文件。1

2

3

4

5

6

7

8

9############################ 原始配置 ############################

#LLVM_TOOLCHAIN_PREBUILT_ROOT := $(call get-toolchain-root,llvm)

#LLVM_TOOLCHAIN_PREFIX := $(LLVM_TOOLCHAIN_PREBUILT_ROOT)/bin/

#################################################################

############################ 修改后 #############################

OLLVM_NAME := ollvm-4.0

LLVM_TOOLCHAIN_PREBUILT_ROOT := $(call get-toolchain-root,$(OLLVM_NAME))

LLVM_TOOLCHAIN_PREFIX := $(LLVM_TOOLCHAIN_PREBUILT_ROOT)/bin/

#其他配置不做修改

3.使用ollvm进行编译

使用 ollvm 进行 ndk 的编译需要对 Application.mk 和 Android.mk 文件做相应的修改。

Android.mk 中添加混淆编译参数:

1LOCAL_CFLAGS += -mllvm -sub -mllvm -bcf -mllvm -fla

Application.mk 中配置 NDK_TOOLCHAIN_VERSION

1

2APP_ABI := x86 armeabi-v7a x86_64 arm64-v8a armeabi mips64

NDK_TOOLCHAIN_VERSION := clang-ollvm-4.0

参考资料:

代码混淆android.mk,利用ollvm进行代码混淆相关推荐

  1. android怎么注释代码块,Android.mk 代码注释

    参考文章:http://www.cnblogs.com/wainiwann/p/3837936.html LOCAL_PATH := $(call my-dir)  #返回Android.mk的目录路 ...

  2. 代码 拉取_Git 利用 Webhooks 实现代码的自动拉取

    WebHook 简介 WebHook 功能是帮助用户 push 代码后,自动回调一个您设定的 http 地址. 这是一个通用的解决方案,用户可以自己根据不同的需求,来编写自己的脚本程序. 环境 服务器 ...

  3. android 代码功能测试,Android触屏测试实例代码

    本文实例详细描述了Android触屏测试代码,可实现对触屏的点击.移动.离开等事件的处理,对于Android初学者有很好的借鉴价值. 具体功能代码如下: package com.test; impor ...

  4. 编写Android.mk把Android studio项目编译到AOSP源码中

    前言: 在工作,我们利用Android studio开发apk是非常方便的,当我们要把工程代码放在android 源码中编译的时候,需要我们自己编写Andorid.mk 文件.以下内容是对Androi ...

  5. Android.mk基础知识

    一.基础知识 1.Android.mk文件可以将源码打包成模块,模块可以是apk,jar包,c/c++应用程序,静态库和动态库.动态库可以被以到应用程序包apk,静态库可以被连接入动态库. 2.And ...

  6. Android.mk文件语法规范

    序言: ------------- 此文档旨在描述Android.mk文件的语法,Android.mk文件为Android NDK(原生开发)描述了你C/C++源文件. 为了明白下面的内容,你必须已经 ...

  7. Android.mk解析

    一.变量说明: 1.LOCAL_PATH:= $(call my-dir) 此行代码在Android.mk的开头,用于给出当前文件的路径 LOCAL_PATH 用于在开发树中查找源文件 宏函数'my- ...

  8. Android.mk解析【转】

    一.变量说明: 1.LOCAL_PATH:= $(call my-dir) 此行代码在Android.mk的开头,用于给出当前文件的路径 LOCAL_PATH 用于在开发树中查找源文件 宏函数'my- ...

  9. 编写Android.mk中的LOCAL_SRC_FILES,使其自动查找源文件,不需要手动添加

    在使用NDK编译C/C++项目的过程中,免不了要编写Android.mk文件,其中最重要的就是android.mk源文件列表. cpp文件位于android项目下的的不同文件夹和子文件夹下 按照通常的 ...

最新文章

  1. 记忆网络RNN、LSTM与GRU
  2. treeview控件怎么使用修改发育树_树形控件在生产力工具中的设计
  3. python SQLAlchemy数据库操作
  4. 天梯赛 L1-039 古风排版 (20 分)
  5. 「MacOS」无法打开***,因为无法验证开发者。
  6. (6)Zynq AXI_HP接口介绍
  7. redis 经纬度_Redis 中的 GEO(地理信息)类型
  8. CPDA项目数据分析师和CDA数据分析师有什么区别?
  9. 302号文--个人银行账户分类管理
  10. Google 翻译插件不能用了怎么办
  11. IT行业道德伦理 介绍
  12. Linux救援(rescue)模式知识点
  13. 家庭風水的六大注意事項_家居风水自查
  14. 大O、小o、大Ω、小ω、大Θ符号在算法中是什么意思?
  15. 大学数据库创建与查询实战——查询
  16. [注]微信公众号的运营推广总结方案(持续更新)
  17. 大学军训板报计算机学院,军训板报
  18. SpringCloud Netflix-Eureka使用
  19. winrar正确破解方法
  20. 词语语义的相关关系和相似关系量化

热门文章

  1. 为拯救爸妈朋友圈,达摩院造了“谣言粉碎机” 1
  2. Python数据挖掘与机器学习,快速掌握聚类算法和关联分析
  3. 阿里云直播转点播最佳实践
  4. 高速通道-冗余物理专线接入-健康检查配置
  5. 不记得 Git 命令? 懒人版 Git 值得拥有!
  6. 面试时遇到「看门狗」脖子上挂着「时间轮」,我就问你怕不怕?
  7. Cloud一分钟 | 北京13部门召开座谈会,要求阿里京东等平台规范开展双11促销活动...
  8. 「拨云见日」英特尔揭秘短视频背后的二三事
  9. echarts 折线图 html模板,设置ECharts折线图的提示框
  10. centos7 /etc/profile 文件模板