基于Obfuscator-LLVM代码混淆工具在Xcode中集成,并记录针对代码混淆方案的实践过程

本文介绍了代码混淆在保护软件安全中的重要性,并重点讲解了如何在Xcode中集成开源混淆工具Obfuscator-LLVM。通过控制流扁平化、指令替换和虚假控制流等技术,增加代码复杂性,防止逆向工程。文章详细记录了Obfuscator-LLVM的下载、编译、配置Xcode和设置混淆参数的过程,以及混淆前后代码的对比,为iOS开发者提供了一种增强代码安全性的实践方法。
一、前言

代码逆向,从来都不神秘,有人的地方就有江湖,同样有代码的地方,就有逆向,如何防护代码被逆向分析或破解,也是正向开发者们必须思考的一个问题,考虑代码混淆实际上就是增加代码的破解难度,防止逆向工程和代码分析,以保护知识产权和应用程序的安全性,它在软件开发过程中可以用于保护关键算法、隐藏敏感信息、防止代码剽窃和修改,以及减少应用程序的漏洞被利用的风险。

二、混淆方案
  1. 修改方法和变量名:将方法和变量名更改为无意义的、随机生成的名称。可以使用工具如Mach-O 编译器(Mach-O Compiler)来自动化执行此操作。

  2. 使用宏定义或函数替换:将方法调用替换为宏定义或函数调用,使得代码的结构更难以理解和分析。

  3. 字符串加密:对字符串进行加密,以防止明文字符串在二进制文件中可见。在运行时,解密字符串以便正常使用。

  4. 添加无用代码:在代码中添加大量的无用代码、冗余代码和条件分支,以增加逆向工程的难度。

  5. 类和方法重命名:将类名和方法名更改为不直观的名称,使代码更难以理解。可以使用自动化工具帮助进行重命名。

  6. 函数内联:使用内联关键字将函数内联到调用位置,这样可以减少函数调用的可见性。

  7. 虚拟化:使用虚拟机或者JIT(Just-In-Time)编译技术将部分敏感代码动态地转换为特定平台的指令序列。

  8. 加密算法:对敏感数据进行加密处理,以防止数据泄露。

 以上是我们通常会想到的一些代码混淆的办法,不过在具体操作中过于繁琐,运用起来可能就不那么容易了。

三、混淆工具库

在涉及以上混淆方案里面的各种办法时,我们基本会选择工具库,古人云:“工欲善其事必先利其器”,所谓器这才是我们需要研究的目标,目前主流的此类工具包括:Obfuscator-LLVM、iXGuard、Jscrambler,Armariris等,这些工具库都旨在增加代码的复杂性和混淆性,从而增强代码的安全性,防止恶意用户对代码进行逆向工程或篡改,选择适合自己项目需求的工具,可以帮助开发人员提高应用程序的安全性并减少潜在的风险,接下来我们先简单了解一些它们都有什么独特的特点和功能。

1、Obfuscator-LLVM:

它是基于 LLVM 编译器框架开发的一个开源工具,用于对代码进行混淆。它可以改变代码的结构、重命名符号、插入虚假代码等,以增加代码的复杂性和混淆性,从而增加代码的逆向工程难度。Github:https://github.com/obfuscator-llvm/obfuscator

 2、iXGuard:iXGuard 是一款专门针对 iOS 应用的全面代码保护工具。它通过方法名混淆、字符串加密、控制流扰乱等技术来保护应用程序免受逆向工程和代码泄露的威胁,并提供了防止调试和反调试的功能。官网:https://www.guardsquare.com/ixguard

3、Jscrambler:Jscrambler 是一个面向 JavaScript 应用的代码混淆和保护平台。它使用多种技术,如标识符混淆、自动遮蔽、代码加密等,以保护 JavaScript 代码免受逆向工程、代码注入和代码盗用的风险。官网:https://jscrambler.com/

4、Armariris:Armariris 是一个开源的 Android 应用程序保护工具,它主要通过修改字节码、资源文件加密、反调试等技术来提供代码保护,它还可以隐藏敏感信息、检测恶意行为并阻止反向工程。Github:https://github.com/GoSSIP-SJTU/Armariris

综合考虑,在iOS相关的开发中,我们可能会选择Obfuscator-LLVM 或 iXGuard 作为混淆工具库,当然了国内某大厂的一些加固方案这里就不介绍了,不过介于后者iXGuard是一款商业化工具,续费付费使用,对于普通开发者来说可能负担不起,而前者Obfuscator-LLVM 是一个开源的工具,它基于 LLVM 编译器框架,并以开源许可证发布,这就意味可以免费获取和使用Obfuscator-LLVM 的源代码,并根据需要自定义或修改工具以满足特定的需求,那就很符合笔者的胃口了,后续笔者会针对Obfuscator-LLVM在下载、编译、生成工具链、配置Xcode和混淆参数,以及混淆前后代码对比做出比较详细的参考记录。


友情提示:前面的路不太好走,如同蜀道之难,每一步可能就一个坑,坑坑惹人烦,如需乘坐索道,请悬崖勒马,赶快离开。


四、Obfuscator-LLVM实践记录

简介:Obfuscator-LLVM是一个基于LLVM编译器框架的代码混淆工具。它通过对源代码进行重写和变换,改变代码的结构和逻辑,从而使代码变得难以理解和分析。Obfuscator-LLVM可以对C、C++和Objective-C等语言的代码进行混淆处理。它采用了多种技术,如控制流平坦化、函数内联、代码替换、字符串加密和虚假代码插入等,以增加代码的复杂性和混淆度。这样一来,即使有人获取了混淆后的代码,也很难还原出原始的逻辑和算法。

1、下载源Obfuscator-LLVM源文件,通过Git方式,注意我们选择的是13.x版本,这个过程比较慢,需要耐心等待。

git clone -b llvm-13.x https://github.com/heroims/obfuscator.git

 2、下载CMake构建工具,Obfuscator-LLVM需要此工具来编译,所以必须先安装CMake工具,官网:https://cmake.org/

CMake是一个跨平台的开源构建工具,用于管理软件项目的构建过程,它通过一个名为CMakeLists.txt的文本文件来配置和描述项目的构建流程。

CMake的设计理念是提供一种与平台和编译器无关的构建系统。通过编写CMakeLists.txt文件,开发者可以描述项目的源代码、编译选项、依赖关系和构建规则等信息。CMake根据这些描述生成特定平台和编译器所需的原生构建脚本(如Makefile或Visual Studio解决方案),从而实现了跨平台、跨编译器的构建过程。

CMake支持多种编程语言和平台,包括C、C++、Java、Python等,并且可以生成针对各种构建系统和集成开发环境(IDE)的输出,例如Make、Ninja、Visual Studio、Xcode等。这使得开发者可以在不同的操作系统和开发环境中使用统一的构建描述,简化了项目的维护和移植工作。

CMake还提供了丰富的功能和选项,如条件判断、循环、变量定义和引用、模块管理等,可以高度定制化项目的构建过程。它还支持包管理器的集成,便于管理项目的依赖库。

总之,CMake是一个强大而灵活的构建工具,旨在简化跨平台软件项目的构建过程。通过使用CMake,开发者可以更方便地管理和构建复杂的软件项目,并实现跨操作系统和编译器的移植性。

这里要注意下:CMake提供了可视化UI和源码两种方式,笔者在使用可视化UI操作时一直没有成功,后续便采用安装源码命令行的方式编译Obfuscator-LLVM,下载地方如下图:

 工具界面:

源码:https://github.com/Kitware/CMake/releases

  源码命令行安装:

sudo ./bootstrap && sudo make && sudo make install

 

 安装完查看版本:

cmake --version

 3、编译Obfuscator-LLVM源文件,具体配置和构建流程如下步骤:

 

 之后就是漫长等待,如果有失败,继续执行最后一个命令:make -j8 即可。

总结命令如下:

% git clone -b llvm-13.x https://github.com/heroims/obfuscator.git
% cd obfuscator
% mkdir build
% cd build
% cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF ../llvm
% make -j8

为了更清晰以上命令的作用,详细解释如下:

这段命令是用来下载、配置和构建 Obfuscator-LLVM 的过程。以下是对每个命令的解释:

git clone -b llvm-13.x https://github.com/heroims/obfuscator.git:
这个命令使用 Git 工具将 Obfuscator-LLVM 的源代码克隆到本地。-b llvm-13.x 参数指定了要克隆的分支(在这个例子中是名为 llvm-13.x 的分支),https://github.com/heroims/obfuscator.git 是源代码的仓库地址。

cd obfuscator:
进入刚刚克隆的 Obfuscator-LLVM 源代码目录。

mkdir build:
创建一个用于构建的目录,通常被称为构建目录或生成目录。在这个例子中,它被命名为 build。

cd build:
进入构建目录。

cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF ../llvm:
这是用于配置构建的 CMake 命令。它会根据参数指定的选项生成构建所需的文件。下面是各个参数的解释:

-DCMAKE_BUILD_TYPE=Release:指定构建类型为 Release,即生成优化后的可执行文件。
-DLLVM_CREATE_XCODE_TOOLCHAIN=ON:开启生成 Xcode 工具链的选项,该工具链可以在 Xcode 中使用 LLVM 和 Clang。
-DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi":启用指定的 LLVM 项目,包括 clang 编译器、libc++ 和 libc++abi 库。
-DLLVM_ENABLE_NEW_PASS_MANAGER=OFF:禁用新的 Pass 管理器,使用旧的 Pass 管理器。
../llvm 是指向 LLVM 源代码目录的路径,CMake 会根据这个路径寻找所需的源代码和配置文件。

make -j8:
运行 make 命令开始构建过程。-j8 参数表示并行构建,其中 8 表示同时运行 8 个任务。这可以加快构建速度。

若顺利编译通过,可看到如下命令结束,至少笔者是如此。

 4、生成Xcode工具链

直到顺利编译生成

开始安装工具链

 命令行:

sudo make install-xcode-toolchain

接下来把生成的工具链移到到Xcode开发者目录

命令行: 

sudo mv /usr/local/Toolchains  /Library/Developer/

以上两句命令行详细解释如下:

sudo make install-xcode-toolchain:
这个命令使用 make 工具安装 Xcode 工具链。install-xcode-toolchain 是 make 的一个目标,它会将生成的 Xcode 工具链安装到默认的路径中。

sudo mv /usr/local/Toolchains  /Library/Developer/:
这个命令用于移动已安装的 Toolchains 目录到 /Library/Developer/。/usr/local/Toolchains 是默认的 Toolchains 安装路径,而 /Library/Developer/ 是 Xcode 的开发者目录。通过将 Toolchains 目录移动到合适的位置,以便 Xcode 可以识别并使用它。

使用 sudo 命令作为超级用户权限执行此命令。

这两个命令的目的是将构建得到的 Xcode 工具链安装到适当的位置,以便在 Xcode 中使用 Obfuscator-LLVM 提供的功能。

% sudo make install-xcode-toolchain
% sudo mv /usr/local/Toolchains  /Library/Developer

5、启用Obfuscator-LLVM工具链

打开Xcode 11+ ,选择菜单栏 - Xcode - Toolchains - org.llvm.13.0.1,如下图:

 6、混淆编译代码

在Xcode中启动LLVM后开始编译Command+B,这时候会出现一个错误,如下图:

 解释如下:

clang-13: error: unknown argument: '-index-store-path':
这个错误表示 Clang 13 不认识 -index-store-path 参数。该参数用于指定索引文件的存储路径,以支持代码编辑器、IDE 或其他工具对代码进行索引和导航。可能的原因是你正在使用的 Clang 版本不支持该参数。你可以查阅 Clang 的文档或使用 --help 命令查看可用的参数列表来确认是否存在该参数。

clang-13: error: cannot specify -o when generating multiple output files:
这个错误表示在生成多个输出文件时不能使用 -o 参数。-o 参数用于指定生成的单个输出文件的名称。然而,当你尝试生成多个输出文件时,Clang 不能通过一个参数指定多个文件的名称。你需要检查编译命令中是否使用了 -o 参数并确保只有一个输出文件。

解决错误:

既然是索引出了问题,那么我们可以选择在LLVM编译时关闭它,在xcode中找到Enable index-while-building,然后把默认的Default修改能No,如下图:

 

 7、在Xcode中配置编译时的混淆参数命令

首先找到 Other C Flags 选项,在其中开始配置混淆参数,这里要注意不要混淆了Other Linker Flags,一定是 Other C Flags,不然没有效果,两者详细介绍如下:

"Other C Flags" 是一个构建设置选项,用于指定编译器在编译过程中使用的其他参数。这些参数可以对编译器的行为产生一定影响,以下是一些常见的影响:

  1. 警告标志:通过在 "Other C Flags" 中使用编译器的警告标志(例如 -W-Wall-Werror)可以启用编译器的警告功能,并将警告视为错误。这有助于提高代码质量和发现潜在的问题。

  2. 优化标志:通过在 "Other C Flags" 中使用优化标志(例如 -O1-O2-O3)可以指定编译器对代码进行优化的级别。不同级别的优化可能会影响代码的执行速度和大小。

  3. 宏定义:通过在 "Other C Flags" 中使用 -D 参数,可以定义预处理器宏。这使得您可以在编译时通过宏来控制代码中的条件编译,以实现不同的编译选项或功能开关。

  4. 包含路径:通过在 "Other C Flags" 中使用 -I 参数,可以指定编译器在搜索头文件时要包含的额外路径。这对于包含非标准位置的头文件十分有用。

  5. 编译器选项:通过在 "Other C Flags" 中使用其他编译器特定的选项,可以对编译过程进行更精细的控制。例如,您可以使用 -march 指定目标架构,使用 -std 指定C语言版本,或者使用其他特定于编译器的选项。

需要注意的是,不同的编译器可能支持不同的标志和选项。在使用特定的标志之前,建议查阅相关文档或参考编译器的说明以了解其作用和用法。此外,"Other C Flags" 的具体效果和含义也取决于所使用的构建系统和开发环境。

"Other Linker Flags" 是一个构建设置选项,用于指定链接器在编译和链接过程中使用的额外参数。它们可以对链接器的行为产生一定影响,以下是一些常见的影响:

  1. 指定库文件路径:通过在 "Other Linker Flags" 中使用 -L 参数,可以指定链接器搜索库文件的路径。这使得链接器能够找到所需的库文件,以便在链接时正确解析和连接函数引用。

  2. 添加库文件:通过使用 -l 参数,在 "Other Linker Flags" 中指定要链接的库文件的名称,可以将特定的库文件与项目进行关联。这样,链接器会在最终可执行文件中包含该库文件的代码和符号,使得程序能够调用库中提供的功能。

  3. 解决符号冲突:有时可能会遇到多个库文件中包含相同符号的情况,这会导致链接器无法确定要使用哪个定义。在这种情况下,可以使用 "Other Linker Flags" 中的 -force_load-ObjC 参数来强制链接器加载指定的库文件,确保使用正确的符号定义。

  4. 定义全局变量:使用 -defsym 参数,可以在 "Other Linker Flags" 中定义全局变量,并使其在链接过程中可用。这对于一些特殊的需求或特定平台上的代码兼容性很有用。

  5. 调试和优化选项:通过 "Other Linker Flags" 可以指定链接器的调试和优化选项,例如启用符号表、关闭优化等。这可以影响生成的可执行文件的调试和性能特性。

以下是一些常见的O-LLVM混淆参数及其意义:

  1. -fla(Function Level Obfuscation):对函数进行混淆。它通过改变函数控制流和添加无用指令来增加代码的复杂性,使得代码更难以阅读和理解。

  2. -sub(Instruction Substitution):对指令进行替换。它会使用等效但不同的指令替换现有指令,以增加代码的多样性,增加代码分析和逆向工程的难度。

  3. -bcf(Bogus Control Flow):生成虚假的控制流。该参数用于插入虚假的分支语句,使得程序的控制流图变得复杂和混乱,增加了逆向工程的难度。

  4. -sobf(String Obfuscation):对字符串进行混淆。它将程序中的字符串进行编码或加密,使得字符串常量难以直接读取,增加了代码分析的难度。

  5. -hide(Symbol Hiding):隐藏符号信息。该参数用于隐藏函数和变量的名称,使得反汇编和符号表分析更加困难。

  6. -split(Code Splitting):将函数体切分成多个片段进行混淆。该参数会将函数体中的指令划分为多个片段,并对这些片段进行重新排列和插入,增加了代码的复杂性。

  7. -flatten(Flattening):扁平化控制流。它通过将嵌套的条件语句转换为扁平的顺序结构,增加代码的复杂度,使得逻辑分析和反汇编更加困难。

开启控制流扁平化

-mllvm -fla 开启控制流扁平化
-mllvm -split 激活基本块划分。一起使用时能提高打平能力。
-mllvm -split_num=3 如果激活控制流打平,对每一个基本块应用三次控制流打平,默认使用1次。

开启指令替换

-mllvm -sub 开启指令替换
-mllvm -sub_loop=3 如果激活了指令替换,使用这个选项在一个函数中应用3次指令替换,默认应用1次。

开启虚假控制流

-mllvm -bcf 开启虚假控制流
bcf可以配合下面参数使用
-mllvm -bcf_loop=3 设置函数混淆次数为3次 不加此选项默认为1次
-mllvm -bcf_prob=40 设置代码块被混淆的概率是40%,默认30%

例如:-mllvm -fla -mllvm -bcf -mllvm -sub -mllvm -split -mllvm -sobf

 8、混淆前后代码对比

测试代码1 -这是一个动态库的iOS代码:

#import "Obfuscator_LLVM_DEMO.h"

@implementation Obfuscator_LLVM_DEMO

+(void)load{
    
    NSString *userName = @"mapboo";
    
    if ([userName isEqualToString:@"mapboo"]) {
        NSLog(@"登录成功");
    }else{
        NSLog(@"登录失败");
    }
}

@end

笔者采用 Hopper Disassembler 来查看,顺便介绍一下这款工具:

Hopper Disassembler(Hopper 反汇编器)是一款用于逆向工程和代码分析的工具。它可以将机器码转换为可读的汇编指令,以帮助理解和分析二进制文件的内部结构和功能。以下是一些 Hopper Disassembler 的特点和功能:

  1. 反汇编:Hopper Disassembler 能够对多种体系结构的二进制文件进行反汇编,包括 x86、ARM、MIPS、PowerPC 等。它能够将二进制指令转换为人类可读的汇编语言表示形式。

  2. 交互式界面:Hopper Disassembler 提供了一个用户友好的界面,使得在反汇编和分析过程中可以直观地查看和编辑汇编代码,并且支持与反汇编之间的导航和搜索。

  3. 符号注释和反汇编注释:Hopper Disassembler 支持给反汇编代码添加注释,以增加代码的可读性和理解性。可以通过注释来标记函数、变量、数据结构等重要信息。

  4. 控制流图:Hopper Disassembler 能够生成程序的控制流图,帮助理解代码中各个基本块之间的控制流关系,以及条件分支和循环结构的组织。

  5. 数据分析:Hopper Disassembler 能够识别和分析程序中的数据结构,如字符串、数组和结构体,并在代码中给出相应的注释和标记。

  6. 插件支持:Hopper Disassembler 允许开发者编写插件来扩展其功能。这使得用户可以根据自己的需求和场景,添加新的特性和工具。

需要注意的是,Hopper Disassembler 是一款商业软件,用户需要购买许可证才能使用完整的功能。它在逆向工程和代码分析领域广受欢迎,为安全研究人员、逆向工程师和开发者提供了强大的工具和资源。

混淆代码 - 前  如下图:

混淆代码 - 后  如下图: 

 


测试代码2 -这是一个macOS 的APP代码:

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(100, 150, 400, 100)];
    [button setTitle:@"Obfuscator-LLVM\n\n用户登录"];
    [button setTarget:self];
    [button setAction:@selector(compareStrings:)];
    [self.view addSubview:button];
}

- (void)compareStrings:(id)sender {
    NSString *userName = @"mapboo";
    if ([userName isEqualToString:@"mapboo"]) {
        NSAlert *alert = [[NSAlert alloc] init];
        [alert setMessageText:@"登录成功"];
        [alert addButtonWithTitle:@"确定"];
        [alert runModal];
    }else{
        NSLog(@"登录失败");
    }
    
}



@end

混淆代码 - 前

 混淆代码 - 后

 混淆前后效果一致:

注意:如果混淆配置参数包含-mllvm -sobf,可能会出现字符串乱码问题,笔者没有添加此参数,大家可自行添加各个参数做对比测试。


至此,想说点什么,又不知从何说起,只能沧海一声笑,滚滚两行泪啊,写作不易,总计花费24*3H,就这样吧,实践记录到此结束。


后语:写文之时,家中小儿问爸爸何为文章,侧目告之文章即是心得与传承,随之摇头而去,故将此文送之于他,四岁伊始,未来可期。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

群鸿

感谢认可,多谢打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值