├── images ├── BCF.png ├── CFF.png ├── MBA.png └── iSub.png ├── source ├── BCF │ ├── BcfAttribute.cpp │ ├── CMakeLists.txt │ ├── BcfPass.hpp │ ├── LICENSE-OBFUSCATOR.TXT │ └── BcfPass.cpp ├── CFF │ ├── CffAttribute.cpp │ ├── CMakeLists.txt │ ├── CffPass.hpp │ ├── LICENSE-OBFUSCATOR.TXT │ └── CffPass.cpp ├── MBA │ ├── MbaAttribute.cpp │ ├── CMakeLists.txt │ ├── MbaPass.hpp │ └── MbaPass.cpp ├── ISUB │ ├── iSubAttribute.cpp │ ├── CMakeLists.txt │ ├── iSubPass.hpp │ └── iSubPass.cpp ├── CMakeLists.txt ├── Passes │ ├── CMakeLists.txt │ ├── ObfuscationPassManager.hpp │ ├── IObfuscationPass.hpp │ ├── FuncAnnotationsParser.hpp │ ├── IObfuscationPass.cpp │ ├── ObfuscationPassManager.cpp │ └── FuncAnnotationsParser.cpp ├── common.hpp ├── FuncAttributeStore.hpp ├── FuncAttributeStore.cpp └── FuncAttribute.hpp ├── .vscode ├── settings.json ├── c_cpp_properties.json └── tasks.json ├── tests ├── bcfTest.cpp ├── TestAll.cpp ├── cffTest.cpp ├── mbaTest.cpp └── isubTest.cpp ├── .gitignore ├── main.cpp ├── CMakeLists.txt └── README.md /images/BCF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slattz/ObfusC/HEAD/images/BCF.png -------------------------------------------------------------------------------- /images/CFF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slattz/ObfusC/HEAD/images/CFF.png -------------------------------------------------------------------------------- /images/MBA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slattz/ObfusC/HEAD/images/MBA.png -------------------------------------------------------------------------------- /images/iSub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Slattz/ObfusC/HEAD/images/iSub.png -------------------------------------------------------------------------------- /source/BCF/BcfAttribute.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAttribute.hpp" 2 | #include "BcfPass.hpp" 3 | 4 | namespace obfusc { 5 | NEW_FUNC_ATTR(Bcf, 'b', 'c', 'f'); 6 | } -------------------------------------------------------------------------------- /source/CFF/CffAttribute.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAttribute.hpp" 2 | #include "CffPass.hpp" 3 | 4 | namespace obfusc { 5 | NEW_FUNC_ATTR(Cff, 'c', 'f', 'f'); 6 | } -------------------------------------------------------------------------------- /source/MBA/MbaAttribute.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAttribute.hpp" 2 | #include "MbaPass.hpp" 3 | 4 | namespace obfusc { 5 | NEW_FUNC_ATTR(Mba, 'm', 'b', 'a'); 6 | } -------------------------------------------------------------------------------- /source/BCF/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE BcfAttribute.cpp) 2 | target_sources(ObfusC PRIVATE BcfPass.cpp) 3 | target_sources(ObfusC PRIVATE BcfPass.hpp) -------------------------------------------------------------------------------- /source/CFF/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE CffAttribute.cpp) 2 | target_sources(ObfusC PRIVATE CffPass.cpp) 3 | target_sources(ObfusC PRIVATE CffPass.hpp) -------------------------------------------------------------------------------- /source/ISUB/iSubAttribute.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAttribute.hpp" 2 | #include "iSubPass.hpp" 3 | 4 | namespace obfusc { 5 | NEW_FUNC_ATTR(iSub, 'i', 's', 'u', 'b'); 6 | } -------------------------------------------------------------------------------- /source/ISUB/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE iSubAttribute.cpp) 2 | target_sources(ObfusC PRIVATE iSubPass.cpp) 3 | target_sources(ObfusC PRIVATE iSubPass.hpp) -------------------------------------------------------------------------------- /source/MBA/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE MbaAttribute.cpp) 2 | target_sources(ObfusC PRIVATE MbaPass.cpp) 3 | target_sources(ObfusC PRIVATE MbaPass.hpp) 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": true, 3 | "files.associations": { 4 | "*.cl": "opencl", 5 | "*.inc": "cpp", 6 | "*.tcc": "cpp", 7 | "type_traits": "cpp", 8 | "*.def": "cpp", 9 | "limits": "cpp" 10 | } 11 | } -------------------------------------------------------------------------------- /source/ISUB/iSubPass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IObfuscationPass.hpp" 3 | 4 | namespace obfusc { 5 | class iSubPass : public IObfuscationPass { 6 | public: 7 | iSubPass(); 8 | ~iSubPass() override; 9 | 10 | bool obfuscate(llvm::Module& mod, llvm::Function& func) override; 11 | }; 12 | } -------------------------------------------------------------------------------- /source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE FuncAttribute.hpp) 2 | target_sources(ObfusC PRIVATE FuncAttributeStore.hpp) 3 | target_sources(ObfusC PRIVATE FuncAttributeStore.cpp) 4 | target_sources(ObfusC PRIVATE common.hpp) 5 | add_subdirectory("MBA") 6 | add_subdirectory("BCF") 7 | add_subdirectory("CFF") 8 | add_subdirectory("ISUB") 9 | add_subdirectory("Passes") -------------------------------------------------------------------------------- /source/Passes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(ObfusC PRIVATE FuncAnnotationsParser.hpp) 2 | target_sources(ObfusC PRIVATE FuncAnnotationsParser.cpp) 3 | target_sources(ObfusC PRIVATE IObfuscationPass.hpp) 4 | target_sources(ObfusC PRIVATE IObfuscationPass.cpp) 5 | target_sources(ObfusC PRIVATE ObfuscationPassManager.hpp) 6 | target_sources(ObfusC PRIVATE ObfuscationPassManager.cpp) -------------------------------------------------------------------------------- /source/CFF/CffPass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IObfuscationPass.hpp" 3 | 4 | namespace obfusc { 5 | class CffPass : public IObfuscationPass { 6 | public: 7 | CffPass(); 8 | ~CffPass() override; 9 | 10 | bool obfuscate(llvm::Module& mod, llvm::Function& func) override; 11 | 12 | private: 13 | void fixStack(llvm::Function& func); 14 | }; 15 | } -------------------------------------------------------------------------------- /tests/bcfTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace BcfTest { 6 | 7 | [[obfusc::bcf]] int BcfTestVal(int a, int b) { 8 | return a+b+20; 9 | } 10 | 11 | 12 | void BcfTestAll() { 13 | int ret = BcfTestVal(10, 10); 14 | printf("Bcf Ret: %d\n", ret); 15 | } 16 | } 17 | 18 | #ifndef OBFUSC_TEST_BUILD_ALL 19 | 20 | int main(int argc, char *argv[]) { 21 | BcfTest::BcfTestAll(); 22 | return 0; 23 | } 24 | 25 | #endif -------------------------------------------------------------------------------- /source/Passes/ObfuscationPassManager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace obfusc { 5 | struct ObfuscationPassManager : llvm::PassInfoMixin { 6 | // Takes IR unit to run the pass on Module and the corresponding manager 7 | llvm::PreservedAnalyses run(llvm::Module& mod, llvm::ModuleAnalysisManager&); 8 | 9 | // If false, pass is skipped for functions decorated with the optnone attribute (e.g. -O0). 10 | static bool isRequired() { return true; } 11 | }; 12 | } -------------------------------------------------------------------------------- /tests/TestAll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace MbaTest { 5 | void MbaTestAll(); 6 | } 7 | 8 | namespace CffTest { 9 | void CffTestAll(); 10 | } 11 | 12 | namespace iSubTest { 13 | void iSubTestAll(); 14 | } 15 | 16 | namespace BcfTest { 17 | void BcfTestAll(); 18 | } 19 | 20 | #ifdef OBFUSC_TEST_BUILD_ALL 21 | 22 | int main(int argc, char *argv[]) { 23 | MbaTest::MbaTestAll(); 24 | CffTest::CffTestAll(); 25 | iSubTest::iSubTestAll(); 26 | BcfTest::BcfTestAll(); 27 | return 0; 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /source/BCF/BcfPass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IObfuscationPass.hpp" 3 | 4 | //Heavily based on Obfuscator-LLVM 5 | //https://github.com/obfuscator-llvm/obfuscator/blob/llvm-4.0/lib/Transforms/Obfuscation/BogusControlFlow.cpp 6 | 7 | namespace obfusc { 8 | class BcfPass : public IObfuscationPass { 9 | public: 10 | BcfPass(); 11 | ~BcfPass() override; 12 | 13 | bool obfuscate(llvm::Module& mod, llvm::Function& func) override; 14 | 15 | private: 16 | llvm::BasicBlock* MakeBogusBlock(llvm::BasicBlock* originalBlock, llvm::Function& func); 17 | }; 18 | } -------------------------------------------------------------------------------- /source/Passes/IObfuscationPass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class IObfuscationPass { 8 | public: 9 | virtual bool obfuscate(llvm::Module& mod, llvm::Function& func) = 0; 10 | protected: 11 | IObfuscationPass(); 12 | virtual ~IObfuscationPass() {} 13 | 14 | /* Get a random number that is half the types bit length (e.g. 64 bit for 128 bit values) */ 15 | virtual uint64_t GetRandomNumber(llvm::Type* type); 16 | std::mt19937_64 m_randGen64; 17 | }; -------------------------------------------------------------------------------- /source/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef OBFUSC_VERSION_MAJOR 4 | #define OBFUSC_VERSION_MAJOR 0 5 | #endif 6 | 7 | #ifndef OBFUSC_VERSION_MINOR 8 | #define OBFUSC_VERSION_MINOR 0 9 | #endif 10 | 11 | #ifndef OBFUSC_VERSION_MICRO 12 | #define OBFUSC_VERSION_MICRO 0 13 | #endif 14 | 15 | #ifndef OBFUSC_GIT_REV 16 | #define OBFUSC_GIT_REV 0 17 | #endif 18 | 19 | #define STRINGIFY(x) #x 20 | #define TOSTRING(x) STRINGIFY(x) 21 | #define OBFUSC_VERSION_STR "v" TOSTRING(OBFUSC_VERSION_MAJOR) "." TOSTRING(OBFUSC_VERSION_MINOR) "." TOSTRING(OBFUSC_VERSION_MICRO) "-" TOSTRING(OBFUSC_GIT_REV) -------------------------------------------------------------------------------- /tests/cffTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace CffTest { 6 | 7 | [[obfusc::cff]] int CffTestVal(int numLoops) { 8 | int ret = 0; 9 | for (int i = 0; i < numLoops; i++) { 10 | ret++; 11 | } 12 | 13 | return ret; 14 | } 15 | 16 | 17 | void CffTestAll() { 18 | int ret = CffTestVal(100); 19 | printf("Cff Ret: %d\n", ret); 20 | } 21 | } 22 | 23 | #ifndef OBFUSC_TEST_BUILD_ALL 24 | 25 | int main(int argc, char *argv[]) { 26 | CffTest::CffTestAll(); 27 | return 0; 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # IDA Pro 35 | *.id0 36 | *.id1 37 | *.id2 38 | *.nam 39 | *.til 40 | linux_server64 41 | 42 | #Misc 43 | build/ 44 | *.ll 45 | mbaTest 46 | isubTest 47 | bcfTest 48 | cffTest 49 | TestAll 50 | TestAll_NoObfusC -------------------------------------------------------------------------------- /source/Passes/FuncAnnotationsParser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace obfusc { 5 | struct FuncAnnotationsParser : llvm::PassInfoMixin { 6 | // Takes IR unit to run the pass on Module and the corresponding manager 7 | llvm::PreservedAnalyses run(llvm::Module& M, llvm::ModuleAnalysisManager&); 8 | 9 | // If false, pass is skipped for functions decorated with the optnone attribute (e.g. -O0). 10 | static bool isRequired() { return true; } 11 | 12 | private: 13 | enum AnnotationOperands { 14 | FUNCTION_OPERAND = 0, 15 | ANNOTATE_OPERAND = 1, 16 | FILENAME_OPERAND = 2 17 | }; 18 | }; 19 | } -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux Ubuntu", 5 | "defines": [ 6 | "VERSION" 7 | ], 8 | "compilerPath": "/usr/bin/clang++-15", 9 | "compilerArgs": [ 10 | 11 | ], 12 | "cStandard": "c17", 13 | "cppStandard": "c++20", 14 | "intelliSenseMode": "linux-clang-x64", 15 | "includePath": [ 16 | "${workspaceFolder}", 17 | "${workspaceFolder}/source/**", 18 | "/usr/include/llvm-15/**" 19 | 20 | ], 21 | "configurationProvider": "ms-vscode.cmake-tools" 22 | } 23 | ], 24 | "version": 4 25 | } -------------------------------------------------------------------------------- /source/FuncAttributeStore.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "IObfuscationPass.hpp" 5 | 6 | namespace obfusc { 7 | class FuncAttributeStore { 8 | public: 9 | static FuncAttributeStore& GetInstance(); 10 | bool IsAttrStored(llvm::StringRef& attr); 11 | IObfuscationPass* GetAttrPass(llvm::StringRef&& attr); 12 | void StoreAttributeInfo(const char* name, IObfuscationPass* pass); 13 | 14 | private: 15 | FuncAttributeStore() {} 16 | 17 | struct AttrStoreInfo { 18 | const char* name; 19 | IObfuscationPass* pass; 20 | size_t size; 21 | }; 22 | std::vector m_info; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /source/Passes/IObfuscationPass.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "IObfuscationPass.hpp" 3 | 4 | IObfuscationPass::IObfuscationPass() { 5 | std::random_device rd; //Get hardware specific random device 6 | m_randGen64.seed(rd()); //Seed Mersenne Twister random generator 7 | } 8 | 9 | /* Get a random number that is half the types bit length (e.g. 64 bit for 128 bit values) */ 10 | uint64_t IObfuscationPass::GetRandomNumber(llvm::Type* type) { 11 | uint64_t modNum = UCHAR_MAX; //UCHAR_MAX covers 8-bit and 16-bit 12 | if (type->getIntegerBitWidth() == 32) { //32-bit 13 | modNum = USHRT_MAX; 14 | } else if (type->getIntegerBitWidth() >= 64) { //64-bit and 128-bit 15 | modNum = UINT_MAX; 16 | } 17 | 18 | return m_randGen64()%modNum; 19 | } -------------------------------------------------------------------------------- /source/MBA/MbaPass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IObfuscationPass.hpp" 3 | 4 | namespace obfusc { 5 | class MbaPass : public IObfuscationPass { 6 | public: 7 | MbaPass(); 8 | ~MbaPass() override; 9 | 10 | bool obfuscate(llvm::Module& mod, llvm::Function& func) override; 11 | 12 | private: 13 | enum SubstituteType : int { 14 | Add = 0, 15 | Subtract, 16 | Divide, 17 | Not, 18 | Xor, 19 | Max 20 | }; 21 | 22 | static constexpr size_t s_RecursiveAmount = 100; 23 | 24 | uint64_t GetSignedMax(llvm::Type* type); 25 | llvm::Value* GenStackAlignmentCode(llvm::IRBuilder<>& irBuilder, llvm::Type* newType, llvm::Value* operand); 26 | llvm::Value* Substitute(llvm::IRBuilder<>& irBuilder, llvm::Type* type, llvm::Type* origType, llvm::Value* operand, size_t numRecursions = 0); 27 | }; 28 | } -------------------------------------------------------------------------------- /source/Passes/ObfuscationPassManager.cpp: -------------------------------------------------------------------------------- 1 | #include "ObfuscationPassManager.hpp" 2 | #include "IObfuscationPass.hpp" 3 | #include "FuncAttributeStore.hpp" 4 | 5 | namespace obfusc { 6 | llvm::PreservedAnalyses ObfuscationPassManager::run(llvm::Module& mod, llvm::ModuleAnalysisManager&) { 7 | bool changed = false; 8 | for (auto& func : mod.getFunctionList()) { //Get all functions in module 9 | for (auto& attrs : func.getAttributes()) { //Get each attribute lists attached to function 10 | for (auto& attr : attrs) { //Get attributes one by one 11 | if (attr.isStringAttribute()) { //If attribute is a string 12 | IObfuscationPass* pass = FuncAttributeStore::GetInstance().GetAttrPass(llvm::StringRef(attr.getAsString().data())); //Check if attr is an obfuscation pass 13 | if (pass) { 14 | changed |= pass->obfuscate(mod, func); //Call obfuscate func 15 | } 16 | } 17 | } 18 | } 19 | } 20 | 21 | if (changed) { 22 | return llvm::PreservedAnalyses::none(); 23 | } 24 | return llvm::PreservedAnalyses::all(); 25 | } 26 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "common.hpp" 6 | #include "FuncAnnotationsParser.hpp" 7 | #include "ObfuscationPassManager.hpp" 8 | 9 | namespace obfusc { 10 | llvm::PassPluginLibraryInfo getObfuscPluginInfo() { 11 | llvm::outs() << "ObfusC Version: " << OBFUSC_VERSION_STR << "\n"; 12 | return {LLVM_PLUGIN_API_VERSION, "ObfusC", OBFUSC_VERSION_STR, 13 | [](llvm::PassBuilder &PB) { 14 | PB.registerPipelineEarlySimplificationEPCallback( 15 | [=](llvm::ModulePassManager &MPM, llvm::OptimizationLevel Level) { 16 | MPM.addPass(obfusc::FuncAnnotationsParser()); 17 | } 18 | ); 19 | PB.registerOptimizerLastEPCallback( 20 | [=](llvm::ModulePassManager &MPM, llvm::OptimizationLevel Level) { 21 | MPM.addPass(obfusc::ObfuscationPassManager()); 22 | } 23 | ); 24 | } 25 | }; 26 | } 27 | } 28 | 29 | // Dynamic Library Entrypoint 30 | extern "C" LLVM_ATTRIBUTE_WEAK llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() { 31 | return obfusc::getObfuscPluginInfo(); 32 | } 33 | -------------------------------------------------------------------------------- /source/FuncAttributeStore.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAttribute.hpp" 2 | #include 3 | 4 | namespace obfusc { 5 | FuncAttributeStore& FuncAttributeStore::GetInstance() { 6 | static FuncAttributeStore x; 7 | return x; 8 | } 9 | 10 | bool FuncAttributeStore::IsAttrStored(llvm::StringRef& attr) { 11 | if (attr.size() < 2) { 12 | return false; 13 | } 14 | 15 | const char* attrCStr = attr.data(); 16 | 17 | if (attr[0] == '\"') { 18 | attrCStr = attr.substr(1, attr.size()-2).data(); 19 | } 20 | 21 | for (auto& info : m_info) { 22 | if (strncasecmp(info.name, attrCStr, info.size) == 0) { 23 | return true; 24 | } 25 | } 26 | 27 | return false; 28 | } 29 | 30 | IObfuscationPass* FuncAttributeStore::GetAttrPass(llvm::StringRef&& attr) { 31 | if (attr.size() < 2) { 32 | return nullptr; 33 | } 34 | 35 | const char* attrCStr = attr.data(); 36 | 37 | if (attr[0] == '\"') { 38 | attrCStr = attr.substr(1, attr.size()-2).data(); 39 | } 40 | 41 | for (auto& info : m_info) { 42 | if (strncasecmp(info.name, attrCStr, info.size) == 0) { 43 | return info.pass; 44 | } 45 | } 46 | 47 | return nullptr; 48 | } 49 | 50 | void FuncAttributeStore::StoreAttributeInfo(const char* name, IObfuscationPass* pass) { 51 | m_info.push_back({name, pass, strlen(name)}); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13.4) 2 | project(ObfusC) 3 | 4 | # Set this to a valid LLVM installation dir 5 | set(LT_LLVM_INSTALL_DIR "" CACHE PATH "/usr/bin/") 6 | 7 | # Add the location of LLVMConfig.cmake to CMake search paths (so that 8 | # find_package can locate it) 9 | list(APPEND CMAKE_PREFIX_PATH "${LT_LLVM_INSTALL_DIR}/lib/llvm-15/cmake") 10 | 11 | find_package(LLVM 15 REQUIRED CONFIG) 12 | 13 | # Add the LLVM include paths and my includes 14 | include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) 15 | include_directories(SYSTEM ${CLANG_INCLUDE_DIRS}) 16 | 17 | set(CMAKE_CXX_STANDARD 20) 18 | 19 | # LLVM is normally built without RTTI. Be consistent with that. 20 | if(NOT LLVM_ENABLE_RTTI) 21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") 22 | endif() 23 | 24 | execute_process( 25 | COMMAND git rev-parse --short HEAD 26 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 27 | OUTPUT_VARIABLE GIT_COMMIT_HASH 28 | OUTPUT_STRIP_TRAILING_WHITESPACE 29 | ) 30 | 31 | add_definitions(-DOBFUSC_VERSION_MAJOR=0 -DOBFUSC_VERSION_MINOR=3 -DOBFUSC_VERSION_MICRO=0 -DOBFUSC_GIT_REV=${GIT_COMMIT_HASH}) 32 | 33 | 34 | # Add Target and source dir 35 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib) 36 | 37 | add_library(ObfusC SHARED main.cpp) 38 | target_include_directories(ObfusC PRIVATE "source") 39 | target_include_directories(ObfusC PRIVATE "source/MBA") 40 | target_include_directories(ObfusC PRIVATE "source/ISUB") 41 | target_include_directories(ObfusC PRIVATE "source/CFF") 42 | target_include_directories(ObfusC PRIVATE "source/BCF") 43 | target_include_directories(ObfusC PRIVATE "source/Passes") 44 | add_subdirectory("source") 45 | -------------------------------------------------------------------------------- /source/Passes/FuncAnnotationsParser.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncAnnotationsParser.hpp" 2 | #include "FuncAttributeStore.hpp" 3 | 4 | namespace obfusc { 5 | llvm::PreservedAnalyses FuncAnnotationsParser::run(llvm::Module& M, llvm::ModuleAnalysisManager&) { 6 | llvm::GlobalVariable* globalAttrs = M.getGlobalVariable("llvm.global.annotations"); //Get llvm.global.annotations from IR data 7 | if (!globalAttrs) { 8 | return llvm::PreservedAnalyses::all(); 9 | } 10 | 11 | llvm::ConstantArray* array = llvm::cast(globalAttrs->getOperand(0)); //Get array of operands 12 | for (llvm::Value* operand : array->operands()) { //Get each operand 13 | llvm::ConstantStruct* constant = llvm::dyn_cast(operand); //Cast operand to a struct (i.e. the annotation struct) 14 | if (!constant || constant->getNumOperands() < 2) { //Must be at least two operands (FUNCTION_OPERAND and ANNOTATE_OPERAND) 15 | continue; 16 | } 17 | 18 | llvm::Function* func = llvm::cast(constant->getOperand(AnnotationOperands::FUNCTION_OPERAND)); //Get function 19 | llvm::GlobalVariable* globalStrPtr = llvm::cast(constant->getOperand(AnnotationOperands::ANNOTATE_OPERAND)); 20 | if (!func || !globalStrPtr) { 21 | continue; 22 | } 23 | 24 | if (llvm::ConstantDataArray* strArray = llvm::dyn_cast(globalStrPtr->getOperand(0))) { //Get Annotation str 25 | llvm::StringRef str = strArray->getAsString(); 26 | if (FuncAttributeStore::GetInstance().IsAttrStored(str)) { 27 | func->addFnAttr(str); //add Annotation to function 28 | } 29 | } 30 | } 31 | 32 | return llvm::PreservedAnalyses::all(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ObfusC - Implementation of a Compiler Plugin for C++ Obfuscation 2 | ObfusC entails creating a LLVM Compiler Plugin (written in C++) with the main purpose of providing a seamless and easy to use C/C++ obfuscation for the user. 3 | 4 | The user is given the option to specify what functionality to obfuscate through the use of code attributes. 5 | 6 | ObfusC integrates directly into LLVM by working at the Intermediate Representation (IR) level of the compiler, which is used to translate high-level languages such as C and C++, to target architectures such as x86 and ARM and AArch64. 7 | 8 | # Features 9 | 10 | ## Mixed Boolean Arithmetic 11 | 12 | This involves the use of a combination of standard arithmetic operations, such as addition and subtraction, with logical operations, such as AND, NOT, and OR. 13 | 14 | ![Alt text](images/MBA.png?raw=true) 15 | 16 | --- 17 | 18 | ## Bogus Control Flow 19 | 20 | This alters a function’s control flow by inserting conditional jumps that point either into the original basic code block or to a fake basic code block. 21 | 22 | ![Alt text](images/BCF.png?raw=true) 23 | 24 | --- 25 | 26 | ## Instruction Substitution 27 | 28 | This simply replaces standard binary operators with functionally equivalent but more complicated sequences of instructions. 29 | 30 | ![Alt text](images/iSub.png?raw=true) 31 | 32 | --- 33 | 34 | ## Control Flow Flattening 35 | 36 | This involves the transformation of a program's control flow, the sequence of instructions that determines how a program executes, into a more complex and less transparent form. This is accomplished through techniques such as loop unrolling. 37 | 38 | ![Alt text](images/iSub.png?raw=true) 39 | 40 | # Download 41 | Latest Release: [Here](https://github.com/Slattz/ObfusC/releases/latest) 42 | 43 | # Usage 44 | 45 | Add the following to your compile arguments: 46 | 47 | ``` 48 | -fplugin=./libObfusC.so -fpass-plugin=./libObfusC.so 49 | ``` 50 | 51 | # Building on Linux 52 | 53 | ## Dependencies 54 | 55 | * CMake 3.13.4+ 56 | * Ninja 57 | * LLVM 58 | * LLVM Dev Headers 59 | 60 | ## Building 61 | ``` 62 | git clone --recursive https://github.com/Slattz/ObfusC 63 | cd ObfusC 64 | ``` 65 | 66 | Next: 67 | ```bash 68 | mkdir build && cd build 69 | cmake ../ -GNinja -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-15 70 | ``` -------------------------------------------------------------------------------- /source/BCF/LICENSE-OBFUSCATOR.TXT: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | Obfuscator-LLVM Release License 3 | ============================================================================== 4 | University of Illinois/NCSA 5 | Open Source License 6 | 7 | Copyright (c) 2014 Haute Ecole d'Ingénierie et de Gestion du Canton de Vaud (HEIG-VD). All rights reserved. 8 | 9 | Developed by: 10 | 11 | Obfuscator-LLVM Team 12 | 13 | Haute-Ecole d'Ingénierie et de Gestion du Canton de Vaud (HEIG-VD), a part 14 | of the University of Applied Sciences and Arts Western Switzerland (HES-SO) 15 | 16 | http://o-llvm.org 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | this software and associated documentation files (the "Software"), to deal with 20 | the Software without restriction, including without limitation the rights to 21 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 22 | of the Software, and to permit persons to whom the Software is furnished to do 23 | so, subject to the following conditions: 24 | 25 | * Redistributions of source code must retain the above copyright notice, 26 | this list of conditions and the following disclaimers. 27 | 28 | * Redistributions in binary form must reproduce the above copyright notice, 29 | this list of conditions and the following disclaimers in the 30 | documentation and/or other materials provided with the distribution. 31 | 32 | * Neither the names of the Obfuscator-LLVM Team, the Haute Ecole d'Ingénierie 33 | et de Gestion du Canton de Vaud (HEIG-VD), the University of Applied Sciences 34 | and Arts Western Switzerland (HES-SO) nor the names of its contributors 35 | may be used to endorse or promote products derived from this Software 36 | without specific prior written permission. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 40 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 44 | SOFTWARE. 45 | -------------------------------------------------------------------------------- /source/CFF/LICENSE-OBFUSCATOR.TXT: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | Obfuscator-LLVM Release License 3 | ============================================================================== 4 | University of Illinois/NCSA 5 | Open Source License 6 | 7 | Copyright (c) 2014 Haute Ecole d'Ingénierie et de Gestion du Canton de Vaud (HEIG-VD). All rights reserved. 8 | 9 | Developed by: 10 | 11 | Obfuscator-LLVM Team 12 | 13 | Haute-Ecole d'Ingénierie et de Gestion du Canton de Vaud (HEIG-VD), a part 14 | of the University of Applied Sciences and Arts Western Switzerland (HES-SO) 15 | 16 | http://o-llvm.org 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | this software and associated documentation files (the "Software"), to deal with 20 | the Software without restriction, including without limitation the rights to 21 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 22 | of the Software, and to permit persons to whom the Software is furnished to do 23 | so, subject to the following conditions: 24 | 25 | * Redistributions of source code must retain the above copyright notice, 26 | this list of conditions and the following disclaimers. 27 | 28 | * Redistributions in binary form must reproduce the above copyright notice, 29 | this list of conditions and the following disclaimers in the 30 | documentation and/or other materials provided with the distribution. 31 | 32 | * Neither the names of the Obfuscator-LLVM Team, the Haute Ecole d'Ingénierie 33 | et de Gestion du Canton de Vaud (HEIG-VD), the University of Applied Sciences 34 | and Arts Western Switzerland (HES-SO) nor the names of its contributors 35 | may be used to endorse or promote products derived from this Software 36 | without specific prior written permission. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 40 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 44 | SOFTWARE. 45 | -------------------------------------------------------------------------------- /tests/mbaTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace MbaTest { 6 | template 7 | [[obfusc::mba]] T Add(T a, T b) { 8 | return a + b; 9 | } 10 | 11 | template 12 | [[obfusc::mba]] T Sub(T a, T b) { 13 | return a - b; 14 | } 15 | 16 | template 17 | [[obfusc::mba]] T Mul(T a, T b) { 18 | return a * b; 19 | } 20 | 21 | template 22 | [[obfusc::mba]] T Div(T a, T b) { 23 | return a / b; 24 | } 25 | 26 | template 27 | void TestBinaryOperator(T a, T b, T expectedRes, T (*op)(T, T)) { 28 | T testVal = op(a, b); 29 | printf("A: %lu B: %lu, Expected Res: %lu, Actual Res: %lu\n", static_cast(a), static_cast(b), static_cast(expectedRes), static_cast(testVal)); 30 | assert(testVal == expectedRes); 31 | } 32 | 33 | void MbaTestAdd() { 34 | TestBinaryOperator(200, 16, 216, Add); 35 | TestBinaryOperator(32'123, 12'321, 44'444, Add); 36 | TestBinaryOperator(987'654'321, 123'456'789, 1'111'111'110, Add); 37 | TestBinaryOperator(2'305'843'009'213'693'951, 2'305'843'009'213'693'951, 4'611'686'018'427'387'902, Add); 38 | } 39 | 40 | void MbaTestSub() { 41 | TestBinaryOperator(220, 20, 200, Sub); 42 | TestBinaryOperator(32'123, 12'321, 19'802, Sub); 43 | TestBinaryOperator(987'654'321, 123'456'789, 864'197'532, Sub); 44 | TestBinaryOperator(3'305'843'009'213'693'951, 2'305'843'009'213'693'951, 1'000'000'000'000'000'000, Sub); 45 | } 46 | 47 | void MbaTestMul() { 48 | TestBinaryOperator(120, 2, 240, Mul); 49 | TestBinaryOperator(600, 100, 60'000, Mul); 50 | TestBinaryOperator(600'000, 1'000, 600'000'000, Mul); 51 | TestBinaryOperator(2'305'843'009'213'693'951, 2, 4'611'686'018'427'387'902, Mul); 52 | } 53 | 54 | void MbaTestDiv() { 55 | TestBinaryOperator(240, 2, 120, Div); 56 | TestBinaryOperator(60'000, 100, 600, Div); 57 | TestBinaryOperator(600'000'000, 1'000, 600'000, Div); 58 | TestBinaryOperator(4'611'686'018'427'387'902, 2, 2'305'843'009'213'693'951, Div); 59 | } 60 | 61 | void MbaTestAll() { 62 | MbaTestAdd(); 63 | MbaTestSub(); 64 | MbaTestMul(); 65 | MbaTestDiv(); 66 | } 67 | } 68 | 69 | #ifndef OBFUSC_TEST_BUILD_ALL 70 | 71 | int main(int argc, char *argv[]) { 72 | MbaTest::MbaTestAll(); 73 | return 0; 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /source/ISUB/iSubPass.cpp: -------------------------------------------------------------------------------- 1 | #include "iSubPass.hpp" 2 | 3 | /* 4 | Based on Obfuscator-LLVM 5 | https://github.com/obfuscator-llvm/obfuscator/blob/llvm-4.0/lib/Transforms/Obfuscation/Substitution.cpp 6 | */ 7 | 8 | namespace obfusc { 9 | iSubPass::iSubPass() {} 10 | iSubPass::~iSubPass() {} 11 | 12 | bool iSubPass::obfuscate(llvm::Module& mod, llvm::Function& func) { 13 | bool changed = false; 14 | 15 | for (auto& block : func) { 16 | for (auto instruction = block.begin(); instruction != block.end(); instruction++) { 17 | llvm::BinaryOperator* binOp = llvm::dyn_cast(instruction); 18 | if (!binOp) //Is instruction a binary op 19 | continue; 20 | 21 | llvm::IRBuilder irBuilder(binOp); 22 | 23 | llvm::Instruction* newInstrs; 24 | switch (binOp->getOpcode()) { 25 | case llvm::Instruction::Add: //a = b - (-c) 26 | newInstrs = llvm::BinaryOperator::CreateSub(binOp->getOperand(0), irBuilder.CreateNeg(binOp->getOperand(1))); 27 | break; 28 | 29 | case llvm::Instruction::FAdd: //a = b - (-c) 30 | newInstrs = llvm::BinaryOperator::CreateFSub(binOp->getOperand(0), irBuilder.CreateFNeg(binOp->getOperand(1))); 31 | break; 32 | 33 | case llvm::Instruction::Sub: //a = b + (-c) 34 | newInstrs = llvm::BinaryOperator::CreateAdd(binOp->getOperand(0), irBuilder.CreateNeg(binOp->getOperand(1))); 35 | break; 36 | 37 | case llvm::Instruction::FSub: //a = b + (-c) 38 | newInstrs = llvm::BinaryOperator::CreateFAdd(binOp->getOperand(0), irBuilder.CreateFNeg(binOp->getOperand(1))); 39 | break; 40 | 41 | case llvm::Instruction::And: //a = b & c -> a = (b ^ ~c) & b 42 | newInstrs = llvm::BinaryOperator::CreateAnd(irBuilder.CreateXor(binOp->getOperand(0), irBuilder.CreateNot(binOp->getOperand(1))), binOp->getOperand(0)); 43 | break; 44 | 45 | case llvm::Instruction::Or: //a = b | c -> a = (b & c) | (b ^ c) 46 | newInstrs = llvm::BinaryOperator::CreateOr(irBuilder.CreateAnd(binOp->getOperand(0), binOp->getOperand(1)), 47 | irBuilder.CreateXor(binOp->getOperand(0), binOp->getOperand(1))); 48 | break; 49 | 50 | default: 51 | continue; 52 | } 53 | 54 | llvm::ReplaceInstWithInst(block.getInstList(), instruction, newInstrs); //replace old instruction with new obfuscation instructions 55 | changed = true; 56 | } 57 | } 58 | 59 | return changed; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Run Test", 8 | "type": "shell", 9 | "command": "/usr/bin/clang++-15", 10 | "options": { 11 | "cwd": "${workspaceFolder}/tests" 12 | }, 13 | "args": [ 14 | "-g", 15 | "-std=c++2b", 16 | "-fplugin=${workspaceFolder}/lib/libObfusC.so", 17 | "-fpass-plugin=${workspaceFolder}/lib/libObfusC.so", 18 | "${file}", 19 | "-o", 20 | "${fileDirname}/${fileBasenameNoExtension}" 21 | ], 22 | "problemMatcher": ["$gcc"], 23 | "group": { 24 | "kind": "build" 25 | }, 26 | "presentation": { 27 | "reveal": "always", 28 | "panel": "shared" 29 | } 30 | }, 31 | { 32 | "label": "Run All Tests", 33 | "type": "shell", 34 | "command": "/usr/bin/clang++-15", 35 | "options": { 36 | "cwd": "${workspaceFolder}/tests" 37 | }, 38 | "args": [ 39 | "-g", 40 | "-std=c++2b", 41 | "-DOBFUSC_TEST_BUILD_ALL", 42 | "-fplugin=${workspaceFolder}/lib/libObfusC.so", 43 | "-fpass-plugin=${workspaceFolder}/lib/libObfusC.so", 44 | "${fileDirname}/**.cpp", 45 | "-o", 46 | "${fileDirname}/${fileBasenameNoExtension}" 47 | ], 48 | "problemMatcher": [ 49 | "$gcc" 50 | ], 51 | "group": { 52 | "kind": "build" 53 | }, 54 | "presentation": { 55 | "reveal": "always", 56 | "panel": "dedicated" 57 | } 58 | }, 59 | { 60 | "label": "Run All Tests (No Obfuscation)", 61 | "type": "shell", 62 | "command": "/usr/bin/clang++-15", 63 | "options": { 64 | "cwd": "${workspaceFolder}/tests" 65 | }, 66 | "args": [ 67 | "-g", 68 | "-std=c++2b", 69 | "-DOBFUSC_TEST_BUILD_ALL", 70 | "${fileDirname}/**.cpp", 71 | "-o", 72 | "${fileDirname}/${fileBasenameNoExtension}_NoObfusC" 73 | ], 74 | "problemMatcher": [ 75 | "$gcc" 76 | ], 77 | "group": { 78 | "kind": "build" 79 | }, 80 | "presentation": { 81 | "reveal": "always", 82 | "panel": "dedicated" 83 | } 84 | } 85 | ] 86 | } -------------------------------------------------------------------------------- /tests/isubTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace iSubTest { 6 | template 7 | [[obfusc::isub]] T Add(T a, T b) { 8 | return a + b; 9 | } 10 | 11 | template 12 | [[obfusc::isub]] T Sub(T a, T b) { 13 | return a - b; 14 | } 15 | template 16 | [[obfusc::isub]] T And(T a, T b) { 17 | return a & b; 18 | } 19 | 20 | template 21 | [[obfusc::isub]] T Or(T a, T b) { 22 | return a | b; 23 | } 24 | 25 | template 26 | void TestBinaryOperator(T a, T b, T expectedRes, T (*op)(T, T)) { 27 | T testVal = op(a, b); 28 | printf("A: %lu B: %lu, Expected Res: %lu, Actual Res: %lu\n", static_cast(a), static_cast(b), static_cast(expectedRes), static_cast(testVal)); 29 | assert(testVal == expectedRes); 30 | } 31 | 32 | template 33 | void TestFloatBinaryOperator(T a, T b, T expectedRes, T (*op)(T, T)) { 34 | T testVal = op(a, b); 35 | printf("A: %f B: %f, Expected Res: %f, Actual Res: %f\n", a, b, expectedRes, testVal); 36 | assert(testVal == expectedRes); 37 | } 38 | 39 | void iSubTestAdd() { 40 | TestBinaryOperator(200, 16, 216, Add); 41 | TestBinaryOperator(32'123, 12'321, 44'444, Add); 42 | TestBinaryOperator(987'654'321, 123'456'789, 1'111'111'110, Add); 43 | TestBinaryOperator(2'305'843'009'213'693'951, 2'305'843'009'213'693'951, 4'611'686'018'427'387'902, Add); 44 | 45 | TestFloatBinaryOperator(1.0f, 2.1f, 3.1f, Add); 46 | TestFloatBinaryOperator(1.0, 2.1, 3.1, Add); 47 | } 48 | 49 | void iSubTestSub() { 50 | TestBinaryOperator(220, 20, 200, Sub); 51 | TestBinaryOperator(32'123, 12'321, 19'802, Sub); 52 | TestBinaryOperator(987'654'321, 123'456'789, 864'197'532, Sub); 53 | TestBinaryOperator(3'305'843'009'213'693'951, 2'305'843'009'213'693'951, 1'000'000'000'000'000'000, Sub); 54 | 55 | TestFloatBinaryOperator(3.1f, 2.1f, 1.0f, Sub); 56 | TestFloatBinaryOperator(3.1, 2.1, 1.0, Sub); 57 | } 58 | 59 | void iSubTestAnd() { 60 | TestBinaryOperator( 2, 6, 2, And); 61 | TestBinaryOperator(2, 6, 2, And); 62 | TestBinaryOperator(2, 6, 2, And); 63 | TestBinaryOperator(2, 6, 2, And); 64 | } 65 | 66 | void iSubTestOr() { 67 | TestBinaryOperator( 2, 4, 6, Or); 68 | TestBinaryOperator(2, 4, 6, Or); 69 | TestBinaryOperator(2, 4, 6, Or); 70 | TestBinaryOperator(2, 4, 6, Or); 71 | } 72 | 73 | void iSubTestAll() { 74 | iSubTestAdd(); 75 | iSubTestSub(); 76 | iSubTestAnd(); 77 | iSubTestOr(); 78 | } 79 | } 80 | 81 | #ifndef OBFUSC_TEST_BUILD_ALL 82 | 83 | int main(int argc, char *argv[]) { 84 | iSubTest::iSubTestAll(); 85 | return 0; 86 | } 87 | 88 | #endif -------------------------------------------------------------------------------- /source/FuncAttribute.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "FuncAttributeStore.hpp" 7 | #include "IObfuscationPass.hpp" 8 | 9 | 10 | namespace obfusc { 11 | template 12 | class FuncAttribute : public clang::ParsedAttrInfo { 13 | public: 14 | virtual bool diagAppertainsToDecl(clang::Sema& S, const clang::ParsedAttr& Attr, const clang::Decl* D) const override { 15 | if (!clang::isa(D)) { //This attribute appertains to functions only. 16 | S.Diag(Attr.getLoc(), clang::diag::warn_attribute_wrong_decl_type_str) << Attr << "functions"; 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | virtual AttrHandling handleDeclAttribute(clang::Sema& S, clang::Decl* D, const clang::ParsedAttr& Attr) const override { 23 | if ((!D->getDeclContext()->isFileContext())) { //Check if the decl is at file scope 24 | if (D->getDeclContext()->getDeclKind() != clang::Decl::Kind::CXXRecord) { //or if it's a lambda (other CXXRecords are covered by diagAppertainsToDecl) 25 | std::string attrStr(Attr.getAttrName()->deuglifiedName().data()); 26 | attrStr.append(" attribute only allowed at file scope and on lambdas"); 27 | 28 | unsigned ID = S.getDiagnostics().getDiagnosticIDs()->getCustomDiagID(clang::DiagnosticIDs::Error, llvm::StringRef(attrStr)); 29 | S.Diag(Attr.getLoc(), ID); 30 | return AttributeNotApplied; 31 | } 32 | } 33 | 34 | if (Attr.getNumArgs() > OptArgs) { 35 | std::string attrStr(Attr.getAttrName()->deuglifiedName().data()); 36 | attrStr.append("attribute only accepts no arguments"); 37 | 38 | unsigned ID = S.getDiagnostics().getDiagnosticIDs()->getCustomDiagID(clang::DiagnosticIDs::Error, llvm::StringRef(attrStr)); 39 | S.Diag(Attr.getLoc(), ID); 40 | return AttributeNotApplied; 41 | } 42 | 43 | D->addAttr(clang::AnnotateAttr::Create(S.Context, Attr.getAttrName()->deuglifiedName(), nullptr, 0, Attr.getRange())); 44 | return AttributeApplied; 45 | } 46 | 47 | protected: 48 | inline FuncAttribute() { 49 | OptArgs = 0; 50 | static constexpr const char nameStr[] = { obfName..., '\0' }; 51 | static constexpr const char cxxNameStr[] = {'o', 'b', 'f', 'u', 's', 'c', ':', ':', obfName..., '\0' }; 52 | 53 | static const Spelling S[] {{clang::ParsedAttr::AS_GNU, nameStr}, 54 | {clang::ParsedAttr::AS_CXX11, nameStr}, 55 | {clang::ParsedAttr::AS_CXX11, cxxNameStr}}; 56 | 57 | Spellings = S; 58 | 59 | FuncAttributeStore::GetInstance().StoreAttributeInfo(nameStr, new passType()); 60 | } 61 | }; 62 | 63 | //name ## Pass class (e.g. MbaPass) needs to be included before using this macro. 64 | #define NEW_FUNC_ATTR(name, ...) \ 65 | static_assert(std::is_convertible::value, #name "Pass must inherit IObfuscationPass as public"); \ 66 | class name ## Attribute : public FuncAttribute { }; \ 67 | static clang::ParsedAttrInfoRegistry::Add name ## Clang("obfusc_" #name, "") 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /source/BCF/BcfPass.cpp: -------------------------------------------------------------------------------- 1 | #include "BcfPass.hpp" 2 | #include 3 | 4 | //Heavily based on Obfuscator-LLVM 5 | //https://github.com/obfuscator-llvm/obfuscator/blob/llvm-4.0/lib/Transforms/Obfuscation/BogusControlFlow.cpp 6 | 7 | namespace obfusc { 8 | BcfPass::BcfPass() {} 9 | BcfPass::~BcfPass() {} 10 | 11 | bool BcfPass::obfuscate(llvm::Module& mod, llvm::Function& func) { 12 | bool changed = false; 13 | 14 | std::vector basicBlocks; //make copy of blocks 15 | for (auto& block : func) { 16 | basicBlocks.push_back(&block); 17 | } 18 | 19 | //For every block copied 20 | for (llvm::BasicBlock* block : basicBlocks) { 21 | auto instruction = block->begin(); 22 | if (block->getFirstNonPHIOrDbgOrLifetime()) { 23 | instruction = static_cast(block->getFirstNonPHIOrDbgOrLifetime()); //skip past PHI instructions 24 | } 25 | 26 | llvm::BasicBlock* origBlock = block->splitBasicBlock(instruction); //Get original block 27 | llvm::BasicBlock* changedBlock = MakeBogusBlock(origBlock, func); //Get Bogus/altered version of same block 28 | 29 | //Erase from parents for each block 30 | changedBlock->getTerminator()->eraseFromParent(); 31 | block->getTerminator()->eraseFromParent(); 32 | 33 | llvm::Type* int32Type = llvm::Type::getInt32Ty(mod.getContext()); 34 | 35 | //Create global variables for comparison 36 | llvm::GlobalVariable* x = new llvm::GlobalVariable(mod, int32Type, false, llvm::GlobalValue::LinkageTypes::InternalLinkage, llvm::ConstantInt::get(int32Type, 1)); 37 | llvm::GlobalVariable* y = new llvm::GlobalVariable(mod, int32Type, false, llvm::GlobalValue::LinkageTypes::InternalLinkage, llvm::ConstantInt::get(int32Type, 3)); 38 | 39 | //Load values from global vars 40 | llvm::LoadInst* opX = new llvm::LoadInst(int32Type, x, "", block); 41 | llvm::LoadInst* opY = new llvm::LoadInst(int32Type, y, "", block); 42 | 43 | //Create compare instruction 44 | llvm::ICmpInst* cmpInstr = new llvm::ICmpInst(*block, llvm::CmpInst::Predicate::ICMP_ULT, opX, opY); 45 | 46 | //Create branches to each block based on cmp instr 47 | llvm::BranchInst::Create(origBlock, changedBlock, cmpInstr, block); 48 | llvm::BranchInst::Create(origBlock, changedBlock); 49 | 50 | auto endInstr = origBlock->end(); 51 | endInstr--; //Get actual last instr 52 | auto endBlock = origBlock->splitBasicBlock(endInstr); 53 | origBlock->getTerminator()->eraseFromParent(); //remove from parent block 54 | 55 | //Make cmp instruction 56 | cmpInstr = new llvm::ICmpInst(*origBlock, llvm::CmpInst::Predicate::ICMP_ULT, opX, opY); 57 | llvm::BranchInst::Create(endBlock, changedBlock, cmpInstr, origBlock); //Loop back from bogus block to changed block 58 | 59 | changed = true; 60 | } 61 | 62 | return changed; 63 | } 64 | 65 | llvm::BasicBlock* BcfPass::MakeBogusBlock(llvm::BasicBlock* originalBlock, llvm::Function& func) { 66 | llvm::ValueToValueMapTy valMap; 67 | llvm::BasicBlock* retBlock = llvm::CloneBasicBlock(originalBlock, valMap, "", &func); 68 | 69 | //Start remapping information for each instruction 70 | auto origInstruction = originalBlock->begin(); 71 | for (auto instruction = retBlock->begin(); instruction != retBlock->end(); instruction++) { 72 | for (auto op = instruction->op_begin(); op != instruction->op_end(); ++op) { 73 | llvm::Value* val = llvm::MapValue(*op, valMap); //Map operations of new instrs 74 | if (val) { 75 | *op = val; 76 | } 77 | } 78 | 79 | llvm::PHINode* phiNode = llvm::dyn_cast(instruction); 80 | if (phiNode) { //Remap PHI nodes 81 | for (unsigned int i = 0; i != phiNode->getNumIncomingValues(); ++i) { 82 | llvm::Value* val = llvm::MapValue(phiNode->getIncomingBlock(i), valMap); 83 | if (val) { 84 | phiNode->setIncomingBlock(i, llvm::cast(val)); 85 | } 86 | } 87 | } 88 | 89 | llvm::SmallVector> metadata; 90 | instruction->getAllMetadata(metadata); 91 | 92 | //Needed for DWARF symbols 93 | instruction->setDebugLoc(origInstruction->getDebugLoc()); 94 | origInstruction++; 95 | 96 | /* Start altering blocks!! */ 97 | 98 | if (instruction->isBinaryOp()) { //Swap operators for binary instrs 99 | llvm::Value* op0 = instruction->getOperand(0); 100 | llvm::Value* op1 = instruction->getOperand(1); 101 | 102 | instruction->setOperand(0, op1); 103 | instruction->setOperand(1, op0); 104 | } 105 | 106 | //Make Load instrs into Store instrs 107 | else if (instruction->getOpcode() == llvm::Instruction::Load) { 108 | llvm::Value* op0 = instruction->getOperand(0); 109 | llvm::AllocaInst* allocIns = (llvm::AllocaInst*)op0; 110 | llvm::Type* opType = allocIns->getAllocatedType(); 111 | 112 | auto randVal = llvm::ConstantInt::get(opType, GetRandomNumber(opType)); //Get random number for storing 113 | 114 | llvm::StoreInst* newOp = new llvm::StoreInst(randVal, op0, true, &*instruction); 115 | instruction = instruction->eraseFromParent(); 116 | } 117 | 118 | //Make Store instrs into Load instrs 119 | else if (instruction->getOpcode() == llvm::Instruction::Store) { 120 | llvm::Value* op0 = instruction->getOperand(0); 121 | llvm::Value* op1 = instruction->getOperand(1); 122 | 123 | llvm::LoadInst* newOp = new llvm::LoadInst(op0->getType(), op1, "", &*instruction); 124 | instruction = instruction->eraseFromParent(); 125 | } 126 | } 127 | 128 | return retBlock; 129 | } 130 | } -------------------------------------------------------------------------------- /source/MBA/MbaPass.cpp: -------------------------------------------------------------------------------- 1 | #include "MbaPass.hpp" 2 | #include 3 | #include 4 | 5 | namespace obfusc { 6 | MbaPass::MbaPass() {} 7 | MbaPass::~MbaPass() {} 8 | 9 | bool MbaPass::obfuscate(llvm::Module& mod, llvm::Function& func) { 10 | bool changed = false; 11 | 12 | for (auto& block : func) { 13 | for (auto instruction = block.begin(); instruction != block.end(); instruction++) { 14 | llvm::BinaryOperator* binOp = llvm::dyn_cast(instruction); 15 | if (!binOp) //Is instruction a binary op 16 | continue; 17 | 18 | llvm::IRBuilder irBuilder(binOp); 19 | llvm::Type* newType = llvm::IntegerType::getInt128Ty(binOp->getType()->getContext()); //Set type to 128 bit to account for possible uint64 overflows 20 | 21 | llvm::Value* op1 = GenStackAlignmentCode(irBuilder, newType, binOp->getOperand(0)); 22 | llvm::Value* op2 = GenStackAlignmentCode(irBuilder, newType, binOp->getOperand(1)); 23 | 24 | op1 = Substitute(irBuilder, newType, binOp->getType(), op1); //Generate MBA for op1 25 | op2 = Substitute(irBuilder, newType, binOp->getType(), op2); //Generate MBA for op2 26 | 27 | llvm::Instruction* newInstrs; 28 | unsigned opCode = binOp->getOpcode(); 29 | switch (opCode) { //Gen underlying operation 30 | case llvm::Instruction::Add: 31 | newInstrs = llvm::BinaryOperator::CreateAdd(op1, op2); 32 | break; 33 | 34 | case llvm::Instruction::Sub: 35 | newInstrs = llvm::BinaryOperator::CreateSub(op1, op2); 36 | break; 37 | 38 | case llvm::Instruction::Mul: 39 | newInstrs = llvm::BinaryOperator::CreateMul(op1, op2); 40 | break; 41 | 42 | case llvm::Instruction::UDiv: 43 | newInstrs = llvm::BinaryOperator::CreateUDiv(op1, op2); 44 | break; 45 | 46 | case llvm::Instruction::SDiv: 47 | newInstrs = llvm::BinaryOperator::CreateSDiv(op1, op2); 48 | break; 49 | 50 | case llvm::Instruction::And: 51 | newInstrs = llvm::BinaryOperator::CreateAnd(op1, op2); 52 | break; 53 | 54 | case llvm::Instruction::Or: 55 | newInstrs = llvm::BinaryOperator::CreateOr(op1, op2); 56 | break; 57 | 58 | case llvm::Instruction::Xor: 59 | newInstrs = llvm::BinaryOperator::CreateXor(op1, op2); 60 | break; 61 | 62 | case llvm::Instruction::LShr: 63 | newInstrs = llvm::BinaryOperator::CreateLShr(op1, op2); 64 | break; 65 | 66 | case llvm::Instruction::Shl: 67 | newInstrs = llvm::BinaryOperator::CreateShl(op1, op2); 68 | break; 69 | 70 | default: 71 | continue; 72 | } 73 | 74 | llvm::ReplaceInstWithInst(block.getInstList(), instruction, newInstrs); //replace old instruction with new obfuscation instructions 75 | changed = true; 76 | } 77 | } 78 | 79 | return changed; 80 | } 81 | 82 | uint64_t MbaPass::GetSignedMax(llvm::Type* type) { 83 | switch (type->getIntegerBitWidth()) { 84 | case 8: 85 | return CHAR_MAX; 86 | case 16: 87 | return SHRT_MAX; 88 | case 32: 89 | return INT_MAX; 90 | case 64: 91 | return LLONG_MAX; 92 | default: 93 | return CHAR_MAX; 94 | } 95 | } 96 | 97 | /* Gen loads and stores to convert initial value to a 128 bit value (e.g. 32 bit to 128 bit) */ 98 | llvm::Value* MbaPass::GenStackAlignmentCode(llvm::IRBuilder<>& irBuilder, llvm::Type* newType, llvm::Value* operand) { 99 | llvm::Instruction* alloc = irBuilder.CreateAlloca(newType); 100 | auto constZero = llvm::ConstantInt::get(newType, 0); 101 | llvm::Instruction* store = irBuilder.CreateStore(constZero, alloc); 102 | store = irBuilder.CreateStore(operand, alloc); 103 | return irBuilder.CreateLoad(newType, alloc); 104 | } 105 | 106 | /* Recursive function to generate the various mixed arithmetic IR. Essentially creates a reversible tree of IR instructions */ 107 | llvm::Value* MbaPass::Substitute(llvm::IRBuilder<>& irBuilder, llvm::Type* type, llvm::Type* origType, llvm::Value* operand, size_t numRecursions) { 108 | if (numRecursions >= s_RecursiveAmount) { 109 | return operand; 110 | } 111 | 112 | llvm::Instruction* instr = llvm::dyn_cast(operand); 113 | if (instr) { 114 | unsigned int opCode = instr->getOpcode(); 115 | if ((opCode == llvm::Instruction::Add) || (opCode == llvm::Instruction::Sub) || (opCode == llvm::Instruction::UDiv) || 116 | (opCode == llvm::Instruction::SDiv) || (opCode == llvm::Instruction::Xor)) 117 | { 118 | operand->mutateType(type); 119 | } 120 | } 121 | 122 | int randType = m_randGen64() % SubstituteType::Max; //Randomly make obfuscation operation 123 | auto randVal = llvm::ConstantInt::get(type, GetRandomNumber(origType)); //Get random number for each operation 124 | 125 | /* x = (x - randVal) + randVal */ 126 | if (randType == SubstituteType::Add) { 127 | auto a = Substitute(irBuilder, type, origType, irBuilder.CreateSub(operand, randVal), numRecursions+1); 128 | return irBuilder.CreateAdd(a, randVal); 129 | } 130 | 131 | /* x = (x + randVal) - randVal */ 132 | else if (randType == SubstituteType::Subtract) { 133 | auto a = Substitute(irBuilder, type, origType, irBuilder.CreateAdd(operand, randVal), numRecursions+1); 134 | return irBuilder.CreateSub(a, randVal); 135 | } 136 | 137 | /* x = (x * randVal) / randVal */ 138 | else if (randType == SubstituteType::Divide) { 139 | auto a = Substitute(irBuilder, type, origType, operand, numRecursions+1); 140 | return irBuilder.CreateSDiv(irBuilder.CreateMul(a, randVal), randVal); 141 | } 142 | 143 | /* x = ~(~x) */ 144 | else if (randType == SubstituteType::Not) { 145 | auto signedMax = llvm::ConstantInt::get(type, GetSignedMax(origType)); //Get random number for each operation 146 | auto a = Substitute(irBuilder, type, origType, irBuilder.CreateXor(operand, signedMax), numRecursions+1); 147 | return irBuilder.CreateXor(a, signedMax); 148 | } 149 | 150 | /* x = (x ^ randVal) ^ randVal */ 151 | else if (randType == SubstituteType::Xor) { 152 | auto a = Substitute(irBuilder, type, origType, irBuilder.CreateXor(operand, randVal), numRecursions+1); 153 | return irBuilder.CreateXor(a, randVal); 154 | } 155 | 156 | return operand; 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /source/CFF/CffPass.cpp: -------------------------------------------------------------------------------- 1 | #include "CffPass.hpp" 2 | #include 3 | #include 4 | 5 | //Heavily based on Obfuscator-LLVM 6 | //https://github.com/obfuscator-llvm/obfuscator/blob/llvm-4.0/lib/Transforms/Obfuscation/Flattening.cpp 7 | 8 | namespace obfusc { 9 | CffPass::CffPass() {} 10 | CffPass::~CffPass() {} 11 | 12 | bool CffPass::obfuscate(llvm::Module& mod, llvm::Function& func) { 13 | // Copy original blocks 14 | std::vector origBB; 15 | for (auto& block : func) { 16 | if (isa(block.getTerminator())) { 17 | return false; 18 | } 19 | origBB.push_back(&block); 20 | } 21 | 22 | // Nothing to flatten 23 | if (origBB.size() < 2) { 24 | return false; 25 | } 26 | 27 | // Remove first BB 28 | origBB.erase(origBB.begin()); 29 | 30 | // Get a pointer on the first BB 31 | llvm::Function::iterator tmp = func.begin(); 32 | llvm::BasicBlock* insert = &*tmp; 33 | 34 | // If main begin with an if 35 | llvm::BranchInst* br = nullptr; 36 | if (isa(insert->getTerminator())) { 37 | br = cast(insert->getTerminator()); 38 | } 39 | 40 | if ((br != nullptr && br->isConditional()) || insert->getTerminator()->getNumSuccessors() > 1) { 41 | llvm::BasicBlock::iterator i = insert->end(); 42 | --i; 43 | 44 | if (insert->size() > 1) { 45 | --i; 46 | } 47 | 48 | llvm::BasicBlock* tmpBB = insert->splitBasicBlock(i, "first"); 49 | origBB.insert(origBB.begin(), tmpBB); 50 | } 51 | 52 | // Remove jump 53 | insert->getTerminator()->eraseFromParent(); 54 | 55 | // Create switch variable and set as it 56 | llvm::AllocaInst* switchVar = new llvm::AllocaInst(llvm::Type::getInt32Ty(func.getContext()), 0, "switchVar", insert); 57 | new llvm::StoreInst(llvm::ConstantInt::get(llvm::Type::getInt32Ty(func.getContext()), 0), switchVar, insert); 58 | 59 | // Create main loop 60 | llvm::BasicBlock* loopEntry = llvm::BasicBlock::Create(func.getContext(), "loopEntry", &func, insert); 61 | llvm::BasicBlock* loopEnd = llvm::BasicBlock::Create(func.getContext(), "loopEnd", &func, insert); 62 | 63 | llvm::LoadInst* load = new llvm::LoadInst(llvm::Type::getInt32Ty(func.getContext()), switchVar, "switchVar", loopEntry); 64 | 65 | // Move first BB on top 66 | insert->moveBefore(loopEntry); 67 | llvm::BranchInst::Create(loopEntry, insert); 68 | 69 | // loopEnd jump to loopEntry 70 | llvm::BranchInst::Create(loopEntry, loopEnd); 71 | 72 | llvm::BasicBlock* swDefault = llvm::BasicBlock::Create(func.getContext(), "switchDefault", &func, loopEnd); 73 | llvm::BranchInst::Create(loopEnd, swDefault); 74 | 75 | // Create switch instruction itself and set condition 76 | llvm::SwitchInst* switchI = llvm::SwitchInst::Create(&(*(func.begin())), swDefault, 0, loopEntry); 77 | switchI->setCondition(load); 78 | 79 | // Remove branch jump from 1st BB and make a jump to the while 80 | func.begin()->getTerminator()->eraseFromParent(); 81 | 82 | llvm::BranchInst::Create(loopEntry, &(*(func.begin()))); 83 | 84 | // Put all BB in the switch 85 | for (std::vector::iterator b = origBB.begin(); b != origBB.end(); ++b) { 86 | llvm::BasicBlock* i = *b; 87 | 88 | // Move the BB inside the switch (only visual, no code logic) 89 | i->moveBefore(loopEnd); 90 | 91 | // Add case to switch 92 | llvm::ConstantInt* numCase = llvm::cast(llvm::ConstantInt::get(switchI->getCondition()->getType(), switchI->getNumCases())); 93 | switchI->addCase(numCase, i); 94 | } 95 | 96 | // Recalculate switchVar 97 | for (std::vector::iterator b = origBB.begin(); b != origBB.end(); ++b) { 98 | llvm::BasicBlock* i = *b; 99 | 100 | // If it's a non-conditional jump 101 | if (i->getTerminator()->getNumSuccessors() == 1) { 102 | // Get successor and delete terminator 103 | llvm::BasicBlock* succ = i->getTerminator()->getSuccessor(0); 104 | i->getTerminator()->eraseFromParent(); 105 | 106 | // Get next case 107 | llvm::ConstantInt* numCase = switchI->findCaseDest(succ); 108 | 109 | // If next case == default case (switchDefault) 110 | if (numCase == NULL) { 111 | numCase = cast(llvm::ConstantInt::get(switchI->getCondition()->getType(), switchI->getNumCases())); 112 | } 113 | 114 | // Update switchVar and jump to the end of loop 115 | new llvm::StoreInst(numCase, load->getPointerOperand(), i); 116 | llvm::BranchInst::Create(loopEnd, i); 117 | } 118 | 119 | // If it's a conditional jump 120 | else if (i->getTerminator()->getNumSuccessors() == 2) { 121 | // Get next cases 122 | llvm::ConstantInt* numCaseTrue = switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); 123 | llvm::ConstantInt* numCaseFalse = switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); 124 | 125 | // Check if next case == default case (switchDefault) 126 | if (numCaseTrue == NULL) { 127 | numCaseTrue = llvm::cast(llvm::ConstantInt::get(switchI->getCondition()->getType(), switchI->getNumCases())); 128 | } 129 | 130 | if (numCaseFalse == NULL) { 131 | numCaseFalse = llvm::cast(llvm::ConstantInt::get(switchI->getCondition()->getType(), switchI->getNumCases())); 132 | } 133 | 134 | // Create a SelectInst 135 | llvm::BranchInst *br = llvm::cast(i->getTerminator()); 136 | llvm::SelectInst *sel = llvm::SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", i->getTerminator()); 137 | 138 | // Erase terminator 139 | i->getTerminator()->eraseFromParent(); 140 | 141 | // Update switchVar and jump to the end of loop 142 | new llvm::StoreInst(sel, load->getPointerOperand(), i); 143 | llvm::BranchInst::Create(loopEnd, i); 144 | } 145 | } 146 | 147 | fixStack(func); 148 | //func.viewCFG(); 149 | 150 | return true; 151 | } 152 | 153 | //Based on lib/Transforms/Scalar/Reg2Mem.cpp 154 | static bool valueEscapes(const llvm::Instruction& Inst) { 155 | const llvm::BasicBlock* BB = Inst.getParent(); 156 | for (const llvm::User* U : Inst.users()) { 157 | const llvm::Instruction* UI = llvm::cast(U); 158 | if (UI->getParent() != BB || llvm::isa(UI)) { 159 | return true; 160 | } 161 | } 162 | return false; 163 | } 164 | 165 | void CffPass::fixStack(llvm::Function& func) { 166 | // Try to remove phi node and demote reg to stack 167 | std::vector tmpPhi; 168 | std::vector tmpReg; 169 | llvm::BasicBlock& bbEntry = *(func.begin()); 170 | 171 | while (true) { 172 | tmpPhi.clear(); 173 | tmpReg.clear(); 174 | 175 | for (auto& block : func) { 176 | for (auto& instruction : block) { 177 | if (llvm::isa(&instruction)) { 178 | tmpPhi.push_back(llvm::cast(&instruction)); 179 | } 180 | 181 | else if (!(llvm::isa(&instruction) && instruction.getParent() == &bbEntry) && 182 | (valueEscapes(instruction) || instruction.isUsedOutsideOfBlock(&block))) 183 | { 184 | tmpReg.push_back(&instruction); 185 | } 186 | } 187 | } 188 | 189 | for (llvm::Instruction* reg : tmpReg) { 190 | llvm::DemoteRegToStack(*reg, false, func.begin()->getTerminator()); 191 | } 192 | 193 | for (llvm::PHINode* phi : tmpPhi) { 194 | llvm::DemotePHIToStack(phi, func.begin()->getTerminator()); 195 | } 196 | 197 | if (tmpReg.size() == 0 || tmpPhi.size() == 0) { 198 | break; 199 | } 200 | } 201 | } 202 | } --------------------------------------------------------------------------------