官方的OLLVM适配到LLVM-4.0就没有再更新了,不过网上有许多大佬开源的适配新版本LLVM的OLLVM可以参考。
环境及源码
Mac 14.6.1
Android Studio
NDK 25.1.8937393
cmake 3.31.5
ninja 1.12.1
下载OLLVM
NDK 25.1.8937393对应的LLVM版本为14.x,因此我从网上找了几个适配到14之后的OLLVM进行编译,最终使用的是https://github.com/heroims/obfuscator。
1 | $ git clone --depth=1 -b release/14.x https://github.com/llvm/llvm-project.git |
这里作者提供了两个版本的patch,我使用NewPass版本编译后,clang没有混淆的选项,可能是编译时没有配置正确,使用LegacyPass可以正常使用。
New Pass Manager是 LLVM 项目中对原有Legacy Pass Manager的重新设计和改进,从 LLVM 11 开始被引入,并在后续版本中逐步推广。新 Pass 管理器在性能、易用性和灵活性方面相较旧 Pass 管理器有许多优化,目前已经被推荐为默认的 Pass 管理方式。
- reject选项,表示如果patch内容如果不能应用则生成.rej文件记录没有被应用的patch部分,可以后续手动修改,不过这里如果使用14.x版本,patch可以全部正常应用。
- ignore-whitespace选项,表示比较和应用补丁时忽略空格变化。
编译OLLVM
1 | $ cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF |
- -G Ninja:使用 ninja 进行编译源码
- -DLLVM_ENABLE_PROJECTS=”clang”:启用 clang,有多个选择 但我们只需要 clang,官方文档有说明
- -DCMAKE_BUILD_TYPE=Release:构建 release 版本,比 debug 版本编译快很多
- -DLLVM_INCLUDE_TESTS=OFF:关闭 llvm 的头文件测试,也是为了加快编译速度
- -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF:这个非常重要,llvm-12.x 开始默认使用 new pass manager 进行编译源码,导致 ollvm 不起作用
编译:
1 | $ cmake --build build -j16 |
配置Android Studio
1.编译成功后,需要把build/bin目录中的clang
clang++
clang-format
clang-cl
4个文件复制到ndk对应目录中(最好先备份原文件):
1 | ~/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin |
2.将build/lib/clang/14.0.6/include目录中的__stddef_max_align_t.h
float.h
stdarg.h
stdbool.h
stddef.h
5个文件也复制到ndk对应目录中:
1 | ~/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include |
3.拷贝库文件
1 | $ cd /Users/fanrong/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64 |
否则在编译arm架构时会报错缺少atomic或unwind等库文件,如果只编译arm64架构应该就不需要拷贝了。
NDK中使用OLLVM
参数 | 说明 |
---|---|
-mllvm | 传递给 LLVM 的内部选项 |
-fla | 启用控制流平坦化(Control Flow Flattening) |
-sub | 启用指令替换(Instruction Substitution) |
-sub_loop=3 | 一个函数应用3次sub,默认为1 |
-bcf | 启用伪代码插入(Bogus Code Insertion) |
-bcf_loop=3 | 一个函数应用3次bcf,默认为1 |
-bcf_prob=40 | 一个基本块会有40%的概率被混淆,默认为30% |
-split | 启用基本块分割,和fla一起用时增强fla |
-split_num=3 | 一个基本块应用3次split,默认为1 |
Heroims 在移植 OLLVM 时,集成了 Armariris 的字符串混淆功能。(不过好像只对char *起作用了,对char []没生效)
| 参数 | 说明 |
| :—- | :—- |
| -sobf | 启用字符串加密 |
在 build.gradle 中进行配置,如:
1 | android { |
如果需要单个函数混淆的情况:
1 | __attribute((__annotate__("bcf"))) |
从llvm-project源码看LLVM版本:
llvm-18:llvm-project/llvm/CMakeLists.txt
llvm-19:llvm-project/cmake/Modules/LLVMVersion.cmake
reference
Windows 编译 OLLVM NDK 使用
OLLVM代码混淆移植与使用(再续)
https://github.com/sr-tream/obfuscator/tree/master
移植 OLLVM 到 Android NDK,Android Studio 中使用 OLLVM
移植 OLLVM 到 LLVM 18,C&C++代码混淆
https://github.com/CYRUS-STUDIO/LLVM