+
+

版权归作者所有,如有转发,请注明文章出处: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;
+  else
+    return 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 工程

+

word/media/image1.png

+

设置 CMake

+
    +
  • 设置 LLVM_DIR 、 禁用 llvm-gtest
  • +
+
-DCMAKE_PREFIX_PATH="D:/Projects/llvm-project/build" -DLLVM_INCLUDE_TESTS=OFF
+
    +
  • 工具链选择 Visual Studio
  • +
+

word/media/image2.png +关于如何编译 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"
+

word/media/image3.png

+

下断点并调试

+

word/media/image4.png

+

问题原因

+

在 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 正常运行

+

word/media/image5.png

+

使用 IDA 打开编译后的可执行程序,下面时未使用混淆时的反汇编视图

+

word/media/image6.png

+

经过控制流平坦化后

+

word/media/image7.png

+

源码

+

完整源码地址:https://github.com/CYRUS-STUDIO/LLVM

+ +