美文网首页iOS待阅奏折iOS技巧
Obfuscator-LLVM在iOS中的实践

Obfuscator-LLVM在iOS中的实践

作者: fighting300 | 来源:发表于2017-08-31 18:18 被阅读2779次

原文链接:http://fighting300.com....

OLLVM简介

OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个项目,该项目旨在提供一套开源的针对LLVM的代码混淆工具,以增加对逆向工程的难度。后期转向商业项目strong.protect。目前,OLLVM已经支持LLVM-4.0版本。

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

LLVM IR 是LLVM的中间表示,优化器就是对IR进行操作的,具体的优化操作由一些列的Pass来完成,当前端生成初级IR后,Pass会依次对IR进行处理,最终生成后端可用的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 iOS编译环境搭建

以下,介绍OLLVM iOS环境的插件创建过程。
首先下载源码,编译OLLVM混淆器,这里采用LLVM的版本是4.0。下载编译过程如下:

$ 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  

下载的源码里已经包含了LLVM和Clang,编译完成后,编译好的二进制程序都存在在build/bin目录下。

依据github上的wiki,bin目录下编译好的工具链可以直接用来编译混淆linux下的程序,就像我们常用的gcc那样。若想使用OLLVM来混淆iOS程序,还需将bin目录下的工具链整合进Xcode插件中,具体步骤如下。

配置Xcode--新建Obfuscator插件

$ cd /Applications/Xcode.app/Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/  
$ sudo cp -r Clang\ LLVM\ 1.0.xcplugin/ Obfuscator.xcplugin  
$ cd Obfuscator.xcplugin/Contents/  
$ sudo plutil -convert xml1 Info.plist  
$ sudo vim Info.plist  

修改Info.plist中的对应内容:

<string>com.apple.compilers.clang</string> -> <string>com.apple.compilers.obfuscator</string>  
<string>Clang LLVM 1.0 Compiler Xcode Plug-in</string> -> <string>Obfuscator Xcode Plug-in</string>  

修改Obfuscator.xcspec文件

$ sudo plutil -convert binary1 Info.plist  
$ cd Resources/  
$ sudo mv Clang\ LLVM\ 1.0.xcspec Obfuscator.xcspec  
$ sudo vim Obfuscator.xcspec  

修改ExecPath的地址为当前build/bin的地址(!重点)

Identifier = "com.apple.compilers.llvm.clang.1_0"; -> Identifier = "com.apple.compilers.llvm.obfuscator.4_0";  
Name = "Apple LLVM 8.0"; -> Name = "Obfuscator 4.0";  
Description = "Apple LLVM 8.0 compiler"; -> Description = "Obfuscator 4.0";  
Vendor = Apple; -> Vendor = HEIG-VD;  
Version = "7.0"; -> Version = "4.0";  
ExecPath = "clang"; -> ExecPath = "/path/to/obfuscator_bin/clang";  

修改 Obfuscator 4.0 Strings

$ cd English.lproj/  
$ sudo mv Apple\ LLVM\ 8.0.strings "Obfuscator 4.0.strings"  
$ sudo plutil -convert xml1 Obfuscator\ 4.0.strings  
$ sudo vim Obfuscator\ 4.0.strings  
"Description" = "Apple LLVM 8.0 Compiler"; -> "Description" = "Obfuscator 4.0";  
"Name" = "Apple LLVM 8.0"; -> "Name" = "Obfuscator 4.0";  
"Vendor" = "Apple"; -> "Vendor" = "HEIG-VD";  
"Version" = "8.0"; -> "Version" = "4.0";  

sudo plutil -convert binary1 Obfuscator\ 4.0.strings

现在,你可以打开Xcode在项目配置里来选择新的编译器,并且可以在C Flags或C++ Flags下添加混淆标签。

选择编译器
添加混淆标签

这样配置完成后,就可以编译项目生成混淆后的程序。

ollvm混淆使用

接下来使用以下demo介绍混淆功能的具体使用。

int main(){  
    int a = 1;  
    int b = 0;  
    int c = 0;  
    if(a > b){  
        a = 100;    
        b = 50;    
        c = a - b;    
        int d = a + b;    
        int e = a & b;    
        int f = a ^ b;    
        printf("c = %d\n",c);    
        printf("d = %d\n",d);    
        printf("e = %d\n",e);    
        printf("f = %d\n",f);    
        printf("a > b\n");    
    }else{  
        printf("a < b\n");    
    }  
    return 0;  
}

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

Instructions Substitution

指令替换模式主要是将正常的运算操作(+,-,&,|等)替换成功能相等但表述更复杂的形式。比如,对于表达式 a = b + c,它的等价式可以有 a = – ( -b – c), a = b – (-c) 或 a = -(-b) + c 等,原表达式可以替换成任意相等式,或者通过随机数在多个相等式中做选择。SUB模式目前只支持整数运算操作,支持 + , – , & , | 和 ^ 操作,还是比较局限的。编译时,使用 -mllvm -sub 参数即可。

-mllvm -sub: 启用instructions substitution  
-mllvm -sub_loop=3: 对每个函数混淆3次,默认1词  

Control Flow Flattening

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



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

-mllvm -fla: 启用control flow flattening
-mllvm -split: 启用block切分,提升平展程度
-mllvm -split_num=3: 对每个block混淆3次,默认1词
Bogus Control Flow

控制流伪造模式也是对程序的控制流做操作,不同的是,BCF模式会在原代码块的前后随机插入新的代码块,新插入的代码块不是确定的,然后新代码块再通过条件判断跳转到原代码块中。更要命地是,原代码块可能会被克隆并插入随机的垃圾指令。这么多不确定性,就导致对同一份代码多次做BCF模式的混淆时,得到的是不同的混淆效果。可见,BCF混淆模式还是很强大的,不同于FLA那种较确定的混淆模式。使用BCF模式编译时配置参数 -mllvm -bcf即可,此外,BCF模式还支持其它几个参数,下面参数与-mllvm -bcf参数配合使用。

-mllvm -bcf: 启用 bogus control flow
-mllvm -bcf_loop=3: 对一个函数混淆3次,默认1次
-mllvm -bcf_prob=40: 代码块被混淆的概率是40%,默认30%

如上图,下面两个着色的代码块就是有上面两个代码块克隆而来,而且其中被插入了一些垃圾指令,类似于这样:

当然,上述介绍的三种混淆模式可以搭配使用,同时使用三个参数混淆后,原本简单的if-else分支代码将会变得异常复杂,这无疑给逆向分析增加巨大的难度。

Functions annotations

有的时候,由于效率或其他原因的考虑,我们只想给指定的函数混淆或不混淆该函数,OLLVM也提供了对这一特性的支持,你只需要给对应的函数添加attributes即可。比如,想对函数foo()使用fla混淆,只需要给函数foo()增加fla属性即可。

int foo() __attribute((__annotate__(("fla"))));
int foo() {
   return 2;
}

你可以给函数添加一个或多个注释。如果你不想混淆某个函数,你可以使用否定标签。例如如果不想对func()函数使用bcf属性,那标记为“nobcf”即可。

错误处理

1.编译时报错,提示信息如下:

clang-3.6: error: unknown argument: '-gmodules'
clang-3.6: error: unknown argument: '-fembed-bitcode-marker'
Command /Users/dream/ollvm/build/bin/clang failed with exit code 1

在Build Settings中搜索并修改:
-gmodules: Obfuscator 4.0 - Code Generation: Generate Debug Symbols: 原来yes,改成no
-fembed-bitcode-marker: Build Option: Enable Bitcode: 原来yes,改成no

你可以在该git地址下找到最新的插件和build编译器文件,该编译器所使用的Xcode版本是8.3.3。

相关文章

网友评论

  • the宇亮:你好,是不是在xcode10下无法使用了?
  • 0b151757bed0:添加了参数过后编译出来的二进制 用反编译工具打开 显示并没有什么变化。
    -mllvm -fla -mllvm -sub_loop=3 -mllvm -split_num=3 -mllvm -bcf_loop=3 -mllvm -bcf_prob=100。
  • master_huang:cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/
    build obfuscator 时报错。提示配置不对。有谁知道吗?
  • TokapoNzld:error: can't exec 'path/to/obfuscator_bin/clang' (No such file or directory)
    Command path/to/obfuscator_bin/clang failed with exit code 71

    大佬,编译的时候报错 这个怎么破
    breezeWarm:@TokapoNzld 自己创建的目录是怎么弄,能够具体点吗
    TokapoNzld:@乱世先生 解决了,clang的目录写错了,要写成你自己创建的目录
    乱世先生:老哥,解决问题了吗?
  • 零壹后学者:clang (LLVM option parsing): Unknown command line argument '-sub'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-stats'?
    clang (LLVM option parsing): Unknown command line argument '-fla'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-help'?
    clang (LLVM option parsing): Unknown command line argument '-bcf'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-help'?
    melonsong:请问解决了吗,我也遇到了相同的问题
  • 零壹后学者:clang (LLVM option parsing): Unknown command line argument '-sub'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-stats'?
    clang (LLVM option parsing): Unknown command line argument '-fla'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-help'?
    clang (LLVM option parsing): Unknown command line argument '-bcf'. Try: 'clang (LLVM option parsing) -help'
    clang (LLVM option parsing): Did you mean '-help'?

    大神。xcode9.2. 找不到命令
    b3b5236c6aae:大兄弟,请问你这个问题怎么解决的?我也是填ExecPath这个参数绝对路径,但还是报这个错
  • 往事随锋:请教一下:在xcode 9.0下:
    如果Index-While-Building 设置成 default
    报错:clang-4.0: error: cannot specify -o when generating multiple output files
    Command /Users/beta/Documents/build/bin/clang failed with exit code 1

    如果Index-While-Building 设置成 No
    报错:In file included from /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.0.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:64:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.0.sdk/System/Library/Frameworks/UIKit.framework/Headers/NSFileProviderExtension.h:14:9: fatal error: could not build module 'FileProvider'
    #import <FileProvider/NSFileProviderExtension.h>
    ~~~~~~
    /Users/beta/Documents/SEC.IOS/Src/SEC/SEC/Components/Other/BetaWMPersonal.pch:7:9: fatal error: could not build module 'UIKit'
    zhengziyu:@往事随锋 大兄弟,遇到相同的问题了,怎么升级llvm5.0啊?
    往事随锋:@DogeHank 升级llvm5.0
    零壹后学者:兄弟。你的解决了吗。我跟你的一样
  • 8fc99f582558:大神:为什么我的xcode上添加 Obfuscator 4.0 然后显示的 是unsupporter compiler Obfuscator 4.0
    小小901:修改info.plist 中的 "com.apple.compilers.llvm.clang.1_0"; -> "com.apple.compilers.llvm.obfuscator.4_0"
  • 小鱼人_1d45:iphonesimulator/LibHNLogic.build/DerivedSources -F/Users/vegeance/TianTaiKaMi/clientcode/common/libs -stdlib=libc++ -c /Users/vegeance/TianTaiKaMi/clientcode/common/LibHNLogic/HNPlatformLogic/HNPlatformSpreadManager.cpp -o /Users/vegeance/Library/Developer/Xcode/DerivedData/MixProject-enqaofqhwwnvtpcsvnhdmcbgepyz/Build/Intermediates.noindex/LibHNLogic.build/Debug-iphonesimulator/LibHNLogic.build/Objects-normal/x86_64/HNPlatformSpreadManager.o

    In file included from /Users/vegeance/TianTaiKaMi/clientcode/common/LibHNLogic/HNPlatformLogic/HNPlatformSpreadManager.cpp:3:
    /Users/vegeance/TianTaiKaMi/clientcode/common/LibHNLogic/HNPlatformLogic/HNPlatformSpreadManager.h:7:10: fatal error: 'string' file not found
    #include <string>
    ^~~~~~~~
    1 error generated.
    Command /Users/vegeance/build/bin/clang-4.0 failed with exit code 1
    根本编译不过啊,8.33和9.2都编译不过,为什么基础库会报错??????急,在线等。。
  • 竹叶青_ab6f:支持bitcode吗
  • HarlanC:为啥编译后用IDA打开之后没有变化,还是能把函数反编译出来。流程也没有变化
    0b151757bed0:请问你解决了吗?我添加了参数反编译出来也没有变化
  • 一Bu小心丶:error: can't exec '/path/to/obfuscator_bin/clang' (No such file or directory)
    Command /path/to/obfuscator_bin/clang failed with exit code 71
    编译出现这个怎么解决?
    金玉游龙:路径改成自己本机上 clang 的绝对路径
    横爬介士:@Amanda_Lhy 大佬,我遇到这个问题了,我也没解决呢 ,你解决了没
    Amanda_Lhy:解决了没,我现在遇到这个问题
  • Laya_Egret:u3d 转过来的 工程
    In file included from /Users/lengyu/Downloads/IOS5/Classes/Prefix.pch:10:
    /Users/lengyu/Downloads/IOS5/Classes/Preprocessor.h:16:2: error: please use xcode 6.0 or newer
    #error please use xcode 6.0 or newer
    ^
    1 error generated.
    Command /Users/lengyu/build/bin/clang failed with exit code 1
    Laya_Egret:@0peep0 8.3.3
    0peep0:你用的xcode几?
    Laya_Egret:IOS5/Classes/main.mm:3:10: fatal error: 'csignal' file not found
    #include <csignal>
    ^~~~~~~~~
    1 error generated.
    Command /Users/lengyu/build/bin/clang failed with exit code 1
  • _冷忆:最后运行的时候一直报 error: can't exec '/Users/ice/Desktop/work/github/build/bin' (Permission denied)
    Command /Users/ice/Desktop/work/github/build/bin failed with exit code 71 这个目录是编译好的ollvm库命令 chmod +x 提权了还是不行
    _冷忆:@一Bu小心丶 没有呢,解决了请告知下,谢谢
    一Bu小心丶:@_冷忆 同遇这个问题,解决了么,求助
    _冷忆:ExecPath = "clang"; -> ExecPath = "/path/to/obfuscator_bin/clang"; 这边指定的路径一直提示没权限,求助楼主
  • x5forever:clang-4.0: error: cannot specify -o when generating multiple output files
    Command /Users/x5/obfuscator/build/bin/clang failed with exit code 1

    怎么破?
    等流心0316:同错,就是因为xcode9的原因吗?
    x5forever:@fighting300 编译
    我试了xcode8是好的,应该是xcode9没有兼容。你试下,应该也报错
    fighting300:这是哪个阶段出现的报错?
  • GJCode:请教下,OLLVM貌似无法针对字符串做混淆把?
    fighting300:@GJCode 有具体的错误信息么,贴下
    GJCode:@fighting300 我下午使用网上开源的字符串混淆Pass和cpp文件,cmake编译没有问题,但是在Xcode中使用时报错,提示#import <Foundation/Foundation.h>
    ~~~~~~~^
    3 errors generated.
    Command /Users/guo/Work/Armariris/obf/build/bin/clang failed with exit code 1
    fighting300:可以,有开源的可以接入,后续发一篇文章^_^

本文标题:Obfuscator-LLVM在iOS中的实践

本文链接:https://www.haomeiwen.com/subject/qtccjxtx.html