最近工作中遇到 ios 代码需要做混淆的需求,因此硬着头皮专研怎么将 ollvm 移植到 xcode 中使用。在网上查到的 ios 集成 ollvm的方法大多是说:“将 ollvm4.0 编译结果制作成一个xcode插件”,但这种应该只适用较老的xcode版本,在xcode10以上的版本并不适用。本人需要移植的是 xcode12.4,对应的 clang 版本是12.0.0,因此那种方法并不适用,且经过尝试,确实没有成功(当然也不排除本人操作不当的可能)。
移植环境:
移植的方法网上比较多,主要是从官网上 ollvm4.0 移植对应的 Obfuscation pass 到高版本 llvm上。如果llvm版本相差太大,可能有的结构体或者方法会有些许改变,编译的时候就会报错,本人的解决方法是将LLVM工程导入到 CLion 中,针对报错的代码,对比高低版本llvm使用的改变(Find in file功能),然后将 Obfuscation pass 中报错代码修正。
用 CLion 打开 Obfuscate/llvm/CMakeLists.txt ,选择 open as project;
在 File | Settings | Build, Execution, Deployment | CMake 的 CMake options 中配置编译选项,Build Type选Release就快一些,编译选项如下:
# 使用 ninja -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=Off # 默认使用 make -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=Off # 如果要移植到的 NDK 或者 xcode 的toolchain中包含 lib64,则还需添加 # -DLLVM_LIBDIR_SUFFIX=64
在 File | Settings | Build, Execution, Deployment | Toolchains 中配置 C++编译器是使用 g++还是clang++,C编译器是使用 g 还是 clang,Make是选择 make 还是ninja。这一步其实默认就可以。
cmake 完成后,开始 Build-Build Project 构建工程,如果有报错会在下边栏中给出错误信息和错误代码位置,点过去就可,方便排查错误。另外用CLion的好处还有就是可以跟踪符号,直接点击便可跳转代码。
// Flags for obfuscation static cl::opt<bool> Flattening("fla", cl::init(false), cl::desc("Enable the flattening pass")); static cl::opt<bool> BogusControlFlow("bcf", cl::init(false), cl::desc("Enable bogus control flow")); static cl::opt<bool> Substitution("sub", cl::init(false), cl::desc("Enable instruction substitutions")); static cl::opt<std::string> AesSeed("aesSeed", cl::init(""), cl::desc("seed for the AES-CTR PRNG")); static cl::opt<bool> Split("split", cl::init(false), cl::desc("Enable basic block splitting")); static cl::opt<bool> StringObf("sobf", cl::init(false), cl::desc("Enable the string obfuscation")); PassManagerBuilder::PassManagerBuilder() { OptLevel = 2; ... CallGraphProfile = true; //ollvm add begin // Initialization of the global cryptographically // secure pseudo-random generator if (!AesSeed.empty()) { if (!llvm::cryptoutils->prng_seed(AesSeed.c_str())) exit(1); } //ollvm add end } void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { // Load sample profile before running the LTO optimization pipeline. ... // Infer attributes about declarations if possible. PM.add(createInferFunctionAttrsLegacyPass()); //ollvm add begin PM.add(createSplitBasicBlock(Split)); PM.add(createBogus(BogusControlFlow)); if (Flattening) { // Lower switch PM.add(createLowerSwitchPass()); } PM.add(createFlattening(Flattening)); PM.add(createSubstitution(Substitution)); PM.add(createStringObfuscation(StringObf)); //ollvm add end if (OptLevel > 1) { ... } PM.add(createJumpThreadingPass(/*FreezeSelectCond*/ true)); }
add_subdirectory(Obfuscation)
llvm-project/llvm/lib/Transforms/IPO/CMakeLists.txt 中添加:
add_llvm_component_library( ... Obfuscation )
llvm12中已经弃用 LLVMBuild.txt,这一项本来是加在 llvm-project/llvm/lib/Transforms/IPO/LLVMBuild.txt 中,现在改到加在这里。
移植的 ollvm12.x (兼 Armariris 字符串加密)已上传至:https://github.com/Chenyangming9/llvm-project/tree/release/ollvm12.x
不管是哪个平台,最好先事先看下原来的llvm的版本 (命令:clang --version),然后将ollvm移植到对应的llvm版本中。
git clone ollvm代码地址 mkdir llvm_root/build_release # CLion中默认生成在 cmake-build-release 或 cmake-build-debug cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS='clang' -DLLVM_INCLUDE_TESTS=OFF -DLLVM_LIBDIR_SUFFIX=64 ../llvm #大多的NDK中有 lib64,所以添加-DLLVM_LIBDIR_SUFFIX=64,xcode中没有,不用加。为什么加 -DLLVM_ENABLE_PROJECTS='clang',因为 Obfuscation pass会编译进 clang,所以要加该项 ninja -j7 # 如果有命令找不到,则按照 官网 [https://releases.llvm.org/12.0.0/docs/GettingStarted.html](https://releases.llvm.org/12.0.0/docs/GettingStarted.html) 中说明配置
编译完成后,将 llvm_root/build_release 中 bin 、include、lib、lib64 覆盖拷贝到 android-ndk/toolchains/llvm/prebuilt/linux-x86_64 中即可。
git clone ollvm代码地址 mkdir llvm_root/build_release # CLion中默认生成在 cmake-build-release 或 cmake-build-debug cmake -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS='clang' -DLLVM_INCLUDE_TESTS=OFF ../llvm #大多的NDK中有 lib64,所以添加-DLLVM_LIBDIR_SUFFIX=64,xcode中没有,不用加。为什么加 -DLLVM_ENABLE_PROJECTS='clang',因为 Obfuscation pass会编译进 clang,所以要加该项 make install-xcode-toolchain -j10 # 编译完成后生成的工具链位于 /usr/local/Toolchains,将其移动到 /Library/Developer/ 目录 sudo mv /usr/local/Toolchains /Library/Developer/
DLLVM_CREATE_XCODE_TOOLCHAIN 选项参考:https://llvm.org/docs/CMake.html#llvm-related-variables
说明: 之前尝试使用 -G “Xcode”,则可以在 xcode 中打开工程,但报错如下:
CMake Error in utils/benchmark/CMakeLists.txt: The custom command generating /usr/local/Toolchains/LLVM12.0.0.xctoolchain is attached to multiple targets: install-xcode-toolchain install-xcode-toolchain-stripped but none of these is a common dependency of the other(s). This is not allowed by the Xcode "new build system".
找不到解决方法,就弃用了,哎。
打开后 xcode 后,在 Xcode-Preferences-Components-Toolchains看到生成好的工具链,如下图:
或者:Xcode-Toolchains中查看到,如下图:
更换工具链,在以上两个位置都可以更换。使用新工具链编译 Xcode 项目,报错unknown argument: ‘-index-store-path’,需要到项目 Build Settings 关闭 Index-While-Building,应该是这个参数在开源的 LLVM 项目中没有实现。如下:
关闭该选项,如下图:
添加 ollvm 编译选项,-mllvm -fla -mllvm -sub -mllvm -bcf -mllvm -sobf
混淆前:
混淆后:
如果文章不错,也请多支持,如果有不对的地方,也请多指正~