版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
前言
把 OLLVM 移植到 LLVM18 后,发现 -fla(控制流平坦化)并不能正常使用。
关于移植过程可以参考这篇文章 【移植 OLLVM 到 LLVM 18,C&C++代码混淆】
测试代码 fla.c
#include <stdlib.h>
int main(int argc, char** argv) {int a = atoi(argv[1]);if(a == 0)return 1;elsereturn 10;return 0;
}
使用 clang 编译并启用 Control Flow Flattening(控制流平坦化)报错如下:
D:\Projects\llvm-project\build>clang -mllvm -fla fla.c -o fla.exe
[OLLVM] run.PipelineStartEPCallback
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0. Program arguments: D:\\Projects\\llvm-project\\build\\bin\\clang.exe -cc1 -triple x86_64-pc-windows-msvc19.42.34433 -emit-obj -mrelax-all -mincremental-linker-compatible -dumpdir fla.exe- -disable-free -clear-ast-before-backend -main-file-name fla.c -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -fdebug-compilation-dir=D:\\Projects\\llvm-project\\build -fcoverage-compilation-dir=D:\\Projects\\llvm-project\\build -resource-dir D:\\Projects\\llvm-project\\build\\lib\\clang\\18 -internal-isystem D:\\Projects\\llvm-project\\build\\lib\\clang\\18\\include -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Tools\\MSVC\\14.42.34433\\include -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Tools\\MSVC\\14.42.34433\\ATLMFC\\include -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Auxiliary\\VS\\include -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\ucrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\um" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\shared" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\winrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\cppwinrt" -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Tools\\MSVC\\14.42.34433\\include -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Tools\\MSVC\\14.42.34433\\ATLMFC\\include -internal-isystem D:\\App\\VisualStudio\\IDE\\VC\\Auxiliary\\VS\\include -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.22621.0\\ucrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\um" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\shared" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\winrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\\\include\\10.0.22621.0\\\\cppwinrt" -ferror-limit 19 -fmessage-length=133 -fno-use-cxa-atexit -fms-extensions -fms-compatibility -fms-compatibility-version=19.42.34433 -fskip-odr-check-in-gmf -fdelayed-template-parsing -fcolor-diagnostics -mllvm -fla -faddrsig -o C:\\Users\\17759\\AppData\\Local\\Temp\\fla-6c1e10.o -x c fla.c
1. <eof> parser at end of file
2. Optimizer
Exception Code: 0xC0000005#0 0x00007ff627d441ff llvm::Instruction::handleMarkerRemoval(void) D:\Projects\llvm-project\llvm\lib\IR\Instruction.cpp:87:0#1 0x00007ff627d443d9 llvm::Instruction::eraseFromParent(void) D:\Projects\llvm-project\llvm\lib\IR\Instruction.cpp:94:0#2 0x00007ff62bb26d39 llvm::FlatteningPass::flatten(class llvm::Function &) D:\Projects\llvm-project\llvm\lib\Passes\Obfuscation\Flattening.cpp:101:0#3 0x00007ff62bb26316 llvm::FlatteningPass::run(class llvm::Function &, class llvm::AnalysisManager<class llvm::Function> &) D:\Projects\llvm-project\llvm\lib\Passes\Obfuscation\Flattening.cpp:20:0#4 0x00007ff62ba9ab18 llvm::detail::PassModel<class llvm::Function, class llvm::FlatteningPass, class llvm::PreservedAnalyses, class llvm::AnalysisManager<class llvm::Function>>::run(class llvm::Function &, class llvm::AnalysisManager<class llvm::Function> &) D:\Projects\llvm-project\llvm\include\llvm\IR\PassManagerInternal.h:89:0#5 0x00007ff623887eb1 llvm::PassManager<class llvm::Function, class llvm::AnalysisManager<class llvm::Function>>::run(class llvm::Function &, class llvm::AnalysisManager<class llvm::Function> &) D:\Projects\llvm-project\llvm\include\llvm\IR\PassManager.h:543:0#6 0x00007ff6238884e8 llvm::detail::PassModel<class llvm::Function, class llvm::PassManager<class llvm::Function, class llvm::AnalysisManager<class llvm::Function>>, class llvm::PreservedAnalyses, class llvm::AnalysisManager<class llvm::Function>>::run(class llvm::Function &, class llvm::AnalysisManager<class llvm::Function> &) D:\Projects\llvm-project\llvm\include\llvm\IR\PassManagerInternal.h:89:0#7 0x00007ff627f3661f llvm::ModuleToFunctionPassAdaptor::run(class llvm::Module &, class llvm::AnalysisManager<class llvm::Module> &) D:\Projects\llvm-project\llvm\lib\IR\PassManager.cpp:123:0#8 0x00007ff623888be8 llvm::detail::PassModel<class llvm::Module, class llvm::ModuleToFunctionPassAdaptor, class llvm::PreservedAnalyses, class llvm::AnalysisManager<class llvm::Module>>::run(class llvm::Module &, class llvm::AnalysisManager<class llvm::Module> &) D:\Projects\llvm-project\llvm\include\llvm\IR\PassManagerInternal.h:89:0#9 0x00007ff627f4bf21 llvm::PassManager<class llvm::Module, class llvm::AnalysisManager<class llvm::Module>>::run(class llvm::Module &, class llvm::AnalysisManager<class llvm::Module> &) D:\Projects\llvm-project\llvm\include\llvm\IR\PassManager.h:543:0
#10 0x00007ff6294ff0ff `anonymous namespace'::EmitAssemblyHelper::RunOptimizationPipeline D:\Projects\llvm-project\clang\lib\CodeGen\BackendUtil.cpp:1150:0
#11 0x00007ff6294ffafc `anonymous namespace'::EmitAssemblyHelper::EmitAssembly D:\Projects\llvm-project\clang\lib\CodeGen\BackendUtil.cpp:1216:0
#12 0x00007ff6294fa859 clang::EmitBackendOutput(class clang::DiagnosticsEngine &, class clang::HeaderSearchOptions const &, class clang::CodeGenOptions const &, class clang::TargetOptions const &, class clang::LangOptions const &, class llvm::StringRef, class llvm::Module *, enum clang::BackendAction, class llvm::IntrusiveRefCntPtr<class llvm::vfs::FileSystem>, class std::unique_ptr<class llvm::raw_pwrite_stream, struct std::default_delete<class llvm::raw_pwrite_stream>>, class clang::BackendConsumer *) D:\Projects\llvm-project\clang\lib\CodeGen\BackendUtil.cpp:1377:0
#13 0x00007ff62a0c0090 clang::BackendConsumer::HandleTranslationUnit(class clang::ASTContext &) D:\Projects\llvm-project\clang\lib\CodeGen\CodeGenAction.cpp:379:0
#14 0x00007ff62e5cf6be clang::ParseAST(class clang::Sema &, bool, bool) D:\Projects\llvm-project\clang\lib\Parse\ParseAST.cpp:183:0
#15 0x00007ff62a57dfd2 clang::ASTFrontendAction::ExecuteAction(void) D:\Projects\llvm-project\clang\lib\Frontend\FrontendAction.cpp:1183:0
#16 0x00007ff62a0bd227 clang::CodeGenAction::ExecuteAction(void) D:\Projects\llvm-project\clang\lib\CodeGen\CodeGenAction.cpp:1153:0
#17 0x00007ff62a57d80c clang::FrontendAction::Execute(void) D:\Projects\llvm-project\clang\lib\Frontend\FrontendAction.cpp:1069:0
#18 0x00007ff62a53a7a4 clang::CompilerInstance::ExecuteAction(class clang::FrontendAction &) D:\Projects\llvm-project\clang\lib\Frontend\CompilerInstance.cpp:1057:0
#19 0x00007ff62a811c06 clang::ExecuteCompilerInvocation(class clang::CompilerInstance *) D:\Projects\llvm-project\clang\lib\FrontendTool\ExecuteCompilerInvocation.cpp:272:0
#20 0x00007ff622ef44ca cc1_main(class llvm::ArrayRef<char const *>, char const *, void *) D:\Projects\llvm-project\clang\tools\driver\cc1_main.cpp:294:0
#21 0x00007ff622eda94f ExecuteCC1Tool D:\Projects\llvm-project\clang\tools\driver\driver.cpp:365:0
#22 0x00007ff622edb195 clang_main(int, char **, struct llvm::ToolContext const &) D:\Projects\llvm-project\clang\tools\driver\driver.cpp:405:0
#23 0x00007ff622f27b46 main D:\Projects\llvm-project\build\tools\clang\tools\driver\clang-driver.cpp:17:0
#24 0x00007ff6329637d9 invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:79:0
#25 0x00007ff6329636c2 __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288:0
#26 0x00007ff63296357e __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331:0
#27 0x00007ff63296386e mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:17:0
#28 0x00007ffb44e4259d (C:\Windows\System32\KERNEL32.DLL+0x1259d)
#29 0x00007ffb456eaf38 (C:\Windows\SYSTEM32\ntdll.dll+0x5af38)
clang: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 18.1.8 (https://github.com/CYRUS-STUDIO/LLVM.git 98e0b5c7f1277be725f8150102b88a992f65d196)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: D:\Projects\llvm-project\build\bin
clang: note: diagnostic msg:
********************PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: C:\Users\cyrus\AppData\Local\Temp\fla-7f9157.c
clang: note: diagnostic msg: C:\Users\cyrus\AppData\Local\Temp\fla-7f9157.sh
clang: note: diagnostic msg:********************
从报错信息来看,Flattening.cpp 的第 101 行代码在运行时发生了异常,具体错误类型是 访问权限冲突 (0xC0000005),通常意味着代码尝试访问了无效或空的内存指针。
使用 CLion 调试 Flattening
在 CLion 中打开 llvm 工程
设置 CMake
- 设置 LLVM_DIR 、 禁用 llvm-gtest
-DCMAKE_PREFIX_PATH="D:/Projects/llvm-project/build" -DLLVM_INCLUDE_TESTS=OFF
- 工具链选择 Visual Studio
关于如何编译 LLVM 可以参考这篇文章【编译 LLVM 源码,使用 Clion 调试 clang】
新增运行配置 ollvm-fla ,添加程序实参:
- 编译可执行程序
-mllvm -fla "D:\Projects\llvm-project\build\fla.c" -o "D:\Projects\llvm-project\build\fla.exe"
- 或者编译 IR 文件
-mllvm -fla -S -emit-llvm "D:\Projects\llvm-project\build\fla.c" -o "D:\Projects\llvm-project\build\fla.ll"
下断点并调试
问题原因
在 Flattening.cpp 中 65 行和 97 行都调用了 entryBB.getTerminator()->eraseFromParent();
if (bEntryBB_isConditional) {entryBB.getTerminator()->eraseFromParent();
}
重复调用 eraseFromParent 从 entryBB 中移除终止指令导致的空指针异常。
把 Flattening.cpp 中 97行的代码
if (bEntryBB_isConditional) {entryBB.getTerminator()->eraseFromParent();
}
改为
BB->getTerminator()->eraseFromParent();
修改完成执行 ninja 命令重新编译 llvm。
参考:https://github.com/DreamSoule/ollvm17/issues/39
测试
使用 clang 并启用 -fla(控制流平坦化)编译 fla.c
clang -mllvm -fla fla.c -o fla.exe
测试 fla.exe 正常运行
使用 IDA 打开编译后的可执行程序,下面时未使用混淆时的反汇编视图
经过控制流平坦化后
源码
完整源码地址:https://github.com/CYRUS-STUDIO/LLVM