这是iOS代码混淆系列文章的最后一篇,前两篇可以点击下方链接查看
前言
前2篇文章已近讲了对于函数名的混淆,对项目中关键信息、资源文件的修改等相关混淆手段。但是,仅仅做到这几点就能万事大吉吗,黑客仍然可以通过分析代码逻辑或伪装代码来寻找程序漏洞,那么还有其他更坚固可靠的混淆方式呢,接下来就介绍下编译器级别的加固混淆方案。
iOS编译原理
iOS 开发中 Objective-C 和 Swift 都用的是 Clang / LLVM 来编译的。Clang是作为编译前端,LLVM做为编译后端,共同完成了iOS项目代码的编译阶段。
Clang(编译前端)
Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,目的是提供惊人的快速编译,比 GCC 快3倍,其中的 clang static analyzer 主要是进行语法分析,语义分析和生成中间代码,当然这个过程会对代码进行检查,出错的和需要警告的会标注出来。
LLVM(编译后端)
LLVM是一个模块化和可重用的编译器和工具链技术的集合,LLVM 核心库提供一个优化器,对流行的 CPU 做代码生成支持。LLVM 比较有特色的一点是它能提供一种代码编写良好的中间代码IR,这意味着它可以作为多种语言的后端,这样就能够提供语言无关的优化同时还能够方便的针对多种 CPU架构生成可执行代码。
Hikari
Hikari 是一个基于 Obfuscator-LLVM 的改进,增加了一些额外的自定义构建通道,更简单易用,结合使用文档,可以快速体验编译级别的代码加固效果。
OLLVM 是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个项目,该项目旨在提供一套开源的针对 LLVM 的代码混淆工具,以增加对逆向工程的难度。目前,OLLVM已经支持LLVM8.0版本。
安装
- 在这里下载最新release版的pkg文件双击安装
- 安装完成后,重启Xcode就可以在Xcode-> Toolchains -> Hikari 中看到已经有了编译器选项。
使用
然后在 Build Settings
-> Other C Flags
中加入混淆标记
-mllvm -enable-bcfobf 启用伪控制流
-mllvm -enable-cffobf 启用控制流平坦化
-mllvm -enable-splitobf 启用基本块分割
-mllvm -enable-subobf 启用指令替换
-mllvm -enable-acdobf 启用反class-dump
-mllvm -enable-indibran 启用基于寄存器的相对跳转,配合其他加固可以彻底破坏IDA/Hopper的伪代码(俗称F5)
-mllvm -enable-strcry 启用字符串加密
-mllvm -enable-funcwra 启用函数封装
-mllvm -enable-allobf 依次性启用上述所有标记
修改Xcode 相关配置,得到混淆效果。
- 选择
Xcode
->Toolchains
->Hikari
将混淆工具和项目关联 - 将所有与要运行的 target 相关的 target(包括pod进来的库),在BuildSetting中修改
Enable Index-While-Building
的值改为 NO。 - 修该BuildSetting 中的
Optimization Level
的值为None[-O0]
- 重新编译项目即可。
可能遇到的问题
-
编译过程中报错,内容如下:
Undefined symbols for architecture arm64: "___isOSVersionAtLeast", referenced from: -[MyLayoutPos posNumVal] in MyLayoutPos.o -[MyLayoutViewSizeClass myLayoutTopPadding] in MyLayoutSizeClass.o -[MyLayoutViewSizeClass myLayoutBottomPadding] in MyLayoutSizeClass.o -[MyLayoutViewSizeClass myLayoutLeadingPadding] in MyLayoutSizeClass.o -[MyLayoutViewSizeClass myLayoutTrailingPadding] in MyLayoutSizeClass.o _HikariFunctionWrapper.7182 in MyLayoutSizeClass.o _HikariFunctionWrapper.7188 in MyLayoutSizeClass.o ... ld: symbol(s) not found for architecture arm64 clang-7: error: linker command failed with exit code 1 (use -v to see invocation)
"___isOSVersionAtLeast"
符号在arm64架构下找不到,根据以往的经验,出现这种错误的时候一般都是没有导入相关动态库(.Framework),或静态库(.a)等造成的。庆幸的是已经有人在GitHub上提交了issues并给出了解决方案:
作者的回答: You probably need to explicitly link to clang-rt, available in your LLVM Toolchain directory Sorry I mean clang-rt, at Hikari.xctoolchain/usr/lib/clang/10.0.0/lib/darwin/libclang_rt.ios.a (or macOS suffix)
意思是说:可能是缺少某个编译器库造成的,需要手动将这个库添加到Xcode的Linked Frameworks andLibraries
动态链接库目录中。并说明了此库所在的目录Hikari.xctoolchain/usr/lib/clang/10.0.0/lib/darwin/libclang_rt.ios.a
,意思是在Hikari编译器的子目录中找到文件libclang_rt.ios.a
,并将他引入到Xcode项目中即可。查找路径顺序如下:
打开Show in Finder
定位到Hikari的安装目录,然后按照此路径usr/lib/clang/10.0.0/lib/darwin/libclang_rt.ios.a
找到libclang_rt.ios.a
文件,添加到Xcode的链接库中即可。
- 使用Hikari编译后,Archive 打包后,需要上传App Store 时可能会出现 “App Store” 按钮消失的问题,Archives页面右下角会出现一个提示字符:
“App Store distribution requires an Xcode Default Toolchain”
意思是:App Store 发布版需要使用Xcode 默认的Toolchain (编译工具)
如下图所示:
出现这个问题是因为,我们使用了Hikari编译器 Archive的包,所以需要想办法去除这个警告即可。在Hikari的wiki文档中,我们发现作者在AppStore Guideline 安装指南中已经说明了解决方案:
Alternatively, you could use Hikari’s toolchain to build normally then remove
DefaultToolchainOverrideInfo
from the IPA’s Info.plist只需要在Arichive 包中的Info.plist 中找到这个值”DefaultToolchainOverrideInfo” 删除即可。可以看出此字段正是标记是否使用默认Toolchain的关键。
操作步骤为下面图示顺序,注意:记得删除字段后,一定要重启Xcode才能生效的。
删除上面红色框所示的字段即可,完了后要重启Xcode才会生效。
总结
这是iOS代码混淆系列文章的最后一篇,着重讲解了iOS编译原理相关知识,编译前端Clang和编译后端LLVM在整个编译期间各自所做的工作。后面重点讲述了如何使用开源工具Hikari 进行编译混淆、加固,在实践过程中,对遇到的坑也讲了解决方案。
希望看了这几篇文章的小伙伴,能对iOS代码混淆有个初步的学习和了解,最好能结合自身条件加以实践,想必会理解的更深刻。