原文地址:https://blog.csdn.net/zhanglei5415/article/details/131434931 ## 一、問題 當對含有中文的url字元串,進行NSURL對象包裝時,是不能被識別的。 不會得到期望的NSURL對象,而是返回一個nil 值 ; ```objectiv ...
編譯 OLLVM
環境準備
這裡使用的是AGP 7.2.2
、NDK 25.2.9519653
、llvm 14.0.7
、cmake 3.22.1
、python39
git
用來下載源碼
python
搞到這一步環境變數里應該已經有python了吧
NDK
AGP 的 7.2.2 版本預設使用的 NDK 版本為21.4.7075529
,對應的 LLVM 為9.0.9
。
需要根據實際情況選擇 NDK 對應的 LLVM 版本,編譯 OLLVM,LLVM 版本號可以通過Sdk_DIR\ndk\$version\toolchains\llvm\prebuilt\windows-x86_64\AndroidVersion.txt
文件看到,如SDK Manager 中的最新版本25.2.9519653
為:
14.0.7
based on r450784d1
for additional information on LLVM revision and cherry-picks, see clang_source_info.md
在 module 的build.gradle
中指定 NDK 版本
android {
ndkVersion "25.2.9519653"
}
OLLVM
可以在 github/heroims/obfuscator 倉庫的分支中找到對應的移植源碼,
13x
和14x
版本也可以在 github/yangyiyu08/ollvm-project 倉庫的對應分支中獲取。14x
版本還可以直接在 Releases 中下載作者編譯好的文件,跳過編譯的步驟。但這個文件在我的環境下會有NDK編譯錯誤的情況,我自己編譯出來的文件運行正常。
這裡使用NDK 25.2.9519653
,需要下載 14x 的源碼。
CMAKE
AGP 的 7.2.2 版本預設使用的 cmake 版本為3.18.1
,在指定 NDK 版本到 25.2.9519653 後,會在編譯時提示需要升級到 3.19 版本以上的信息。所以這裡在編譯前就通過 SDK Manager 下載 3.22.1 版本,並把所在目錄添加到環境變數。
同時在build.gradle
和CMakeLists
中修改工程的 cmake 版本。
開始編譯
在源碼的目錄執行以下命令構建 cmake 配置
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 開始預設使用 newPM進行編譯源碼,導致 ollvm 不起作用!因此,需要加上這個參數禁用掉 newPM。(在每個編譯時增加flag -flegacy-pass-manager 讓 llvm 不走 newPM 編譯也可以,但沒必要)
執行以上命令後若提示 Configuration done. 則配置成功。接下來執行以下命令開始編譯:
cmake --build build -j16
其中-j16
為指定的線程數,需要根據 CPU 調整。然後等待編譯完成
編譯完成
編譯完成後打開build/bin
目錄,找到clang.exe
、clang++.exe
、clang-cl.exe
,可以看到三個文件的MD5是相同的。
編譯後的文件大小為 137MB,對比 NDK 目錄下的 clang.exe 僅有 88.6MB。編譯後的文件可以通過strip clang.exe
命令剝離可執行文件減小到 113MB。
替換到 NDK 環境
備份與替換
首先打開當前 NDK 的 llvm 目錄,將clang.exe
、clang++.exe
、clang-cl.exe
備份,然後把上一步編譯後的文件複製到當前目錄。
複製 lib 庫
此時編譯會出現找不到libunwind
等庫的錯誤,錯誤信息顯示目錄文件不存在
CMake Error at SDK_DIR/cmake/3.22.1/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake:69 (message):
The C compiler
"SDK_DIR/ndk/25.2.9519653/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe"
is not able to compile a simple test program.
It fails with the following output:
Change Dir: APPLICATION_DIR/app/.cxx/RelWithDebInfo/703a16l3/arm64-v8a/CMakeFiles/CMakeTmp
Run Build Command(s):SDK_DIR\\cmake\3.22.1\bin\ninja.exe cmTC_c87d1 && [1/2] Building C object CMakeFiles/cmTC_c87d1.dir/testCCompiler.c.o
[2/2] Linking C executable cmTC_c87d1
FAILED: cmTC_c87d1
cmd.exe /C "cd . && SDK_DIR\\ndk\25.2.9519653\toolchains\llvm\prebuilt\windows-x86_64\bin\clang.exe --target=aarch64-none-linux-android26 --sysroot=SDK_DIR/ndk/25.2.9519653/toolchains/llvm/prebuilt/windows-x86_64/sysroot -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -static-libstdc++ -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments CMakeFiles/cmTC_c87d1.dir/testCCompiler.c.o -o cmTC_c87d1 -latomic -lm && cd ."
ld: error: unable to find library -latomic
ld: error: cannot open SDK_DIR/ndk/25.2.9519653/toolchains/llvm/prebuilt/windows-x86_64/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-aarch64-android.a: No such file or directory
ld: error: unable to find library -l:libunwind.a
ld: error: cannot open SDK_DIR/ndk/25.2.9519653/toolchains/llvm/prebuilt/windows-x86_64/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-aarch64-android.a: No such file or directory
ld: error: unable to find library -l:libunwind.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
CMakeLists.txt:10 (project)
需要把SDK_DIR/ndk/25.2.9519653/toolchains/llvm/prebuilt/windows-x86_64/lib64/
目錄下的calng
目錄,複製到/lib
目錄中,並把clang/14.0.7
修改為14.0.0
。
這裡的14.0.0
是根據錯誤日誌中出現的路徑提取出來的,在控制臺中輸入clang -v
查看當前 clang 的版本,按照日誌中出現或當前使用的 clang 版本調整。
至此,NDK 中 集成 OLLVM 已經完成了。接下來是配置和使用 OLLVM。
配置 OLLVM
這部分網上參考的文檔很多,這裡也只是簡單介紹一下參數
參數
參數 | 說明 |
---|---|
-mllbm -sub | 激活指令替換 |
-mllvm -sub_loop=3 | 如果激活了傳遞,則在函數上應用3次。預設值:1 |
-mllvm -bcf | 激活虛假控制流程 |
-mllvm -bcf_loop=3 | 如果激活了傳遞,則在函數上應用3次。預設值:1 |
-mllvm -bcf_prob=40 | 如果激活了傳遞,基本塊將以40%的概率進行模糊處理。預設值:30 |
-mllvm -fla | 激活控制流扁平化 |
-mllvm -split | 激活基本塊分割。在一起使用時改善展平 |
-mllvm -split_num=3 | 如果激活了傳遞,則在每個基本塊上應用3次。預設值:1 |
拓展參數
heroims在移植 OLLVM 時,集成了Armariris的字元串混淆功能。
參數 | 說明 |
---|---|
-mllvm -sobf | 編譯時候添加選項開啟字元串加密 |
-mllvm -seed= | 指定隨機數生成器種子 |
使用
可以在build.gradle
中進行配置,如:
android {
defaultConfig {
extrnalNativeBuild {
cmake {
cppFlags '-mllvm -fla'
}
}
}
}
也可以在CMakeLists
中進行配置,如:
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mllvm -fla -mllvm -sub -mllvm -sobf")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -fla -mllvm -sub -mllvm -sobf")
輸出比對
以配置了-fvisibility=hidden -ffunction-sections -fdata-sections
的獲取 updatemark 為例,源碼為:
static jstring getUpdate(JNIEnv *env, jobject clazz) {
struct stat sb{};
int updates = 0;
int updatens = 0;
if (stat("/data/data", &sb) == -1) {
//獲取失敗
} else {
updatens = (int) sb.st_atim.tv_nsec;
updates = (int) sb.st_atim.tv_sec;
}
std::string idRes = std::to_string(updates) + "." + std::to_string(updatens);
return env->NewStringUTF(idRes.c_str());
}
before
after
遇到的問題
虛假控制流程的問題
實際編譯的過程中,增加了-mllvm -bcf
參數後,編譯超過半個小時還是沒有完成,移除後正常編譯。
搜索了相關的問題後,發現可能是 ndk 的編譯器優化 flag 在 release 時是 -O2 導致的。
This is specifically an issue with llvm / android-ndk when compiling with thumb mode. You'll either need to disable thumb compilation (annoying) or patch the llvm to not generate this type of instructions; it's not actually an obfuscator-llvm issue.
Potentially try upgrading your ndk as well, though I'm doubtful that will fix this issue. If I have extra time later I can try to find the patch I needed to create for llvm to specifically work around this issue.
但在我這邊,debug 依然是沒有響應,只能是去掉-bcf
。
CMAKELIST 的 Release 不生效問題
CMAKE_C_FLAGS
和CMAKE_C_FLAGS_DEBUG
配置的參數都可以正常生效,但CMAKE_C_FLAGS_RELEASE
配置無法在 release 時生效。只能配置在CMAKE_C_FLAGS
中,然後在 CMakeLists 中判斷當前環境是否為 DEBUG。
參考資料
- yangyiyu08/【清羽】Windows10下編譯OLLVM-14.x
- heroims/OLLVM代碼混淆移植與使用
- obfuscator/issues/-bcf crashes when compiling ndk project