├── .gitignore ├── Armariris ├── CMakeLists.txt ├── CryptoUtils.cpp ├── Enter.cpp ├── Flattening.cpp ├── LICENSE-OBFUSCATOR.TXT ├── LLVMBuild.txt ├── StringObfuscation.cpp ├── Substitution.cpp ├── Utils.cpp └── include │ ├── Transforms │ └── Obfuscation │ │ ├── Flattening.h │ │ ├── StringObfuscation.h │ │ ├── Substitution.h │ │ └── Utils.h │ └── llvm │ └── CryptoUtils.h ├── CMakeLists.txt ├── Hikari ├── AntiClassDump.cpp ├── BogusControlFlow.cpp ├── CMakeLists.txt ├── CryptoUtils.cpp ├── Enter.cpp ├── Flattening.cpp ├── FunctionCallObfuscate.cpp ├── FunctionWrapper.cpp ├── IndirectBranch.cpp ├── LICENSE.md ├── LLVMBuild.txt ├── Obfuscation.cpp ├── SplitBasicBlocks.cpp ├── StringEncryption.cpp ├── Substitution.cpp ├── Utils.cpp ├── include │ └── Transforms │ │ └── Obfuscation │ │ ├── AntiClassDump.h │ │ ├── BogusControlFlow.h │ │ ├── CryptoUtils.h │ │ ├── Flattening.h │ │ ├── FunctionCallObfuscate.h │ │ ├── FunctionWrapper.h │ │ ├── IndirectBranch.h │ │ ├── Obfuscation.h │ │ ├── Split.h │ │ ├── StringEncryption.h │ │ ├── Substitution.h │ │ ├── Utils.h │ │ └── compat │ │ └── CallSite.h └── json.hpp ├── LICENSE ├── README.md ├── ollvm ├── BogusControlFlow.cpp ├── CMakeLists.txt ├── CryptoUtils.cpp ├── Enter.cpp ├── Flattening.cpp ├── LICENSE-OBFUSCATOR.TXT ├── SplitBasicBlocks.cpp ├── Substitution.cpp ├── Utils.cpp └── include │ ├── Transforms │ └── Obfuscation │ │ ├── BogusControlFlow.h │ │ ├── Flattening.h │ │ ├── Split.h │ │ ├── Substitution.h │ │ └── Utils.h │ └── llvm │ └── CryptoUtils.h └── skeleton ├── CMakeLists.txt └── Skeleton.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .idea/ 3 | cmake-build-debug/ 4 | -------------------------------------------------------------------------------- /Armariris/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(Armariris MODULE 2 | # List your source files here. 3 | CryptoUtils.cpp 4 | StringObfuscation.cpp 5 | Substitution.cpp 6 | Flattening.cpp 7 | Utils.cpp 8 | include/Transforms/Obfuscation/Flattening.h 9 | include/Transforms/Obfuscation/StringObfuscation.h 10 | include/Transforms/Obfuscation/Substitution.h 11 | include/Transforms/Obfuscation/Utils.h 12 | Enter.cpp 13 | ) 14 | 15 | # Use C++11 to compile your pass (i.e., supply -std=c++11). 16 | target_compile_features(Armariris PRIVATE cxx_range_for cxx_auto_type) 17 | 18 | include_directories(include) 19 | 20 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 21 | # otherwise, we'll get linker errors about missing RTTI data. 22 | set_target_properties(Armariris PROPERTIES 23 | COMPILE_FLAGS "-fno-rtti" 24 | ) 25 | 26 | # Get proper shared-library behavior (where symbols are not necessarily 27 | # resolved when the shared library is linked) on OS X. 28 | if(APPLE) 29 | set_target_properties(Armariris PROPERTIES 30 | LINK_FLAGS "-undefined dynamic_lookup" 31 | ) 32 | endif(APPLE) 33 | -------------------------------------------------------------------------------- /Armariris/Enter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by LeadroyaL on 2018/10/10. 3 | // 4 | 5 | #include "Transforms/Obfuscation/Flattening.h" 6 | #include "Transforms/Obfuscation/StringObfuscation.h" 7 | #include "Transforms/Obfuscation/Substitution.h" 8 | #include "llvm/IR/LegacyPassManager.h" 9 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 10 | 11 | using namespace llvm; 12 | 13 | static void registerArmaririsModulePass(const PassManagerBuilder &, 14 | legacy::PassManagerBase &PM) { 15 | PM.add(createStringObfuscation(true)); 16 | } 17 | 18 | static void registerArmaririsFunctionPass(const PassManagerBuilder &, 19 | legacy::PassManagerBase &PM) { 20 | #if LLVM_VERSION_MAJOR >= 9 21 | PM.add(createLowerSwitchPass()); 22 | #endif 23 | PM.add(createFlattening(true)); 24 | PM.add(createSubstitution(true)); 25 | } 26 | 27 | static RegisterStandardPasses 28 | RegisterMyPass(PassManagerBuilder::EP_EnabledOnOptLevel0, 29 | registerArmaririsModulePass); 30 | static RegisterStandardPasses 31 | RegisterMyPass0(PassManagerBuilder::EP_OptimizerLast, 32 | registerArmaririsModulePass); 33 | static RegisterStandardPasses 34 | RegisterMyPass1(PassManagerBuilder::EP_EarlyAsPossible, 35 | registerArmaririsFunctionPass); -------------------------------------------------------------------------------- /Armariris/Flattening.cpp: -------------------------------------------------------------------------------- 1 | #include "Transforms/Obfuscation/Flattening.h" 2 | #include "Transforms/Obfuscation/Utils.h" 3 | #include "llvm/Transforms/Scalar.h" 4 | #include "llvm/CryptoUtils.h" 5 | 6 | #define DEBUG_TYPE "flattening" 7 | 8 | using namespace llvm; 9 | 10 | // Stats 11 | STATISTIC(Flattened, "Functions flattened"); 12 | 13 | static cl::opt FunctionName( 14 | "funcFLA", cl::init(""), 15 | cl::desc( 16 | "Flatten only certain functions: -mllvm -funcFLA=\"func1,func2\"")); 17 | 18 | static cl::opt Percentage( 19 | "perFLA", cl::init(100), 20 | cl::desc("Flatten only a certain percentage of functions")); 21 | 22 | namespace { 23 | struct Flattening : public FunctionPass { 24 | static char ID; // Pass identification, replacement for typeid 25 | bool flag; 26 | 27 | Flattening() : FunctionPass(ID) {} 28 | Flattening(bool flag) : FunctionPass(ID) { 29 | this->flag = flag; 30 | // Check if the number of applications is correct 31 | if ( !((Percentage > 0) && (Percentage <= 100)) ) { 32 | LLVMContext ctx; 33 | ctx.emitError(Twine ("Flattening application function percentage -perFLA=x must be 0 < x <= 100")); 34 | } 35 | } 36 | 37 | bool runOnFunction(Function &F); 38 | bool flatten(Function *f); 39 | }; 40 | } 41 | 42 | char Flattening::ID = 0; 43 | static RegisterPass X("flattening", "Call graph flattening"); 44 | Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); } 45 | 46 | bool Flattening::runOnFunction(Function &F) { 47 | Function *tmp = &F; 48 | 49 | // Do we obfuscate 50 | if (toObfuscate(flag, tmp, "fla") && ((int)llvm::cryptoutils->get_range(100) <= Percentage)) { 51 | //errs()<<"Flatten: "<getName()<<"\n"; 52 | 53 | /*if(tmp->getName()=="main"){ 54 | errs()<<"Function: "<getName()<<"\n"; 55 | //fixStack(tmp); 56 | flatten(tmp); 57 | ++Flattened; 58 | }*/ 59 | if(flatten(tmp)) { 60 | // errs()<<"Function: "<getName()<<"\n"; 61 | ++Flattened; 62 | } 63 | } 64 | 65 | return false; 66 | } 67 | 68 | bool Flattening::flatten(Function *f) { 69 | vector origBB; 70 | BasicBlock *loopEntry; 71 | BasicBlock *loopEnd; 72 | LoadInst *load; 73 | SwitchInst *switchI; 74 | AllocaInst *switchVar; 75 | 76 | // SCRAMBLER 77 | char scrambling_key[16]; 78 | llvm::cryptoutils->get_bytes(scrambling_key, 16); 79 | // END OF SCRAMBLER 80 | 81 | // Lower switch 82 | #if LLVM_VERSION_MAJOR >= 9 83 | // >=9.0, LowerSwitchPass depends on LazyValueInfoWrapperPass, which cause AssertError. 84 | // So I move LowerSwitchPass into register function, just before FlatteningPass. 85 | #else 86 | FunctionPass *lower = createLowerSwitchPass(); 87 | lower->runOnFunction(*f); 88 | #endif 89 | // Save all original BB 90 | //errs()<<"Flatten: "<getName()<<"\n"; 91 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 92 | BasicBlock *tmp = &*i; 93 | origBB.push_back(tmp); 94 | 95 | BasicBlock *bb = &*i; 96 | //errs()<<(bb->getTerminator()->getNumSuccessors())<<"\n"; 97 | if (isa(bb->getTerminator())) { 98 | /*if(f->getName()=="main"){ 99 | continue; 100 | }*/ 101 | //return false; 102 | continue; 103 | } 104 | } 105 | 106 | // Nothing to flatten 107 | if (origBB.size() <= 1) { 108 | return false; 109 | } 110 | 111 | 112 | 113 | // Remove first BB 114 | origBB.erase(origBB.begin()); 115 | 116 | // Get a pointer on the first BB 117 | Function::iterator tmp = f->begin(); //++tmp; 118 | BasicBlock *insert = &*tmp; 119 | 120 | // If main begin with an if 121 | BranchInst *br = NULL; 122 | if (isa(insert->getTerminator())) { 123 | br = cast(insert->getTerminator()); 124 | //errs()<<"Branch Inst"<<"\n"; 125 | } 126 | 127 | if ((br != NULL && br->isConditional()) || 128 | insert->getTerminator()->getNumSuccessors() > 1) { 129 | BasicBlock::iterator i = insert->back().getIterator(); 130 | //errs()<<"Conditional Branch"<<"\n"; 131 | 132 | if (insert->size() > 1) { 133 | i--; //Get the second last instruction 134 | } 135 | 136 | //errs()<<"IF Original Terminator: "<<*(insert->getTerminator())<<"\n"; 137 | BasicBlock *tmpBB = insert->splitBasicBlock(i, "first"); 138 | origBB.insert(origBB.begin(), tmpBB); 139 | } 140 | 141 | // Remove jump 142 | //errs()<<"Terminator: "<<*(insert->getTerminator())<<"\n"; 143 | insert->getTerminator()->eraseFromParent(); 144 | //errs()<<"New Terminator: "<<*(insert->back().getIterator())<<"\n"; 145 | 146 | // Create switch variable and set as it 147 | switchVar = 148 | new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert); 149 | new StoreInst( 150 | ConstantInt::get(Type::getInt32Ty(f->getContext()), 151 | llvm::cryptoutils->scramble32(0, scrambling_key)), 152 | switchVar, insert); 153 | 154 | // Create main loop 155 | loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert); 156 | loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert); 157 | 158 | load = new LoadInst(switchVar, "switchVar", loopEntry); 159 | 160 | // Move first BB on top 161 | insert->moveBefore(loopEntry); 162 | BranchInst::Create(loopEntry, insert); 163 | 164 | // loopEnd jump to loopEntry 165 | BranchInst::Create(loopEntry, loopEnd); 166 | 167 | BasicBlock *swDefault = 168 | BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd); 169 | BranchInst::Create(loopEnd, swDefault); 170 | 171 | // Create switch instruction itself and set condition 172 | switchI = SwitchInst::Create(&*(f->begin()), swDefault, 0, loopEntry); 173 | switchI->setCondition(load); 174 | 175 | // Remove branch jump from 1st BB and make a jump to the while 176 | //errs()<<"Terminator: "<<*(f->begin()->getTerminator())<<"\n"; 177 | 178 | //f->begin()->getTerminator()->eraseFromParent();//??????????????????????????????????????????????????????????????????????? 179 | //BranchInst::Create(loopEntry, &*(f->begin()));//???????????????????????????????????????????????????????????????????????? 180 | 181 | // Put all BB in the switch 182 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 183 | ++b) { 184 | BasicBlock *i = *b; 185 | ConstantInt *numCase = NULL; 186 | 187 | // Move the BB inside the switch (only visual, no code logic) 188 | i->moveBefore(loopEnd); 189 | 190 | // Add case to switch 191 | numCase = cast(ConstantInt::get( 192 | switchI->getCondition()->getType(), 193 | llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); 194 | switchI->addCase(numCase, i); 195 | } 196 | 197 | // Recalculate switchVar 198 | //errs()<<"Function: "<getName()<<"\n"; 199 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 200 | ++b) { 201 | BasicBlock *i = *b; 202 | ConstantInt *numCase = NULL; 203 | 204 | // errs()<<"Terminator: "<<*(i->getTerminator())<<"\n"; 205 | 206 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 207 | if(isa(i->getTerminator())){ 208 | /*errs()<<"Has invoke instruction"<<"\n"; 209 | errs()<<*(i->getTerminator())<<"\n"; 210 | */ 211 | InvokeInst *tmp=cast(i->getTerminator()); 212 | //i->getTerminator()->eraseFromParent(); 213 | 214 | BasicBlock *transfer=BasicBlock::Create(f->getContext(), "Transfer", f, insert); 215 | BasicBlock *normal=tmp->getNormalDest(); 216 | transfer->moveBefore(loopEnd); 217 | numCase = cast(ConstantInt::get( 218 | switchI->getCondition()->getType(), 219 | llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); 220 | switchI->addCase(numCase, transfer); 221 | BranchInst::Create(normal,transfer); 222 | 223 | tmp->setNormalDest(transfer); 224 | 225 | numCase = switchI->findCaseDest(transfer); 226 | 227 | if (numCase == NULL) { 228 | numCase = cast( 229 | ConstantInt::get(switchI->getCondition()->getType(), 230 | llvm::cryptoutils->scramble32( 231 | switchI->getNumCases() - 1, scrambling_key))); 232 | } 233 | 234 | StoreInst *store=new StoreInst(numCase, load->getPointerOperand(),i); 235 | store->moveBefore(tmp); 236 | 237 | BranchInst::Create(loopEnd, i); 238 | //tmp->eraseFromParent(); 239 | continue; 240 | 241 | } 242 | 243 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 244 | 245 | 246 | // Ret BB 247 | if (i->getTerminator()->getNumSuccessors() == 0) { 248 | continue; 249 | } 250 | 251 | // If it's a non-conditional jump 252 | if (i->getTerminator()->getNumSuccessors() == 1) { 253 | // Get successor and delete terminator 254 | BasicBlock *succ = i->getTerminator()->getSuccessor(0); 255 | i->getTerminator()->eraseFromParent(); 256 | 257 | // Get next case 258 | numCase = switchI->findCaseDest(succ); 259 | 260 | // If next case == default case (switchDefault) 261 | if (numCase == NULL) { 262 | numCase = cast( 263 | ConstantInt::get(switchI->getCondition()->getType(), 264 | llvm::cryptoutils->scramble32( 265 | switchI->getNumCases() - 1, scrambling_key))); 266 | } 267 | 268 | // Update switchVar and jump to the end of loop 269 | new StoreInst(numCase, load->getPointerOperand(), i); 270 | BranchInst::Create(loopEnd, i); 271 | continue; 272 | } 273 | 274 | // If it's a conditional jump 275 | if (i->getTerminator()->getNumSuccessors() == 2) { 276 | // Get next cases 277 | ConstantInt *numCaseTrue = 278 | switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); 279 | ConstantInt *numCaseFalse = 280 | switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); 281 | 282 | // Check if next case == default case (switchDefault) 283 | if (numCaseTrue == NULL) { 284 | numCaseTrue = cast( 285 | ConstantInt::get(switchI->getCondition()->getType(), 286 | llvm::cryptoutils->scramble32( 287 | switchI->getNumCases() - 1, scrambling_key))); 288 | } 289 | 290 | if (numCaseFalse == NULL) { 291 | numCaseFalse = cast( 292 | ConstantInt::get(switchI->getCondition()->getType(), 293 | llvm::cryptoutils->scramble32( 294 | switchI->getNumCases() - 1, scrambling_key))); 295 | } 296 | 297 | // Create a SelectInst 298 | BranchInst *br = cast(i->getTerminator()); 299 | SelectInst *sel = 300 | SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", 301 | i->getTerminator()); 302 | 303 | // Erase terminator 304 | i->getTerminator()->eraseFromParent(); 305 | 306 | // Update switchVar and jump to the end of loop 307 | new StoreInst(sel, load->getPointerOperand(), i); 308 | BranchInst::Create(loopEnd, i); 309 | continue; 310 | } 311 | } 312 | 313 | fixStack(f); 314 | 315 | return true; 316 | } 317 | -------------------------------------------------------------------------------- /Armariris/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 | -------------------------------------------------------------------------------- /Armariris/LLVMBuild.txt: -------------------------------------------------------------------------------- 1 | ;===- ./lib/Transforms/Scalar/LLVMBuild.txt --------------------*- Conf -*--===; 2 | ; 3 | ; The LLVM Compiler Infrastructure 4 | ; 5 | ; This file is distributed under the University of Illinois Open Source 6 | ; License. See LICENSE.TXT for details. 7 | ; 8 | ;===------------------------------------------------------------------------===; 9 | ; 10 | ; This is an LLVMBuild description file for the components in this subdirectory. 11 | ; 12 | ; For more information on the LLVMBuild system, please see: 13 | ; 14 | ; http://llvm.org/docs/LLVMBuild.html 15 | ; 16 | ;===------------------------------------------------------------------------===; 17 | 18 | [component_0] 19 | type = Library 20 | name = Obfuscation 21 | parent = Transforms 22 | library_name = Obfuscation 23 | 24 | -------------------------------------------------------------------------------- /Armariris/StringObfuscation.cpp: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "objdiv" 2 | #include 3 | #include 4 | 5 | #include "llvm/ADT/Statistic.h" 6 | #include "llvm/IR/Function.h" 7 | #include "llvm/IR/Constants.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/IR/Value.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | #include "llvm/CryptoUtils.h" 13 | #include "Transforms/Obfuscation/StringObfuscation.h" 14 | #include "llvm/IR/IRBuilder.h" 15 | #include "llvm/Transforms/Utils/ModuleUtils.h" 16 | 17 | using namespace llvm; 18 | 19 | STATISTIC(GlobalsEncoded, "Counts number of global variables encoded"); 20 | 21 | namespace llvm { 22 | 23 | struct encVar { 24 | public: 25 | GlobalVariable *var; 26 | uint8_t key; 27 | }; 28 | 29 | class StringObfuscationPass: public llvm::ModulePass { 30 | public: 31 | static char ID; // pass identification 32 | bool is_flag = false; 33 | StringObfuscationPass() : ModulePass(ID) {} 34 | StringObfuscationPass(bool flag) : ModulePass(ID) 35 | { 36 | is_flag = flag; 37 | } 38 | 39 | virtual bool runOnModule(Module &M) { 40 | if(!is_flag) 41 | return false; 42 | std::vector toDelConstGlob; 43 | //std::vector encGlob; 44 | std::vector encGlob; 45 | for (Module::global_iterator gi = M.global_begin(), ge = M.global_end(); 46 | gi != ge; ++gi) { 47 | // Loop over all global variables 48 | GlobalVariable* gv = &(*gi); 49 | //errs() << "Global var " << gv->getName(); 50 | std::string::size_type str_idx = gv->getName().str().find(".str."); 51 | std::string section(gv->getSection()); 52 | 53 | // Let's encode the static ones 54 | if (gv->getName().str().substr(0,4)==".str"&& 55 | gv->isConstant() && 56 | gv->hasInitializer() && 57 | isa(gv->getInitializer()) && 58 | section != "llvm.metadata" && 59 | section.find("__objc_methname") == std::string::npos 60 | /*&&gv->getType()->getArrayElementType()->getArrayElementType()->isIntegerTy()*/) { 61 | ++GlobalsEncoded; 62 | //errs() << " is constant"; 63 | 64 | // Duplicate global variable 65 | GlobalVariable *dynGV = new GlobalVariable(M, 66 | gv->getType()->getElementType(), 67 | !(gv->isConstant()), gv->getLinkage(), 68 | (Constant*) 0, gv->getName(), 69 | (GlobalVariable*) 0, 70 | gv->getThreadLocalMode(), 71 | gv->getType()->getAddressSpace()); 72 | // dynGV->copyAttributesFrom(gv); 73 | dynGV->setInitializer(gv->getInitializer()); 74 | 75 | std::string tmp=gv->getName().str(); 76 | // errs()<<"GV: "<<*gv<<"\n"; 77 | 78 | Constant *initializer = gv->getInitializer(); 79 | ConstantDataSequential *cdata = dyn_cast(initializer); 80 | if (cdata) { 81 | const char *orig = cdata->getRawDataValues().data(); 82 | unsigned len = cdata->getNumElements()*cdata->getElementByteSize(); 83 | 84 | encVar *cur = new encVar(); 85 | cur->var = dynGV; 86 | cur->key = llvm::cryptoutils->get_uint8_t(); 87 | // casting away const is undef. behavior in C++ 88 | // TODO a clean implementation would retrieve the data, generate a new constant 89 | // set the correct type, and copy the data over. 90 | //char *encr = new char[len]; 91 | //Constant *initnew = ConstantDataArray::getString(M.getContext(), encr, true); 92 | char *encr = const_cast(orig); 93 | // Simple xor encoding 94 | for (unsigned i = 0; i != len; ++i) { 95 | encr[i] = orig[i]^cur->key; 96 | } 97 | 98 | // FIXME Second part of the unclean hack. 99 | dynGV->setInitializer(initializer); 100 | 101 | // Prepare to add decode function for this variable 102 | encGlob.push_back(cur); 103 | } else { 104 | // just copying default initializer for now 105 | dynGV->setInitializer(initializer); 106 | } 107 | 108 | // redirect references to new GV and remove old one 109 | gv->replaceAllUsesWith(dynGV); 110 | toDelConstGlob.push_back(gv); 111 | 112 | } 113 | } 114 | 115 | // actuallte delete marked globals 116 | for (unsigned i = 0, e = toDelConstGlob.size(); i != e; ++i) 117 | toDelConstGlob[i]->eraseFromParent(); 118 | 119 | addDecodeFunction(&M, &encGlob); 120 | 121 | 122 | return true; 123 | } 124 | 125 | private: 126 | void addDecodeFunction(Module *mod, std::vector *gvars) { 127 | // Declare and add the function definition 128 | //errs()<<"Successful enter decode function"<<"\n"; 129 | std::vectorFuncTy_args; 130 | FunctionType* FuncTy = FunctionType::get( 131 | /*Result=*/Type::getVoidTy(mod->getContext()), // returning void 132 | /*Params=*/FuncTy_args, // taking no args 133 | /*isVarArg=*/false); 134 | uint64_t StringObfDecodeRandomName = cryptoutils->get_uint64_t(); 135 | std::string random_str; 136 | std::stringstream random_stream; 137 | random_stream << StringObfDecodeRandomName; 138 | random_stream >> random_str; 139 | StringObfDecodeRandomName++; 140 | #if LLVM_VERSION_MAJOR >= 9 141 | FunctionCallee c = mod->getOrInsertFunction(".datadiv_decode" + random_str, FuncTy); 142 | Function* fdecode = cast(c.getCallee()); 143 | fdecode->setCallingConv(CallingConv::C); 144 | #else 145 | Constant* c = mod->getOrInsertFunction(".datadiv_decode" + random_str, FuncTy); 146 | Function* fdecode = cast(c); 147 | fdecode->setCallingConv(CallingConv::C); 148 | #endif 149 | 150 | 151 | BasicBlock* entry = BasicBlock::Create(mod->getContext(), "entry", fdecode); 152 | 153 | IRBuilder<> builder(mod->getContext()); 154 | builder.SetInsertPoint(entry); 155 | 156 | 157 | for (unsigned i = 0, e = gvars->size(); i != e; ++i) { 158 | GlobalVariable *gvar = (*gvars)[i]->var; 159 | uint8_t key = (*gvars)[i]->key; 160 | 161 | Constant *init = gvar->getInitializer(); 162 | ConstantDataSequential *cdata = dyn_cast(init); 163 | 164 | unsigned len = cdata->getNumElements()*cdata->getElementByteSize(); 165 | --len; 166 | 167 | BasicBlock *preHeaderBB=builder.GetInsertBlock(); 168 | BasicBlock* for_body = BasicBlock::Create(mod->getContext(), "for-body", fdecode); 169 | BasicBlock* for_end = BasicBlock::Create(mod->getContext(), "for-end", fdecode); 170 | builder.CreateBr(for_body); 171 | builder.SetInsertPoint(for_body); 172 | PHINode *variable = builder.CreatePHI(Type::getInt32Ty(mod->getContext()), 2, "i"); 173 | Value *startValue = builder.getInt32(0); 174 | Value *endValue = builder.getInt32(len); 175 | variable->addIncoming(startValue, preHeaderBB); 176 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 177 | 178 | //LoadInst *Load=builder.CreateLoad(gvar); 179 | //errs()<<"Load: "<<*(Load->getPointerOperand())<<"\n"; 180 | Value* indexList[2] = {ConstantInt::get(variable->getType(), 0), variable}; 181 | Value *const_key=builder.getInt8(key); 182 | Value *GEP=builder.CreateGEP(gvar,ArrayRef(indexList, 2),"arrayIdx"); 183 | LoadInst *loadElement=builder.CreateLoad(GEP,false); 184 | #if LLVM_VERSION_MAJOR >= 10 185 | loadElement->setAlignment(MaybeAlign(1)); 186 | #else 187 | loadElement->setAlignment(1); 188 | #endif 189 | //errs()<<"Type: "<<*loadElement<<"\n"; 190 | //CastInst* extended = new ZExtInst(const_key, loadElement->getType(), "extended", for_body); 191 | //Value* extended = builder.CreateZExtOrBitCast(const_key, loadElement->getType(),"extended"); 192 | Value *Xor = builder.CreateXor(loadElement,const_key,"xor"); 193 | StoreInst *Store = builder.CreateStore(Xor, GEP,false); 194 | #if LLVM_VERSION_MAJOR >= 10 195 | Store->setAlignment(MaybeAlign(1)); 196 | #else 197 | Store->setAlignment(1); 198 | #endif 199 | 200 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 201 | Value *stepValue = builder.getInt32(1); 202 | Value *nextValue = builder.CreateAdd(variable, stepValue, "next-value"); 203 | Value *endCondition = builder.CreateICmpULT(variable, endValue, "end-condition"); 204 | endCondition = builder.CreateICmpNE(endCondition, builder.getInt1(0), "loop-condition"); 205 | BasicBlock *loopEndBB = builder.GetInsertBlock(); 206 | builder.CreateCondBr(endCondition, loopEndBB, for_end); 207 | builder.SetInsertPoint(for_end); 208 | variable->addIncoming(nextValue, loopEndBB); 209 | 210 | } 211 | builder.CreateRetVoid(); 212 | appendToGlobalCtors(*mod,fdecode,0); 213 | 214 | 215 | } 216 | 217 | }; 218 | 219 | } 220 | 221 | char StringObfuscationPass::ID = 0; 222 | static RegisterPass X("GVDiv", "Global variable (i.e., const char*) diversification pass", false, true); 223 | 224 | Pass * llvm::createStringObfuscation(bool flag) { 225 | return new StringObfuscationPass(flag); 226 | } 227 | -------------------------------------------------------------------------------- /Armariris/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Transforms/Obfuscation/Utils.h" 2 | #include "llvm/Support/raw_ostream.h" 3 | #include 4 | #include "llvm/IR/Module.h" 5 | 6 | // Shamefully borrowed from ../Scalar/RegToMem.cpp :( 7 | bool valueEscapes(Instruction *Inst) { 8 | BasicBlock *BB = Inst->getParent(); 9 | for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; 10 | ++UI) { 11 | Instruction *I = cast(*UI); 12 | if (I->getParent() != BB || isa(I)) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | 19 | void fixStack(Function *f) { 20 | // Try to remove phi node and demote reg to stack 21 | std::vector tmpPhi; 22 | std::vector tmpReg; 23 | BasicBlock *bbEntry = &*(f->begin()); 24 | 25 | do { 26 | tmpPhi.clear(); 27 | tmpReg.clear(); 28 | 29 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 30 | 31 | for (BasicBlock::iterator j = i->begin(); j != i->end(); ++j) { 32 | 33 | if (isa(j)) { 34 | PHINode *phi = cast(j); 35 | tmpPhi.push_back(phi); 36 | continue; 37 | } 38 | if (!(isa(j) && j->getParent() == bbEntry) && 39 | (valueEscapes(&*j) || j->isUsedOutsideOfBlock(&*i))) { 40 | tmpReg.push_back(&*j); 41 | continue; 42 | } 43 | } 44 | } 45 | for (unsigned int i = 0; i != tmpReg.size(); ++i) { 46 | DemoteRegToStack(*tmpReg.at(i), f->begin()->getTerminator()); 47 | } 48 | 49 | for (unsigned int i = 0; i != tmpPhi.size(); ++i) { 50 | DemotePHIToStack(tmpPhi.at(i), f->begin()->getTerminator()); 51 | } 52 | 53 | } while (tmpReg.size() != 0 || tmpPhi.size() != 0); 54 | } 55 | 56 | std::string readAnnotate(Function *f) { 57 | std::string annotation = ""; 58 | 59 | // Get annotation variable 60 | GlobalVariable *glob = 61 | f->getParent()->getGlobalVariable("llvm.global.annotations"); 62 | 63 | if (glob != NULL) { 64 | // Get the array 65 | if (ConstantArray *ca = dyn_cast(glob->getInitializer())) { 66 | for (unsigned i = 0; i < ca->getNumOperands(); ++i) { 67 | // Get the struct 68 | if (ConstantStruct *structAn = 69 | dyn_cast(ca->getOperand(i))) { 70 | if (ConstantExpr *expr = 71 | dyn_cast(structAn->getOperand(0))) { 72 | // If it's a bitcast we can check if the annotation is concerning 73 | // the current function 74 | if (expr->getOpcode() == Instruction::BitCast && 75 | expr->getOperand(0) == f) { 76 | ConstantExpr *note = cast(structAn->getOperand(1)); 77 | // If it's a GetElementPtr, that means we found the variable 78 | // containing the annotations 79 | if (note->getOpcode() == Instruction::GetElementPtr) { 80 | if (GlobalVariable *annoteStr = 81 | dyn_cast(note->getOperand(0))) { 82 | if (ConstantDataSequential *data = 83 | dyn_cast( 84 | annoteStr->getInitializer())) { 85 | if (data->isString()) { 86 | annotation += data->getAsString().lower() + " "; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | return annotation; 98 | } 99 | 100 | bool toObfuscate(bool flag, Function *f, std::string attribute) { 101 | std::string attr = attribute; 102 | std::string attrNo = "no" + attr; 103 | 104 | // Check if declaration 105 | if (f->isDeclaration()) { 106 | return false; 107 | } 108 | 109 | // Check external linkage 110 | if(f->hasAvailableExternallyLinkage() != 0) { 111 | return false; 112 | } 113 | 114 | // We have to check the nofla flag first 115 | // Because .find("fla") is true for a string like "fla" or 116 | // "nofla" 117 | if (readAnnotate(f).find(attrNo) != std::string::npos) { 118 | return false; 119 | } 120 | 121 | // If fla annotations 122 | if (readAnnotate(f).find(attr) != std::string::npos) { 123 | return true; 124 | } 125 | 126 | // If fla flag is set 127 | if (flag == true) { 128 | /* Check if the number of applications is correct 129 | if (!((Percentage > 0) && (Percentage <= 100))) { 130 | LLVMContext &ctx = llvm::getGlobalContext(); 131 | ctx.emitError(Twine("Flattening application function\ 132 | percentage -perFLA=x must be 0 < x <= 100")); 133 | } 134 | // Check name 135 | else if (func.size() != 0 && func.find(f->getName()) != std::string::npos) { 136 | return true; 137 | } 138 | 139 | if ((((int)llvm::cryptoutils->get_range(100))) < Percentage) { 140 | return true; 141 | } 142 | */ 143 | return true; 144 | } 145 | 146 | return false; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /Armariris/include/Transforms/Obfuscation/Flattening.h: -------------------------------------------------------------------------------- 1 | #ifndef _FLATTENING_INCLUDES_ 2 | #define _FLATTENING_INCLUDES_ 3 | 4 | 5 | // LLVM include 6 | #include "llvm/Pass.h" 7 | #include "llvm/IR/Function.h" 8 | #include "llvm/ADT/Statistic.h" 9 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 10 | #include "llvm/Transforms/IPO.h" 11 | #include "llvm/Transforms/Scalar.h" 12 | #include "llvm/IR/Module.h" 13 | #include "llvm/Support/CommandLine.h" 14 | #include "llvm/CryptoUtils.h" 15 | #include "llvm/Transforms/Utils.h" 16 | 17 | // Namespace 18 | using namespace std; 19 | 20 | namespace llvm { 21 | Pass *createFlattening(); 22 | Pass *createFlattening(bool flag); 23 | } 24 | 25 | #endif 26 | 27 | -------------------------------------------------------------------------------- /Armariris/include/Transforms/Obfuscation/StringObfuscation.h: -------------------------------------------------------------------------------- 1 | // LLVM include 2 | #include "llvm/Pass.h" 3 | 4 | namespace llvm { 5 | Pass* createStringObfuscation(bool flag); 6 | } 7 | -------------------------------------------------------------------------------- /Armariris/include/Transforms/Obfuscation/Substitution.h: -------------------------------------------------------------------------------- 1 | #ifndef _SUBSTITUTIONS_H_ 2 | #define _SUBSTITUTIONS_H_ 3 | 4 | 5 | // LLVM include 6 | #include "llvm/Pass.h" 7 | #include "llvm/IR/Function.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/ADT/Statistic.h" 10 | #include "llvm/Transforms/IPO.h" 11 | #include "llvm/IR/Module.h" 12 | #include "llvm/Support/CommandLine.h" 13 | #include "llvm/CryptoUtils.h" 14 | 15 | // Namespace 16 | using namespace llvm; 17 | using namespace std; 18 | 19 | namespace llvm { 20 | Pass *createSubstitution (); 21 | Pass *createSubstitution (bool flag); 22 | } 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /Armariris/include/Transforms/Obfuscation/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_OBF__ 2 | #define __UTILS_OBF__ 3 | 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | void fixStack(Function *f); 12 | std::string readAnnotate(Function *f); 13 | bool toObfuscate(bool flag, Function *f, std::string attribute); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /Armariris/include/llvm/CryptoUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef LLVM_CryptoUtils_H 2 | #define LLVM_CryptoUtils_H 3 | 4 | #include "llvm/Support/ManagedStatic.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace llvm { 12 | 13 | class CryptoUtils; 14 | extern ManagedStatic cryptoutils; 15 | 16 | #define BYTE(x, n) (((x) >> (8 * (n))) & 0xFF) 17 | 18 | #if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 19 | defined(INTEL_CC) 20 | 21 | #ifndef ENDIAN_LITTLE 22 | #define ENDIAN_LITTLE 23 | #endif 24 | #define ENDIAN_32BITWORD 25 | #define UNALIGNED 26 | 27 | #elif defined(__alpha) 28 | 29 | #ifndef ENDIAN_LITTLE 30 | #define ENDIAN_LITTLE 31 | #endif 32 | #define ENDIAN_64BITWORD 33 | 34 | #elif defined(__x86_64__) 35 | 36 | #ifndef ENDIAN_LITTLE 37 | #define ENDIAN_LITTLE 38 | #endif 39 | #define ENDIAN_64BITWORD 40 | #define UNALIGNED 41 | 42 | #elif(defined(__R5900) || defined(R5900) || defined(__R5900__)) && \ 43 | (defined(_mips) || defined(__mips__) || defined(mips)) 44 | 45 | #ifndef ENDIAN_LITTLE 46 | #define ENDIAN_LITTLE 47 | #endif 48 | #define ENDIAN_64BITWORD 49 | 50 | #elif defined(__sparc) 51 | 52 | #ifndef ENDIAN_BIG 53 | #define ENDIAN_BIG 54 | #endif 55 | #if defined(__arch64__) 56 | #define ENDIAN_64BITWORD 57 | #else 58 | #define ENDIAN_32BITWORD 59 | #endif 60 | 61 | #endif 62 | 63 | #if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) 64 | #define ENDIAN_BIG 65 | #endif 66 | 67 | #if !defined(ENDIAN_BIG) && !defined(ENDIAN_LITTLE) 68 | #error \ 69 | "Unknown endianness of the compilation platform, check this header aes_encrypt.h" 70 | #endif 71 | 72 | #ifdef ENDIAN_LITTLE 73 | 74 | #define STORE32H(y, x) \ 75 | { \ 76 | (y)[0] = (uint8_t)(((x) >> 24) & 0xFF); \ 77 | (y)[1] = (uint8_t)(((x) >> 16) & 0xFF); \ 78 | (y)[2] = (uint8_t)(((x) >> 8) & 0xFF); \ 79 | (y)[3] = (uint8_t)(((x) >> 0) & 0xFF); \ 80 | } 81 | #define LOAD32H(x, y) \ 82 | { \ 83 | (x) = ((uint32_t)((y)[0] & 0xFF) << 24) | \ 84 | ((uint32_t)((y)[1] & 0xFF) << 16) | \ 85 | ((uint32_t)((y)[2] & 0xFF) << 8) | ((uint32_t)((y)[3] & 0xFF) << 0); \ 86 | } 87 | 88 | #define LOAD64H(x, y) \ 89 | { \ 90 | (x) = ((uint64_t)((y)[0] & 0xFF) << 56) | \ 91 | ((uint64_t)((y)[1] & 0xFF) << 48) | \ 92 | ((uint64_t)((y)[2] & 0xFF) << 40) | \ 93 | ((uint64_t)((y)[3] & 0xFF) << 32) | \ 94 | ((uint64_t)((y)[4] & 0xFF) << 24) | \ 95 | ((uint64_t)((y)[5] & 0xFF) << 16) | \ 96 | ((uint64_t)((y)[6] & 0xFF) << 8) | ((uint64_t)((y)[7] & 0xFF) << 0); \ 97 | } 98 | 99 | #define STORE64H(y, x) \ 100 | { \ 101 | (y)[0] = (uint8_t)(((x) >> 56) & 0xFF); \ 102 | (y)[1] = (uint8_t)(((x) >> 48) & 0xFF); \ 103 | (y)[2] = (uint8_t)(((x) >> 40) & 0xFF); \ 104 | (y)[3] = (uint8_t)(((x) >> 32) & 0xFF); \ 105 | (y)[4] = (uint8_t)(((x) >> 24) & 0xFF); \ 106 | (y)[5] = (uint8_t)(((x) >> 16) & 0xFF); \ 107 | (y)[6] = (uint8_t)(((x) >> 8) & 0xFF); \ 108 | (y)[7] = (uint8_t)(((x) >> 0) & 0xFF); \ 109 | } 110 | 111 | #endif /* ENDIAN_LITTLE */ 112 | 113 | #ifdef ENDIAN_BIG 114 | 115 | #define STORE32H(y, x) \ 116 | { \ 117 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 118 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 119 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 120 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 121 | } 122 | #define STORE64H(y, x) \ 123 | { \ 124 | (y)[7] = (uint8_t)(((x) >> 56) & 0xFF); \ 125 | (y)[6] = (uint8_t)(((x) >> 48) & 0xFF); \ 126 | (y)[5] = (uint8_t)(((x) >> 40) & 0xFF); \ 127 | (y)[4] = (uint8_t)(((x) >> 32) & 0xFF); \ 128 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 129 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 130 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 131 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 132 | } 133 | #define LOAD32H(x, y) \ 134 | { \ 135 | (x) = ((uint32_t)((y)[3] & 0xFF) << 24) | \ 136 | ((uint32_t)((y)[2] & 0xFF) << 16) | \ 137 | ((uint32_t)((y)[1] & 0xFF) << 8) | ((uint32_t)((y)[0] & 0xFF) << 0); \ 138 | } 139 | 140 | #define LOAD64H(x, y) \ 141 | { \ 142 | (x) = ((uint64_t)((y)[7] & 0xFF) << 56) | \ 143 | ((uint64_t)((y)[6] & 0xFF) << 48) | \ 144 | ((uint64_t)((y)[5] & 0xFF) << 40) | \ 145 | ((uint64_t)((y)[4] & 0xFF) << 32) | \ 146 | ((uint64_t)((y)[3] & 0xFF) << 24) | \ 147 | ((uint64_t)((y)[2] & 0xFF) << 16) | \ 148 | ((uint64_t)((y)[1] & 0xFF) << 8) | ((uint64_t)((y)[0] & 0xFF) << 0); \ 149 | } 150 | 151 | #endif /* ENDIAN_BIG */ 152 | 153 | #define AES_TE0(x) AES_PRECOMP_TE0[(x)] 154 | #define AES_TE1(x) AES_PRECOMP_TE1[(x)] 155 | #define AES_TE2(x) AES_PRECOMP_TE2[(x)] 156 | #define AES_TE3(x) AES_PRECOMP_TE3[(x)] 157 | 158 | #define AES_TE4_0(x) AES_PRECOMP_TE4_0[(x)] 159 | #define AES_TE4_1(x) AES_PRECOMP_TE4_1[(x)] 160 | #define AES_TE4_2(x) AES_PRECOMP_TE4_2[(x)] 161 | #define AES_TE4_3(x) AES_PRECOMP_TE4_3[(x)] 162 | 163 | #define CryptoUtils_POOL_SIZE (0x1 << 17) // 2^17 164 | 165 | #define DUMP(x, l, s) \ 166 | fprintf(stderr, "%s :", (s)); \ 167 | for (int ii = 0; ii < (l); ii++) { \ 168 | fprintf(stderr, "%02hhX", *((x) + ii)); \ 169 | } \ 170 | fprintf(stderr, "\n"); 171 | 172 | // SHA256 173 | /* Various logical functions */ 174 | #define Ch(x, y, z) (z ^ (x &(y ^ z))) 175 | #define Maj(x, y, z) (((x | y) & z) | (x &y)) 176 | #define __S(x, n) RORc((x), (n)) 177 | #define __R(x, n) (((x) & 0xFFFFFFFFUL) >> (n)) 178 | #define Sigma0(x) (__S(x, 2) ^ __S(x, 13) ^ __S(x, 22)) 179 | #define Sigma1(x) (__S(x, 6) ^ __S(x, 11) ^ __S(x, 25)) 180 | #define Gamma0(x) (__S(x, 7) ^ __S(x, 18) ^ __R(x, 3)) 181 | #define Gamma1(x) (__S(x, 17) ^ __S(x, 19) ^ __R(x, 10)) 182 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 183 | 184 | #define RND(a, b, c, d, e, f, g, h, i, ki) \ 185 | t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ 186 | t1 = Sigma0(a) + Maj(a, b, c); \ 187 | d += t0; \ 188 | h = t0 + t1; 189 | 190 | #define RORc(x, y) \ 191 | (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ 192 | ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & \ 193 | 0xFFFFFFFFUL) 194 | 195 | class CryptoUtils { 196 | public: 197 | CryptoUtils(); 198 | ~CryptoUtils(); 199 | 200 | void get_bytes(char *buffer, const int len); 201 | char get_char(); 202 | void prng_seed(const std::string seed); 203 | 204 | // Returns a uniformly distributed 8-bit value 205 | uint8_t get_uint8_t(); 206 | // Returns a uniformly distributed 32-bit value 207 | uint32_t get_uint32_t(); 208 | // Returns an integer uniformly distributed on [0, max[ 209 | uint32_t get_range(const uint32_t max); 210 | // Returns a uniformly distributed 64-bit value 211 | uint64_t get_uint64_t(); 212 | 213 | // Scramble a 32-bit value depending on a 128-bit value 214 | unsigned scramble32(const unsigned in, const char key[16]); 215 | 216 | private: 217 | char key[4]; 218 | char pool[CryptoUtils_POOL_SIZE]; 219 | uint32_t idx; 220 | std::string seed; 221 | bool seeded; 222 | 223 | std::mt19937 gen; 224 | 225 | void prng_seed(); 226 | void populate_pool(); 227 | }; 228 | } 229 | 230 | #endif // LLVM_CryptoUtils_H 231 | 232 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(llvm-pass-tutorial) 3 | 4 | # we need LLVM_HOME in order not automatically set LLVM_DIR 5 | if(NOT DEFINED ENV{LLVM_HOME}) 6 | message(FATAL_ERROR "$LLVM_HOME is not defined") 7 | else () 8 | set(ENV{LLVM_DIR} $ENV{LLVM_HOME}/lib64/cmake/llvm) 9 | endif() 10 | 11 | find_package(LLVM REQUIRED CONFIG) 12 | add_definitions(${LLVM_DEFINITIONS}) 13 | include_directories(${LLVM_INCLUDE_DIRS}) 14 | link_directories(${LLVM_LIBRARY_DIRS}) 15 | if (${LLVM_VERSION_MAJOR} VERSION_GREATER_EQUAL 10) 16 | set(CMAKE_CXX_STANDARD 14) 17 | endif () 18 | 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 20 | include_directories($ENV{LLVM_HOME}/include/c++v1) 21 | set(CMAKE_SKIP_RPATH ON) 22 | 23 | # add_subdirectory(skeleton) # Use your pass name here. 24 | # add_subdirectory(ollvm) # ollvm 25 | add_subdirectory(Hikari) # Hikari 26 | # add_subdirectory(Armariris) # Armariris 27 | -------------------------------------------------------------------------------- /Hikari/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(Hikari MODULE 2 | # List your source files here. 3 | FunctionCallObfuscate.cpp 4 | CryptoUtils.cpp 5 | BogusControlFlow.cpp 6 | Substitution.cpp 7 | Flattening.cpp 8 | Utils.cpp 9 | SplitBasicBlocks.cpp 10 | AntiClassDump.cpp 11 | StringEncryption.cpp 12 | IndirectBranch.cpp 13 | FunctionWrapper.cpp 14 | # Obfuscation.cpp 15 | include/Transforms/Obfuscation/AntiClassDump.h 16 | include/Transforms/Obfuscation/BogusControlFlow.h 17 | include/Transforms/Obfuscation/CryptoUtils.h 18 | include/Transforms/Obfuscation/Flattening.h 19 | include/Transforms/Obfuscation/FunctionCallObfuscate.h 20 | include/Transforms/Obfuscation/FunctionWrapper.h 21 | include/Transforms/Obfuscation/IndirectBranch.h 22 | include/Transforms/Obfuscation/Obfuscation.h 23 | include/Transforms/Obfuscation/Split.h 24 | include/Transforms/Obfuscation/StringEncryption.h 25 | include/Transforms/Obfuscation/Substitution.h 26 | include/Transforms/Obfuscation/Utils.h 27 | Enter.cpp 28 | ) 29 | 30 | # Use C++11 to compile your pass (i.e., supply -std=c++11). 31 | target_compile_features(Hikari PRIVATE cxx_range_for cxx_auto_type) 32 | 33 | include_directories(include) 34 | 35 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 36 | # otherwise, we'll get linker errors about missing RTTI data. 37 | set_target_properties(Hikari PROPERTIES 38 | COMPILE_FLAGS "-fno-rtti" 39 | ) 40 | 41 | # Get proper shared-library behavior (where symbols are not necessarily 42 | # resolved when the shared library is linked) on OS X. 43 | if(APPLE) 44 | set_target_properties(Hikari PROPERTIES 45 | LINK_FLAGS "-undefined dynamic_lookup" 46 | ) 47 | endif(APPLE) 48 | -------------------------------------------------------------------------------- /Hikari/Enter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by LeadroyaL on 2018/10/10. 3 | // 4 | 5 | #include "Transforms/Obfuscation/Obfuscation.h" 6 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 7 | 8 | #if LLVM_VERSION_MAJOR >= 13 9 | #include "llvm/Passes/PassBuilder.h" 10 | #include "llvm/Passes/PassPlugin.h" 11 | 12 | namespace llvm { 13 | 14 | llvm::PassPluginLibraryInfo getOllvmPluginInfo() { 15 | return { 16 | LLVM_PLUGIN_API_VERSION, "Hikari", LLVM_VERSION_STRING, 17 | [](PassBuilder &PB) { 18 | // cryptoutils->prng_seed(); 19 | PB.registerPipelineStartEPCallback( 20 | [](llvm::ModulePassManager &PM, 21 | llvm::OptimizationLevel Level) { 22 | PM.addPass(AntiClassDumpPass()); /*only apple*/ 23 | PM.addPass(FunctionCallObfuscatePass()); /*only apple*/ 24 | PM.addPass(IndirectBranchPass()); 25 | 26 | llvm::FunctionPassManager FPM; 27 | FPM.addPass(BogusControlFlowPass()); 28 | FPM.addPass(FlatteningPass()); 29 | FPM.addPass(SplitBasicBlockPass()); 30 | FPM.addPass(SubstitutionPass()); 31 | PM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); 32 | }); 33 | 34 | PB.registerOptimizerLastEPCallback( 35 | [](llvm::ModulePassManager &PM, 36 | llvm::OptimizationLevel Level) { 37 | PM.addPass(StringEncryptionPass()); 38 | PM.addPass(FunctionWrapperPass()); 39 | }); 40 | }}; 41 | } 42 | 43 | extern "C" LLVM_ATTRIBUTE_WEAK llvm::PassPluginLibraryInfo 44 | llvmGetPassPluginInfo() { 45 | return getOllvmPluginInfo(); 46 | } 47 | 48 | } 49 | #else 50 | using namespace llvm; 51 | 52 | static void registerHikariModulePass(const PassManagerBuilder &, 53 | legacy::PassManagerBase &PM) { 54 | // PM.add(createFunctionWrapperPass(true)); /*broken*/ 55 | PM.add(createStringEncryptionPass(true)); 56 | 57 | } 58 | 59 | static void registerHikariFunctionPass(const PassManagerBuilder &, 60 | legacy::PassManagerBase &PM) { 61 | PM.add(createBogusControlFlowPass(true)); 62 | #if LLVM_VERSION_MAJOR >= 9 63 | PM.add(createLowerSwitchPass()); 64 | #endif 65 | PM.add(createFlatteningPass(true)); 66 | PM.add(createFunctionCallObfuscatePass(true)); 67 | PM.add(createIndirectBranchPass(true)); 68 | PM.add(createSplitBasicBlockPass(true)); 69 | PM.add(createSubstitutionPass(true)); 70 | } 71 | 72 | static RegisterStandardPasses 73 | RegisterMyPass(PassManagerBuilder::EP_EnabledOnOptLevel0, 74 | registerHikariModulePass); 75 | static RegisterStandardPasses 76 | RegisterMyPass0(PassManagerBuilder::EP_OptimizerLast, 77 | registerHikariModulePass); 78 | static RegisterStandardPasses 79 | RegisterMyPass1(PassManagerBuilder::EP_EarlyAsPossible, 80 | registerHikariFunctionPass); 81 | #endif -------------------------------------------------------------------------------- /Hikari/Flattening.cpp: -------------------------------------------------------------------------------- 1 | //===- Flattening.cpp - Flattening Obfuscation pass------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file implements the flattening pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "Transforms/Obfuscation/Obfuscation.h" 15 | #include "Transforms/Obfuscation/CryptoUtils.h" 16 | #include 17 | #include 18 | 19 | #define DEBUG_TYPE "flattening" 20 | 21 | using namespace llvm; 22 | 23 | // Stats 24 | STATISTIC(Flattened, "Functions flattened"); 25 | 26 | namespace { 27 | struct Flattening : public FunctionPass { 28 | static char ID; // Pass identification, replacement for typeid 29 | bool flag; 30 | Flattening() : FunctionPass(ID) { this->flag = true; } 31 | Flattening(bool flag) : FunctionPass(ID) { this->flag = flag; } 32 | bool runOnFunction(Function &F); 33 | bool flatten(Function *f); 34 | }; 35 | } // namespace 36 | 37 | char Flattening::ID = 0; 38 | FunctionPass *llvm::createFlatteningPass(bool flag) { 39 | return new Flattening(flag); 40 | } 41 | FunctionPass *llvm::createFlatteningPass() { return new Flattening(); } 42 | INITIALIZE_PASS(Flattening, "cffobf", "Enable Control Flow Flattening.", true, 43 | true) 44 | bool Flattening::runOnFunction(Function &F) { 45 | Function *tmp = &F; 46 | // Do we obfuscate 47 | if (toObfuscate(flag, tmp, "fla")) { 48 | errs() << "Running ControlFlowFlattening On " << F.getName() << "\n"; 49 | if (flatten(tmp)) { 50 | ++Flattened; 51 | } 52 | } 53 | 54 | return false; 55 | } 56 | 57 | bool Flattening::flatten(Function *f) { 58 | vector origBB; 59 | BasicBlock *loopEntry; 60 | BasicBlock *loopEnd; 61 | LoadInst *load; 62 | SwitchInst *switchI; 63 | AllocaInst *switchVar; 64 | 65 | // SCRAMBLER 66 | char scrambling_key[16]; 67 | llvm::cryptoutils->get_bytes(scrambling_key, 16); 68 | // END OF SCRAMBLER 69 | 70 | #if LLVM_VERSION_MAJOR >= 9 71 | // >=9.0, LowerSwitchPass depends on LazyValueInfoWrapperPass, which cause AssertError. 72 | // So I move LowerSwitchPass into register function, just before FlatteningPass. 73 | #else 74 | FunctionPass *lower = createLowerSwitchPass(); 75 | lower->runOnFunction(*f); 76 | #endif 77 | 78 | // Save all original BB 79 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 80 | BasicBlock *tmp = &*i; 81 | if (tmp->isEHPad() || tmp->isLandingPad()) { 82 | errs()<getName()<<" Contains Exception Handing Instructions and is unsupported for flattening in the open-source version of Hikari.\n"; 83 | return false; 84 | } 85 | origBB.push_back(tmp); 86 | 87 | BasicBlock *bb = &*i; 88 | if (!isa(bb->getTerminator())) { 89 | return false; 90 | } 91 | } 92 | 93 | // Nothing to flatten 94 | if (origBB.size() <= 1) { 95 | return false; 96 | } 97 | 98 | // Remove first BB 99 | origBB.erase(origBB.begin()); 100 | 101 | // Get a pointer on the first BB 102 | Function::iterator tmp = f->begin(); //++tmp; 103 | BasicBlock *insert = &*tmp; 104 | 105 | // If main begin with an if 106 | BranchInst *br = NULL; 107 | if (isa(insert->getTerminator())) { 108 | br = cast(insert->getTerminator()); 109 | } 110 | 111 | if ((br != NULL && br->isConditional()) || 112 | insert->getTerminator()->getNumSuccessors() > 1) { 113 | BasicBlock::iterator i = insert->end(); 114 | --i; 115 | 116 | if (insert->size() > 1) { 117 | --i; 118 | } 119 | 120 | BasicBlock *tmpBB = insert->splitBasicBlock(i, "first"); 121 | origBB.insert(origBB.begin(), tmpBB); 122 | } 123 | 124 | // Remove jump 125 | insert->getTerminator()->eraseFromParent(); 126 | 127 | // Create switch variable and set as it 128 | switchVar = 129 | new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert); 130 | new StoreInst( 131 | ConstantInt::get(Type::getInt32Ty(f->getContext()), 132 | llvm::cryptoutils->scramble32(0, scrambling_key)), 133 | switchVar, insert); 134 | 135 | // Create main loop 136 | loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert); 137 | loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert); 138 | 139 | #if LLVM_VERSION_MAJOR >= 13 140 | load = new LoadInst(switchVar->getType()->getPointerElementType(), switchVar, "switchVar", loopEntry); 141 | #else 142 | load = new LoadInst(switchVar, "switchVar", loopEntry); 143 | #endif 144 | 145 | // Move first BB on top 146 | insert->moveBefore(loopEntry); 147 | BranchInst::Create(loopEntry, insert); 148 | 149 | // loopEnd jump to loopEntry 150 | BranchInst::Create(loopEntry, loopEnd); 151 | 152 | BasicBlock *swDefault = 153 | BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd); 154 | BranchInst::Create(loopEnd, swDefault); 155 | 156 | // Create switch instruction itself and set condition 157 | switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry); 158 | switchI->setCondition(load); 159 | 160 | // Remove branch jump from 1st BB and make a jump to the while 161 | f->begin()->getTerminator()->eraseFromParent(); 162 | 163 | BranchInst::Create(loopEntry, &*f->begin()); 164 | 165 | // Put all BB in the switch 166 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 167 | ++b) { 168 | BasicBlock *i = *b; 169 | ConstantInt *numCase = NULL; 170 | 171 | // Move the BB inside the switch (only visual, no code logic) 172 | i->moveBefore(loopEnd); 173 | 174 | // Add case to switch 175 | numCase = cast(ConstantInt::get( 176 | switchI->getCondition()->getType(), 177 | llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); 178 | switchI->addCase(numCase, i); 179 | } 180 | 181 | // Recalculate switchVar 182 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 183 | ++b) { 184 | BasicBlock *i = *b; 185 | ConstantInt *numCase = NULL; 186 | 187 | // Ret BB 188 | if (i->getTerminator()->getNumSuccessors() == 0) { 189 | continue; 190 | } 191 | 192 | // If it's a non-conditional jump 193 | if (i->getTerminator()->getNumSuccessors() == 1) { 194 | // Get successor and delete terminator 195 | BasicBlock *succ = i->getTerminator()->getSuccessor(0); 196 | i->getTerminator()->eraseFromParent(); 197 | 198 | // Get next case 199 | numCase = switchI->findCaseDest(succ); 200 | 201 | // If next case == default case (switchDefault) 202 | if (numCase == NULL) { 203 | numCase = cast( 204 | ConstantInt::get(switchI->getCondition()->getType(), 205 | llvm::cryptoutils->scramble32( 206 | switchI->getNumCases() - 1, scrambling_key))); 207 | } 208 | 209 | // Update switchVar and jump to the end of loop 210 | new StoreInst(numCase, load->getPointerOperand(), i); 211 | BranchInst::Create(loopEnd, i); 212 | continue; 213 | } 214 | 215 | // If it's a conditional jump 216 | if (i->getTerminator()->getNumSuccessors() == 2) { 217 | // Get next cases 218 | ConstantInt *numCaseTrue = 219 | switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); 220 | ConstantInt *numCaseFalse = 221 | switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); 222 | 223 | // Check if next case == default case (switchDefault) 224 | if (numCaseTrue == NULL) { 225 | numCaseTrue = cast( 226 | ConstantInt::get(switchI->getCondition()->getType(), 227 | llvm::cryptoutils->scramble32( 228 | switchI->getNumCases() - 1, scrambling_key))); 229 | } 230 | 231 | if (numCaseFalse == NULL) { 232 | numCaseFalse = cast( 233 | ConstantInt::get(switchI->getCondition()->getType(), 234 | llvm::cryptoutils->scramble32( 235 | switchI->getNumCases() - 1, scrambling_key))); 236 | } 237 | 238 | // Create a SelectInst 239 | BranchInst *br = cast(i->getTerminator()); 240 | SelectInst *sel = 241 | SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", 242 | i->getTerminator()); 243 | 244 | // Erase terminator 245 | i->getTerminator()->eraseFromParent(); 246 | // Update switchVar and jump to the end of loop 247 | new StoreInst(sel, load->getPointerOperand(), i); 248 | BranchInst::Create(loopEnd, i); 249 | continue; 250 | } 251 | } 252 | errs()<<"Fixing Stack\n"; 253 | fixStack(f); 254 | errs()<<"Fixed Stack\n"; 255 | return true; 256 | } 257 | 258 | #if LLVM_VERSION_MAJOR >= 13 259 | PreservedAnalyses FlatteningPass::run(Function& F, FunctionAnalysisManager& AM) { 260 | Flattening cff; 261 | cff.runOnFunction(F); 262 | 263 | return PreservedAnalyses::all(); 264 | } 265 | #endif 266 | -------------------------------------------------------------------------------- /Hikari/FunctionCallObfuscate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LLVM CallSite Obfuscation Pass 3 | * It works by scanning all CallSites that refers to a function outside of 4 | * current translation unit then replace then with dlopen/dlsym calls 5 | Copyright (C) 2017 Zhang(https://github.com/Naville/) 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as published 9 | by the Free Software Foundation, either version 3 of the License, or 10 | any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | You should have received a copy of the GNU Affero General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include "json.hpp" 21 | #include "llvm/ADT/Triple.h" 22 | #include "llvm/IR/Constants.h" 23 | #include "llvm/IR/IRBuilder.h" 24 | #include "llvm/IR/Instructions.h" 25 | #include "llvm/IR/LegacyPassManager.h" 26 | #include "llvm/IR/Module.h" 27 | #include "llvm/IR/Value.h" 28 | #include "llvm/Pass.h" 29 | #include "llvm/Support/Path.h" 30 | #include "llvm/Support/raw_ostream.h" 31 | #include "Transforms/Obfuscation/Obfuscation.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #if LLVM_VERSION_MAJOR > 10 40 | #include "Transforms/Obfuscation/compat/CallSite.h" 41 | #else 42 | #include "llvm/IR/CallSite.h" 43 | #endif 44 | using namespace llvm; 45 | using namespace std; 46 | using json = nlohmann::json; 47 | static cl::opt 48 | SymbolConfigPath("fcoconfig", 49 | cl::desc("FunctionCallObfuscate Configuration Path"), 50 | cl::value_desc("filename"), cl::init("+-x/")); 51 | namespace llvm { 52 | struct FunctionCallObfuscate : public FunctionPass { 53 | static char ID; 54 | json Configuration; 55 | bool flag; 56 | FunctionCallObfuscate() : FunctionPass(ID) { this->flag = true; } 57 | FunctionCallObfuscate(bool flag) : FunctionPass(ID) { this->flag = flag; } 58 | StringRef getPassName() const override { 59 | return StringRef("FunctionCallObfuscate"); 60 | } 61 | virtual bool doInitialization(Module &M) override { 62 | // Basic Defs 63 | if (SymbolConfigPath == "+-x/") { 64 | SmallString<32> Path; 65 | if (sys::path::home_directory(Path)) { // Stolen from LineEditor.cpp 66 | sys::path::append(Path, "Hikari", "SymbolConfig.json"); 67 | #if LLVM_VERSION_MAJOR >= 13 68 | SymbolConfigPath = Path.str().str(); 69 | #else 70 | SymbolConfigPath = Path.str(); 71 | #endif 72 | } 73 | } 74 | ifstream infile(SymbolConfigPath); 75 | if (infile.good()) { 76 | errs() << "Loading Symbol Configuration From:" << SymbolConfigPath 77 | << "\n"; 78 | infile >> this->Configuration; 79 | } else { 80 | errs() << "Failed To Loading Symbol Configuration From:" 81 | << SymbolConfigPath << "\n"; 82 | } 83 | Triple tri(M.getTargetTriple()); 84 | if (tri.getVendor() != Triple::VendorType::Apple) { 85 | return false; 86 | } 87 | Type *Int64Ty = Type::getInt64Ty(M.getContext()); 88 | Type *Int32Ty = Type::getInt32Ty(M.getContext()); 89 | Type *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); 90 | Type *Int8Ty = Type::getInt8Ty(M.getContext()); 91 | // Generic ObjC Runtime Declarations 92 | FunctionType *IMPType = 93 | FunctionType::get(Int8PtrTy, {Int8PtrTy, Int8PtrTy}, true); 94 | PointerType *IMPPointerType = PointerType::get(IMPType, 0); 95 | vector classReplaceMethodTypeArgs; 96 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 97 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 98 | classReplaceMethodTypeArgs.push_back(IMPPointerType); 99 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 100 | FunctionType *class_replaceMethod_type = 101 | FunctionType::get(IMPPointerType, classReplaceMethodTypeArgs, false); 102 | M.getOrInsertFunction("class_replaceMethod", class_replaceMethod_type); 103 | FunctionType *sel_registerName_type = 104 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 105 | M.getOrInsertFunction("sel_registerName", sel_registerName_type); 106 | FunctionType *objc_getClass_type = 107 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 108 | M.getOrInsertFunction("objc_getClass", objc_getClass_type); 109 | M.getOrInsertFunction("objc_getMetaClass", objc_getClass_type); 110 | StructType *objc_property_attribute_t_type = reinterpret_cast( 111 | #if LLVM_VERSION_MAJOR >= 13 112 | StructType::getTypeByName(M.getContext(), "struct.objc_property_attribute_t")); 113 | #else 114 | M.getTypeByName("struct.objc_property_attribute_t")); 115 | #endif 116 | if (objc_property_attribute_t_type == NULL) { 117 | vector types; 118 | types.push_back(Int8PtrTy); 119 | types.push_back(Int8PtrTy); 120 | objc_property_attribute_t_type = StructType::create( 121 | ArrayRef(types), "struct.objc_property_attribute_t"); 122 | M.getOrInsertGlobal("struct.objc_property_attribute_t", 123 | objc_property_attribute_t_type); 124 | } 125 | vector allocaClsTypeVector; 126 | vector addIvarTypeVector; 127 | vector addPropTypeVector; 128 | allocaClsTypeVector.push_back(Int8PtrTy); 129 | allocaClsTypeVector.push_back(Int8PtrTy); 130 | addIvarTypeVector.push_back(Int8PtrTy); 131 | addIvarTypeVector.push_back(Int8PtrTy); 132 | addPropTypeVector.push_back(Int8PtrTy); 133 | addPropTypeVector.push_back(Int8PtrTy); 134 | addPropTypeVector.push_back(objc_property_attribute_t_type->getPointerTo()); 135 | if (tri.isArch64Bit()) { 136 | // We are 64Bit Device 137 | allocaClsTypeVector.push_back(Int64Ty); 138 | addIvarTypeVector.push_back(Int64Ty); 139 | addPropTypeVector.push_back(Int64Ty); 140 | } else { 141 | // Not 64Bit.However we are still on apple platform.So We are 142 | // ARMV7/ARMV7S/i386 143 | // PowerPC is ignored, feel free to open a PR if you want to 144 | allocaClsTypeVector.push_back(Int32Ty); 145 | addIvarTypeVector.push_back(Int32Ty); 146 | addPropTypeVector.push_back(Int32Ty); 147 | } 148 | addIvarTypeVector.push_back(Int8Ty); 149 | addIvarTypeVector.push_back(Int8PtrTy); 150 | // Types Collected. Now Inject Functions 151 | FunctionType *addIvarType = 152 | FunctionType::get(Int8Ty, ArrayRef(addIvarTypeVector), false); 153 | M.getOrInsertFunction("class_addIvar", addIvarType); 154 | FunctionType *addPropType = 155 | FunctionType::get(Int8Ty, ArrayRef(addPropTypeVector), false); 156 | M.getOrInsertFunction("class_addProperty", addPropType); 157 | FunctionType *class_getName_Type = 158 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 159 | M.getOrInsertFunction("class_getName", class_getName_Type); 160 | FunctionType *objc_getMetaClass_Type = 161 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 162 | M.getOrInsertFunction("objc_getMetaClass", objc_getMetaClass_Type); 163 | return true; 164 | } 165 | void HandleObjC(Module &M) { 166 | // Iterate all CLASSREF uses and replace with objc_getClass() call 167 | // Strings are encrypted in other passes 168 | for (auto G = M.global_begin(); G != M.global_end(); G++) { 169 | GlobalVariable &GV = *G; 170 | if (GV.getName().str().find("OBJC_CLASSLIST_REFERENCES") == 0) { 171 | if (GV.hasInitializer()) { 172 | #if LLVM_VERSION_MAJOR >= 13 173 | string className = GV.getInitializer()->getName().str(); 174 | #else 175 | string className = GV.getInitializer()->getName(); 176 | #endif 177 | className.replace(className.find("OBJC_CLASS_$_"), 178 | strlen("OBJC_CLASS_$_"), ""); 179 | for (auto U = GV.user_begin(); U != GV.user_end(); U++) { 180 | if (Instruction *I = dyn_cast(*U)) { 181 | IRBuilder<> builder(I); 182 | Function *objc_getClass_Func = 183 | cast(M.getFunction("objc_getClass")); 184 | Value *newClassName = 185 | builder.CreateGlobalStringPtr(StringRef(className)); 186 | CallInst *CI = 187 | builder.CreateCall(objc_getClass_Func, {newClassName}); 188 | // We need to bitcast it back to avoid IRVerifier 189 | Value *BCI = builder.CreateBitCast(CI, I->getType()); 190 | I->replaceAllUsesWith(BCI); 191 | I->eraseFromParent(); 192 | } 193 | } 194 | GV.removeDeadConstantUsers(); 195 | if (GV.getNumUses() == 0) { 196 | GV.dropAllReferences(); 197 | GV.eraseFromParent(); 198 | } 199 | } 200 | } 201 | // Selector Convert 202 | else if (GV.getName().str().find("OBJC_SELECTOR_REFERENCES") == 0) { 203 | if (GV.hasInitializer()) { 204 | ConstantExpr *CE = dyn_cast(GV.getInitializer()); 205 | Constant *C = CE->getOperand(0); 206 | GlobalVariable *SELNameGV = dyn_cast(C); 207 | ConstantDataArray *CDA = 208 | dyn_cast(SELNameGV->getInitializer()); 209 | StringRef SELName = CDA->getAsString(); // This is REAL Selector Name 210 | for (auto U = GV.user_begin(); U != GV.user_end(); U++) { 211 | if (Instruction *I = dyn_cast(*U)) { 212 | IRBuilder<> builder(I); 213 | Function *sel_registerName_Func = 214 | cast(M.getFunction("sel_registerName")); 215 | Value *newGlobalSELName = builder.CreateGlobalStringPtr(SELName); 216 | CallInst *CI = 217 | builder.CreateCall(sel_registerName_Func, {newGlobalSELName}); 218 | // We need to bitcast it back to avoid IRVerifier 219 | Value *BCI = builder.CreateBitCast(CI, I->getType()); 220 | I->replaceAllUsesWith(BCI); 221 | I->eraseFromParent(); 222 | } 223 | } 224 | GV.removeDeadConstantUsers(); 225 | if (GV.getNumUses() == 0) { 226 | GV.dropAllReferences(); 227 | GV.eraseFromParent(); 228 | } 229 | } 230 | } 231 | } 232 | } 233 | virtual bool runOnFunction(Function &F) override { 234 | // Construct Function Prototypes 235 | if (toObfuscate(flag, &F, "fco") == false) { 236 | return false; 237 | } 238 | errs() << "Running FunctionCallObfuscate On " << F.getName() << "\n"; 239 | Module *M = F.getParent(); 240 | FixFunctionConstantExpr(&F); 241 | HandleObjC(*M); 242 | Type *Int32Ty = Type::getInt32Ty(M->getContext()); 243 | Type *Int8PtrTy = Type::getInt8PtrTy(M->getContext()); 244 | // ObjC Runtime Declarations 245 | FunctionType *dlopen_type = FunctionType::get( 246 | Int8PtrTy, {Int8PtrTy, Int32Ty}, 247 | false); // int has a length of 32 on both 32/64bit platform 248 | FunctionType *dlsym_type = 249 | FunctionType::get(Int8PtrTy, {Int8PtrTy, Int8PtrTy}, false); 250 | #if LLVM_VERSION_MAJOR >= 9 251 | FunctionCallee dlopen_decl = M->getOrInsertFunction("dlopen", dlopen_type); 252 | FunctionCallee dlsym_decl = M->getOrInsertFunction("dlsym", dlsym_type); 253 | #else 254 | Function *dlopen_decl = 255 | cast(M->getOrInsertFunction("dlopen", dlopen_type)); 256 | Function *dlsym_decl = 257 | cast(M->getOrInsertFunction("dlsym", dlsym_type)); 258 | #endif 259 | // Begin Iteration 260 | for (BasicBlock &BB : F) { 261 | for (auto I = BB.getFirstInsertionPt(), end = BB.end(); I != end; ++I) { 262 | Instruction &Inst = *I; 263 | if (isa(&Inst) || isa(&Inst)) { 264 | CallSite CS(&Inst); 265 | Function *calledFunction = CS.getCalledFunction(); 266 | if (calledFunction == NULL) { 267 | /* 268 | Note: 269 | For Indirect Calls: 270 | CalledFunction is NULL and calledValue is usually a bitcasted 271 | function pointer. We'll need to strip out the hiccups and obtain 272 | the called Function* from there 273 | */ 274 | calledFunction = 275 | dyn_cast(CS.getCalledValue()->stripPointerCasts()); 276 | } 277 | // Simple Extracting Failed 278 | // Use our own implementation 279 | if (calledFunction == NULL) { 280 | DEBUG_WITH_TYPE( 281 | "opt", errs() 282 | << "Failed To Extract Function From Indirect Call: " 283 | << *CS.getCalledValue() << "\n"); 284 | continue; 285 | } 286 | // It's only safe to restrict our modification to external symbols 287 | // Otherwise stripped binary will crash 288 | if (!calledFunction->empty() || 289 | calledFunction->getName().equals("dlsym") || 290 | calledFunction->getName().equals("dlopen") || 291 | calledFunction->isIntrinsic()) { 292 | continue; 293 | } 294 | // errs()<<"Searching For:"<getName()<<" In 295 | // Configuration\n"; 296 | if (this->Configuration.find(calledFunction->getName().str()) != 297 | this->Configuration.end()) { 298 | string sname = this->Configuration[calledFunction->getName().str()] 299 | .get(); 300 | StringRef calledFunctionName = StringRef(sname); 301 | BasicBlock *EntryBlock = CS->getParent(); 302 | IRBuilder<> IRB(EntryBlock, EntryBlock->getFirstInsertionPt()); 303 | vector dlopenargs; 304 | dlopenargs.push_back(Constant::getNullValue(Int8PtrTy)); 305 | dlopenargs.push_back( 306 | ConstantInt::get(Int32Ty, RTLD_NOW | RTLD_GLOBAL)); 307 | Value *Handle = 308 | IRB.CreateCall(dlopen_decl, ArrayRef(dlopenargs)); 309 | // Create dlsym call 310 | vector args; 311 | args.push_back(Handle); 312 | args.push_back(IRB.CreateGlobalStringPtr(calledFunctionName)); 313 | Value *fp = IRB.CreateCall(dlsym_decl, ArrayRef(args)); 314 | Value *bitCastedFunction = 315 | IRB.CreateBitCast(fp, CS.getCalledValue()->getType()); 316 | CS.setCalledFunction(bitCastedFunction); 317 | } 318 | } 319 | } 320 | } 321 | return true; 322 | } 323 | }; 324 | FunctionPass *createFunctionCallObfuscatePass() { 325 | return new FunctionCallObfuscate(); 326 | } 327 | FunctionPass *createFunctionCallObfuscatePass(bool flag) { 328 | return new FunctionCallObfuscate(flag); 329 | } 330 | } // namespace llvm 331 | char FunctionCallObfuscate::ID = 0; 332 | INITIALIZE_PASS(FunctionCallObfuscate, "fcoobf", 333 | "Enable Function CallSite Obfuscation.", true, true) 334 | 335 | #if LLVM_VERSION_MAJOR >= 13 336 | PreservedAnalyses FunctionCallObfuscatePass::run(Module &M, ModuleAnalysisManager& AM) { 337 | FunctionCallObfuscate FOC; 338 | errs() << "FunctionCallObfuscate call\n"; 339 | FOC.doFinalization(M); 340 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 341 | Function &F = *iter; 342 | if (!F.isDeclaration()) 343 | FOC.runOnFunction(F); 344 | } 345 | return PreservedAnalyses::all(); 346 | } 347 | #endif 348 | -------------------------------------------------------------------------------- /Hikari/FunctionWrapper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LLVM FunctionWrapper Pass 3 | Copyright (C) 2017 Zhang(https://github.com/Naville/) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published 7 | by the Free Software Foundation, either version 3 of the License, or 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "llvm/IR/Constants.h" 19 | #include "llvm/IR/IRBuilder.h" 20 | #include "llvm/IR/InstIterator.h" 21 | #include "llvm/IR/Instructions.h" 22 | #include "llvm/IR/Module.h" 23 | #include "llvm/IR/Value.h" 24 | #include "llvm/Pass.h" 25 | #include "Transforms/Obfuscation/Obfuscation.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #if LLVM_VERSION_MAJOR > 10 31 | #include "Transforms/Obfuscation/compat/CallSite.h" 32 | #else 33 | #include "llvm/IR/CallSite.h" 34 | #endif 35 | using namespace llvm; 36 | using namespace std; 37 | static cl::opt 38 | ProbRate("fw_prob", 39 | cl::desc("Choose the probability [%] For Each CallSite To Be " 40 | "Obfuscated By FunctionWrapper"), 41 | cl::value_desc("Probability Rate"), cl::init(30), cl::Optional); 42 | static cl::opt ObfTimes( 43 | "fw_times", 44 | cl::desc( 45 | "Choose how many time the FunctionWrapper pass loop on a CallSite"), 46 | cl::value_desc("Number of Times"), cl::init(2), cl::Optional); 47 | namespace llvm { 48 | struct FunctionWrapper : public ModulePass { 49 | static char ID; 50 | bool flag; 51 | FunctionWrapper() : ModulePass(ID) { this->flag = true; } 52 | FunctionWrapper(bool flag) : ModulePass(ID) { this->flag = flag; } 53 | StringRef getPassName() const override { 54 | return StringRef("FunctionWrapper"); 55 | } 56 | bool runOnModule(Module &M) override { 57 | vector callsites; 58 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 59 | Function &F = *iter; 60 | if (toObfuscate(flag, &F, "fw")) { 61 | errs() << "Running FunctionWrapper On " << F.getName() << "\n"; 62 | for (inst_iterator fi = inst_begin(&F); fi != inst_end(&F); fi++) { 63 | Instruction *Inst = &*fi; 64 | if (isa(Inst) || isa(Inst)) { 65 | if ((int)llvm::cryptoutils->get_range(100) <= ProbRate) { 66 | callsites.push_back(new CallSite(Inst)); 67 | } 68 | } 69 | } 70 | } 71 | } 72 | for (CallSite *CS : callsites) { 73 | for (int i = 0; i < ObfTimes && CS != nullptr; i++) { 74 | CS = HandleCallSite(CS); 75 | } 76 | } 77 | return true; 78 | } // End of runOnModule 79 | CallSite *HandleCallSite(CallSite *CS) { 80 | Value *calledFunction = CS->getCalledFunction(); 81 | if (calledFunction == nullptr) { 82 | calledFunction = CS->getCalledValue()->stripPointerCasts(); 83 | } 84 | // Filter out IndirectCalls that depends on the context 85 | // Otherwise It'll be blantantly troublesome since you can't reference an 86 | // Instruction outside its BB Too much trouble for a hobby project 87 | // To be precise, we only keep CS that refers to a non-intrinsic function 88 | // either directly or through casting 89 | #if LLVM_VERSION_MAJOR >= 10 90 | if (calledFunction == nullptr || 91 | (!isa(calledFunction) && 92 | !isa(calledFunction)) || 93 | CS->getIntrinsicID() != Intrinsic::not_intrinsic) { 94 | return nullptr; 95 | } 96 | #else 97 | if (calledFunction == nullptr || 98 | (!isa(calledFunction) && 99 | !isa(calledFunction)) || 100 | CS->getIntrinsicID() != Intrinsic::ID::not_intrinsic) { 101 | return nullptr; 102 | } 103 | #endif 104 | if (Function *tmp = dyn_cast(calledFunction)) { 105 | if (tmp->getName().startswith("clang.")) { 106 | // Clang Intrinsic 107 | return nullptr; 108 | } 109 | } 110 | // Create a new function which in turn calls the actual function 111 | vector types; 112 | for (unsigned i = 0; i < CS->getNumArgOperands(); i++) { 113 | types.push_back(CS->getArgOperand(i)->getType()); 114 | } 115 | FunctionType *ft = 116 | FunctionType::get(CS->getType(), ArrayRef(types), false); 117 | Function *func = 118 | Function::Create(ft, GlobalValue::LinkageTypes::InternalLinkage, 119 | "HikariFunctionWrapper", CS->getParent()->getModule()); 120 | appendToCompilerUsed(*func->getParent(), {func}); 121 | // FIXME: Correctly Steal Function Attributes 122 | //func->addFnAttr(Attribute::AttrKind::OptimizeNone); 123 | //func->addFnAttr(Attribute::AttrKind::NoInline); 124 | func->copyAttributesFrom(cast(calledFunction)); 125 | BasicBlock *BB = BasicBlock::Create(func->getContext(), "", func); 126 | IRBuilder<> IRB(BB); 127 | vector params; 128 | for (auto arg = func->arg_begin(); arg != func->arg_end(); arg++) { 129 | params.push_back(arg); 130 | } 131 | Value *retval = IRB.CreateCall( 132 | #if LLVM_VERSION_MAJOR >= 13 133 | cast(ConstantExpr::getBitCast(cast(calledFunction),CS->getCalledValue()->getType())->getType()->getPointerElementType()), 134 | #endif 135 | ConstantExpr::getBitCast(cast(calledFunction),CS->getCalledValue()->getType()), ArrayRef(params)); 136 | if (ft->getReturnType()->isVoidTy()) { 137 | IRB.CreateRetVoid(); 138 | } else { 139 | IRB.CreateRet(retval); 140 | } 141 | CS->setCalledFunction(func); 142 | CS->mutateFunctionType(ft); 143 | Instruction *Inst = CS->getInstruction(); 144 | delete CS; 145 | return new CallSite(Inst); 146 | } 147 | }; 148 | ModulePass *createFunctionWrapperPass() { return new FunctionWrapper(); } 149 | ModulePass *createFunctionWrapperPass(bool flag) { 150 | return new FunctionWrapper(flag); 151 | } 152 | } // namespace llvm 153 | 154 | char FunctionWrapper::ID = 0; 155 | INITIALIZE_PASS(FunctionWrapper, "funcwra", "Enable FunctionWrapper.", true, 156 | true) 157 | 158 | #if LLVM_VERSION_MAJOR >= 13 159 | PreservedAnalyses FunctionWrapperPass::run(Module &M, ModuleAnalysisManager& AM) { 160 | FunctionWrapper FW; 161 | FW.runOnModule(M); 162 | 163 | return PreservedAnalyses::all(); 164 | } 165 | #endif 166 | -------------------------------------------------------------------------------- /Hikari/IndirectBranch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | LLVM Indirect Branching Pass 3 | Copyright (C) 2017 Zhang(https://github.com/Naville/) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published 7 | by the Free Software Foundation, either version 3 of the License, or 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "llvm/IR/Constants.h" 19 | #include "llvm/IR/IRBuilder.h" 20 | #include "llvm/IR/InstIterator.h" 21 | #include "llvm/IR/Instructions.h" 22 | #include "llvm/IR/Module.h" 23 | #include "llvm/IR/Value.h" 24 | #include "llvm/Pass.h" 25 | #include "llvm/Support/CommandLine.h" 26 | #include "llvm/Support/raw_ostream.h" 27 | #include "Transforms/Obfuscation/Obfuscation.h" 28 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 29 | using namespace llvm; 30 | using namespace std; 31 | namespace llvm { 32 | struct IndirectBranch : public FunctionPass { 33 | static char ID; 34 | bool flag; 35 | bool initialized; 36 | map indexmap; 37 | IndirectBranch() : FunctionPass(ID) { 38 | this->flag = true; 39 | this->initialized = false; 40 | } 41 | IndirectBranch(bool flag) : FunctionPass(ID) { 42 | this->flag = flag; 43 | this->initialized = false; 44 | } 45 | StringRef getPassName() const override { return StringRef("IndirectBranch"); } 46 | bool initialize(Module &M) { 47 | vector BBs; 48 | unsigned long long i = 0; 49 | for (auto F = M.begin(); F != M.end(); F++) { 50 | for (auto BB = F->begin(); BB != F->end(); BB++) { 51 | BasicBlock *BBPtr = &*BB; 52 | if (BBPtr != &(BBPtr->getParent()->getEntryBlock())) { 53 | indexmap[BBPtr] = i++; 54 | BBs.push_back(BlockAddress::get(BBPtr)); 55 | } 56 | } 57 | } 58 | ArrayType *AT = 59 | ArrayType::get(Type::getInt8PtrTy(M.getContext()), BBs.size()); 60 | Constant *BlockAddressArray = 61 | ConstantArray::get(AT, ArrayRef(BBs)); 62 | GlobalVariable *Table = new GlobalVariable( 63 | M, AT, false, GlobalValue::LinkageTypes::InternalLinkage, 64 | BlockAddressArray, "IndirectBranchingGlobalTable"); 65 | appendToCompilerUsed(M, {Table}); 66 | return true; 67 | } 68 | bool runOnFunction(Function &Func) override { 69 | if (!toObfuscate(flag, &Func, "indibr")) { 70 | return false; 71 | } 72 | if (this->initialized == false) { 73 | initialize(*Func.getParent()); 74 | this->initialized = true; 75 | } 76 | errs() << "Running IndirectBranch On " << Func.getName() << "\n"; 77 | vector BIs; 78 | for (inst_iterator I = inst_begin(Func); I != inst_end(Func); I++) { 79 | Instruction *Inst = &(*I); 80 | if (BranchInst *BI = dyn_cast(Inst)) { 81 | BIs.push_back(BI); 82 | } 83 | } // Finish collecting branching conditions 84 | Value *zero = 85 | ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), 0); 86 | for (BranchInst *BI : BIs) { 87 | IRBuilder<> IRB(BI); 88 | vector BBs; 89 | // We use the condition's evaluation result to generate the GEP 90 | // instruction False evaluates to 0 while true evaluates to 1. So here 91 | // we insert the false block first 92 | if (BI->isConditional()) { 93 | BBs.push_back(BI->getSuccessor(1)); 94 | } 95 | BBs.push_back(BI->getSuccessor(0)); 96 | ArrayType *AT = ArrayType::get( 97 | Type::getInt8PtrTy(Func.getParent()->getContext()), BBs.size()); 98 | vector BlockAddresses; 99 | for (unsigned i = 0; i < BBs.size(); i++) { 100 | BlockAddresses.push_back(BlockAddress::get(BBs[i])); 101 | } 102 | GlobalVariable *LoadFrom = NULL; 103 | 104 | if (BI->isConditional() || 105 | indexmap.find(BI->getSuccessor(0)) == indexmap.end()) { 106 | // Create a new GV 107 | Constant *BlockAddressArray = 108 | ConstantArray::get(AT, ArrayRef(BlockAddresses)); 109 | LoadFrom = new GlobalVariable( 110 | *Func.getParent(), AT, false, 111 | GlobalValue::LinkageTypes::PrivateLinkage, BlockAddressArray, 112 | "HikariConditionalLocalIndirectBranchingTable"); 113 | appendToCompilerUsed(*Func.getParent(), {LoadFrom}); 114 | } else { 115 | LoadFrom = Func.getParent()->getGlobalVariable( 116 | "IndirectBranchingGlobalTable", true); 117 | } 118 | Value *index = NULL; 119 | if (BI->isConditional()) { 120 | Value *condition = BI->getCondition(); 121 | index = IRB.CreateZExt( 122 | condition, Type::getInt32Ty(Func.getParent()->getContext())); 123 | } else { 124 | index = 125 | ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), 126 | indexmap[BI->getSuccessor(0)]); 127 | } 128 | #if LLVM_VERSION_MAJOR >= 13 129 | Value *GEP = IRB.CreateGEP(LoadFrom->getType()->getPointerElementType(), LoadFrom, {zero, index}); 130 | LoadInst *LI = IRB.CreateLoad(GEP->getType()->getPointerElementType(), GEP, "IndirectBranchingTargetAddress"); 131 | #else 132 | Value *GEP = IRB.CreateGEP(LoadFrom, {zero, index}); 133 | LoadInst *LI = IRB.CreateLoad(GEP, "IndirectBranchingTargetAddress"); 134 | #endif 135 | IndirectBrInst *indirBr = IndirectBrInst::Create(LI, BBs.size()); 136 | for (BasicBlock *BB : BBs) { 137 | indirBr->addDestination(BB); 138 | } 139 | ReplaceInstWithInst(BI, indirBr); 140 | } 141 | return true; 142 | } 143 | virtual bool doFinalization(Module &M) override { 144 | indexmap.clear(); 145 | initialized = false; 146 | return false; 147 | } 148 | }; 149 | } // namespace llvm 150 | FunctionPass *llvm::createIndirectBranchPass() { return new IndirectBranch(); } 151 | FunctionPass *llvm::createIndirectBranchPass(bool flag) { 152 | return new IndirectBranch(flag); 153 | } 154 | char IndirectBranch::ID = 0; 155 | INITIALIZE_PASS(IndirectBranch, "indibran", "IndirectBranching", true, true) 156 | 157 | #if LLVM_VERSION_MAJOR >= 13 158 | PreservedAnalyses IndirectBranchPass::run(Module &M, ModuleAnalysisManager& AM) { 159 | IndirectBranch IB; 160 | vector funcs; 161 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 162 | funcs.push_back(&*iter); 163 | } 164 | for (Function *F : funcs) { 165 | IB.runOnFunction(*F); 166 | } 167 | 168 | return PreservedAnalyses::all(); 169 | } 170 | #endif 171 | -------------------------------------------------------------------------------- /Hikari/LLVMBuild.txt: -------------------------------------------------------------------------------- 1 | ;===- ./lib/Transforms/Scalar/LLVMBuild.txt --------------------*- Conf -*--===; 2 | ; 3 | ; The LLVM Compiler Infrastructure 4 | ; 5 | ; This file is distributed under the University of Illinois Open Source 6 | ; License. See LICENSE.TXT for details. 7 | ; 8 | ;===------------------------------------------------------------------------===; 9 | ; 10 | ; This is an LLVMBuild description file for the components in this subdirectory. 11 | ; 12 | ; For more information on the LLVMBuild system, please see: 13 | ; 14 | ; http://llvm.org/docs/LLVMBuild.html 15 | ; 16 | ;===------------------------------------------------------------------------===; 17 | 18 | [component_0] 19 | type = Library 20 | name = Obfuscation 21 | parent = Transforms 22 | library_name = Obfuscation 23 | required_libraries = IRReader Linker 24 | -------------------------------------------------------------------------------- /Hikari/Obfuscation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Zhang(https://github.com/Naville/) 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published 6 | by the Free Software Foundation, either version 3 of the License, or 7 | any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Hikari 's own "Pass Scheduler". 19 | Because currently there is no way to add dependency to transform passes 20 | Ref : http://lists.llvm.org/pipermail/llvm-dev/2011-February/038109.html 21 | */ 22 | #include "Transforms/Obfuscation/Obfuscation.h" 23 | using namespace llvm; 24 | using namespace std; 25 | // Begin Obfuscator Options 26 | static cl::opt AesSeed("aesSeed", cl::init(""), 27 | cl::desc("seed for the AES-CTR PRNG")); 28 | static cl::opt EnableAntiClassDump("enable-acdobf", cl::init(false), 29 | cl::NotHidden, 30 | cl::desc("Enable AntiClassDump.")); 31 | static cl::opt 32 | EnableBogusControlFlow("enable-bcfobf", cl::init(false), cl::NotHidden, 33 | cl::desc("Enable BogusControlFlow.")); 34 | static cl::opt EnableFlattening("enable-cffobf", cl::init(false), 35 | cl::NotHidden, 36 | cl::desc("Enable Flattening.")); 37 | static cl::opt 38 | EnableBasicBlockSplit("enable-splitobf", cl::init(false), cl::NotHidden, 39 | cl::desc("Enable BasicBlockSpliting.")); 40 | static cl::opt 41 | EnableSubstitution("enable-subobf", cl::init(false), cl::NotHidden, 42 | cl::desc("Enable Instruction Substitution.")); 43 | static cl::opt EnableAllObfuscation("enable-allobf", cl::init(false), 44 | cl::NotHidden, 45 | cl::desc("Enable All Obfuscation.")); 46 | static cl::opt EnableFunctionCallObfuscate( 47 | "enable-fco", cl::init(false), cl::NotHidden, 48 | cl::desc("Enable Function CallSite Obfuscation.")); 49 | static cl::opt 50 | EnableStringEncryption("enable-strcry", cl::init(false), cl::NotHidden, 51 | cl::desc("Enable Function CallSite Obfuscation.")); 52 | static cl::opt 53 | EnableIndirectBranching("enable-indibran", cl::init(false), cl::NotHidden, 54 | cl::desc("Enable Indirect Branching.")); 55 | static cl::opt 56 | EnableFunctionWrapper("enable-funcwra", cl::init(false), cl::NotHidden, 57 | cl::desc("Enable Function Wrapper.")); 58 | // End Obfuscator Options 59 | namespace llvm { 60 | struct Obfuscation : public ModulePass { 61 | static char ID; 62 | Obfuscation() : ModulePass(ID) {} 63 | StringRef getPassName() const override { 64 | return StringRef("HikariObfuscationScheduler"); 65 | } 66 | bool runOnModule(Module &M) override { 67 | // Initial ACD Pass 68 | if (EnableAllObfuscation || EnableAntiClassDump) { 69 | ModulePass *P = createAntiClassDumpPass(); 70 | P->doInitialization(M); 71 | P->runOnModule(M); 72 | delete P; 73 | } 74 | // Now do FCO 75 | FunctionPass *FP = createFunctionCallObfuscatePass( 76 | EnableAllObfuscation || EnableFunctionCallObfuscate); 77 | FP->doInitialization(M); 78 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 79 | Function &F = *iter; 80 | if (!F.isDeclaration()) { 81 | FP->runOnFunction(F); 82 | } 83 | } 84 | delete FP; 85 | // Now Encrypt Strings 86 | ModulePass *MP = createStringEncryptionPass(EnableAllObfuscation || 87 | EnableStringEncryption); 88 | MP->runOnModule(M); 89 | delete MP; 90 | /* 91 | // Placing FW here does provide the most obfuscation however the compile 92 | time 93 | // and product size would be literally unbearable for any large project 94 | // Move it to post run 95 | if (EnableAllObfuscation || EnableFunctionWrapper) { 96 | ModulePass *P = createFunctionWrapperPass(); 97 | P->runOnModule(M); 98 | delete P; 99 | }*/ 100 | // Now perform Function-Level Obfuscation 101 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 102 | Function &F = *iter; 103 | if (!F.isDeclaration()) { 104 | FunctionPass *P = NULL; 105 | P = createSplitBasicBlockPass(EnableAllObfuscation || 106 | EnableBasicBlockSplit); 107 | P->runOnFunction(F); 108 | delete P; 109 | P = createBogusControlFlowPass(EnableAllObfuscation || 110 | EnableBogusControlFlow); 111 | P->runOnFunction(F); 112 | delete P; 113 | P = createFlatteningPass(EnableAllObfuscation || EnableFlattening); 114 | P->runOnFunction(F); 115 | delete P; 116 | P = createSubstitutionPass(EnableAllObfuscation || EnableSubstitution); 117 | P->runOnFunction(F); 118 | delete P; 119 | } 120 | } 121 | errs() << "Doing Post-Run Cleanup\n"; 122 | FunctionPass *P = createIndirectBranchPass(EnableAllObfuscation || 123 | EnableIndirectBranching); 124 | vector funcs; 125 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 126 | funcs.push_back(&*iter); 127 | } 128 | for (Function *F : funcs) { 129 | P->runOnFunction(*F); 130 | } 131 | delete P; 132 | MP = createFunctionWrapperPass(EnableAllObfuscation || 133 | EnableFunctionWrapper); 134 | MP->runOnModule(M); 135 | delete MP; 136 | // Cleanup Flags 137 | vector toDelete; 138 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 139 | Function &F = *iter; 140 | if (F.isDeclaration() && F.hasName() && 141 | F.getName().contains("hikari_")) { 142 | for (User *U : F.users()) { 143 | if (Instruction *Inst = dyn_cast(U)) { 144 | Inst->eraseFromParent(); 145 | } 146 | } 147 | toDelete.push_back(&F); 148 | } 149 | } 150 | for (Function *F : toDelete) { 151 | F->eraseFromParent(); 152 | } 153 | errs() << "Hikari Out\n"; 154 | return true; 155 | } // End runOnModule 156 | }; 157 | ModulePass *createObfuscationPass() { 158 | if (!AesSeed.empty()) { 159 | llvm::cryptoutils->prng_seed(AesSeed.c_str()); 160 | } 161 | return new Obfuscation(); 162 | } 163 | } // namespace llvm 164 | char Obfuscation::ID = 0; 165 | INITIALIZE_PASS_BEGIN(Obfuscation, "obfus", "Enable Obfuscation", true, true) 166 | INITIALIZE_PASS_DEPENDENCY(AntiClassDump); 167 | INITIALIZE_PASS_DEPENDENCY(BogusControlFlow); 168 | INITIALIZE_PASS_DEPENDENCY(Flattening); 169 | INITIALIZE_PASS_DEPENDENCY(FunctionCallObfuscate); 170 | INITIALIZE_PASS_DEPENDENCY(IndirectBranch); 171 | INITIALIZE_PASS_DEPENDENCY(SplitBasicBlock); 172 | INITIALIZE_PASS_DEPENDENCY(StringEncryption); 173 | INITIALIZE_PASS_DEPENDENCY(Substitution); 174 | INITIALIZE_PASS_END(Obfuscation, "obfus", "Enable Obfuscation", true, true) 175 | -------------------------------------------------------------------------------- /Hikari/SplitBasicBlocks.cpp: -------------------------------------------------------------------------------- 1 | //===- SplitBasicBlock.cpp - SplitBasicBlokc Obfuscation pass--------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file implements the split basic block pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "Transforms/Obfuscation/CryptoUtils.h" 15 | #include "Transforms/Obfuscation/Split.h" 16 | #include "Transforms/Obfuscation/Utils.h" 17 | 18 | #define DEBUG_TYPE "split" 19 | 20 | using namespace llvm; 21 | using namespace std; 22 | 23 | // Stats 24 | STATISTIC(Split, "Basicblock splitted"); 25 | 26 | static cl::opt SplitNum("split_num", cl::init(2), 27 | cl::desc("Split time each BB")); 28 | 29 | namespace { 30 | struct SplitBasicBlock : public FunctionPass { 31 | static char ID; // Pass identification, replacement for typeid 32 | bool flag; 33 | SplitBasicBlock() : FunctionPass(ID) { this->flag = true; } 34 | SplitBasicBlock(bool flag) : FunctionPass(ID) { this->flag = flag; } 35 | 36 | bool runOnFunction(Function &F); 37 | void split(Function *f); 38 | 39 | bool containsPHI(BasicBlock *b); 40 | void shuffle(std::vector &vec); 41 | }; 42 | } // namespace 43 | 44 | char SplitBasicBlock::ID = 0; 45 | INITIALIZE_PASS(SplitBasicBlock, "splitobf", "Enable BasicBlockSpliting.", true, 46 | true) 47 | FunctionPass *llvm::createSplitBasicBlockPass() { 48 | return new SplitBasicBlock(); 49 | } 50 | FunctionPass *llvm::createSplitBasicBlockPass(bool flag) { 51 | return new SplitBasicBlock(flag); 52 | } 53 | 54 | bool SplitBasicBlock::runOnFunction(Function &F) { 55 | // Check if the number of applications is correct 56 | if (!((SplitNum > 1) && (SplitNum <= 10))) { 57 | errs() << "Split application basic block percentage\ 58 | -split_num=x must be 1 < x <= 10"; 59 | return false; 60 | } 61 | 62 | Function *tmp = &F; 63 | 64 | // Do we obfuscate 65 | if (toObfuscate(flag, tmp, "split")) { 66 | errs() << "Running BasicBlockSplit On " << tmp->getName() << "\n"; 67 | split(tmp); 68 | ++Split; 69 | } 70 | 71 | return false; 72 | } 73 | 74 | void SplitBasicBlock::split(Function *f) { 75 | std::vector origBB; 76 | int splitN = SplitNum; 77 | 78 | // Save all basic blocks 79 | for (Function::iterator I = f->begin(), IE = f->end(); I != IE; ++I) { 80 | origBB.push_back(&*I); 81 | } 82 | 83 | for (std::vector::iterator I = origBB.begin(), 84 | IE = origBB.end(); 85 | I != IE; ++I) { 86 | BasicBlock *curr = *I; 87 | 88 | // No need to split a 1 inst bb 89 | // Or ones containing a PHI node 90 | if (curr->size() < 2 || containsPHI(curr)) { 91 | continue; 92 | } 93 | 94 | // Check splitN and current BB size 95 | if ((size_t)splitN > curr->size()) { 96 | splitN = curr->size() - 1; 97 | } 98 | 99 | // Generate splits point 100 | std::vector test; 101 | for (unsigned i = 1; i < curr->size(); ++i) { 102 | test.push_back(i); 103 | } 104 | 105 | // Shuffle 106 | if (test.size() != 1) { 107 | shuffle(test); 108 | std::sort(test.begin(), test.begin() + splitN); 109 | } 110 | 111 | // Split 112 | BasicBlock::iterator it = curr->begin(); 113 | BasicBlock *toSplit = curr; 114 | int last = 0; 115 | for (int i = 0; i < splitN; ++i) { 116 | for (int j = 0; j < test[i] - last; ++j) { 117 | ++it; 118 | } 119 | last = test[i]; 120 | if (toSplit->size() < 2) 121 | continue; 122 | toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split"); 123 | } 124 | 125 | ++Split; 126 | } 127 | } 128 | 129 | bool SplitBasicBlock::containsPHI(BasicBlock *b) { 130 | for (BasicBlock::iterator I = b->begin(), IE = b->end(); I != IE; ++I) { 131 | if (isa(I)) { 132 | return true; 133 | } 134 | } 135 | return false; 136 | } 137 | 138 | void SplitBasicBlock::shuffle(std::vector &vec) { 139 | int n = vec.size(); 140 | for (int i = n - 1; i > 0; --i) { 141 | std::swap(vec[i], vec[cryptoutils->get_uint32_t() % (i + 1)]); 142 | } 143 | } 144 | 145 | #if LLVM_VERSION_MAJOR >= 13 146 | PreservedAnalyses SplitBasicBlockPass::run(Function& F, FunctionAnalysisManager& AM) { 147 | SplitBasicBlock SBB; 148 | SBB.runOnFunction(F); 149 | 150 | return PreservedAnalyses::all(); 151 | } 152 | #endif 153 | -------------------------------------------------------------------------------- /Hikari/StringEncryption.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * LLVM StringEncryption Pass 3 | Copyright (C) 2017 Zhang(https://github.com/Naville/) 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published 7 | by the Free Software Foundation, either version 3 of the License, or 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "Transforms/Obfuscation/StringEncryption.h" 19 | #include "llvm/IR/Constants.h" 20 | #include "llvm/IR/IRBuilder.h" 21 | #include "llvm/IR/Instructions.h" 22 | #include "llvm/IR/LegacyPassManager.h" 23 | #include "llvm/IR/Module.h" 24 | #include "llvm/IR/Value.h" 25 | #include "llvm/Pass.h" 26 | #include "llvm/Support/CommandLine.h" 27 | #include "llvm/Support/TargetSelect.h" 28 | #include "llvm/Support/raw_ostream.h" 29 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 30 | #include "Transforms/Obfuscation/CryptoUtils.h" 31 | #include "Transforms/Obfuscation/Obfuscation.h" 32 | #include "Transforms/Obfuscation/Utils.h" 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | using namespace llvm; 39 | using namespace std; 40 | namespace llvm { 41 | struct StringEncryption : public ModulePass { 42 | static char ID; 43 | map 44 | encstatus; 45 | bool flag; 46 | StringEncryption() : ModulePass(ID) { this->flag = true; } 47 | StringEncryption(bool flag) : ModulePass(ID) { this->flag = flag; } 48 | StringRef getPassName() const override { 49 | return StringRef("StringEncryption"); 50 | } 51 | bool runOnModule(Module &M) override { 52 | // in runOnModule. We simple iterate function list and dispatch functions 53 | // to handlers 54 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 55 | Function *F = &(*iter); 56 | 57 | if (toObfuscate(flag, F, "strenc")) { 58 | errs() << "Running StringEncryption On " << F->getName() << "\n"; 59 | Constant *S = ConstantInt::get(Type::getInt32Ty(M.getContext()), 0); 60 | GlobalVariable *GV = new GlobalVariable( 61 | M, S->getType(), false, GlobalValue::LinkageTypes::PrivateLinkage, 62 | S, ""); 63 | encstatus[F] = GV; 64 | HandleFunction(F); 65 | } 66 | } 67 | return true; 68 | } // End runOnModule 69 | void HandleFunction(Function *Func) { 70 | /* 71 | - Split Original EntryPoint BB into A and C. 72 | - Create new BB as Decryption BB between A and C. Adjust the terminators 73 | into: A (Alloca a new array containing all) 74 | | 75 | B(If not decrypted) 76 | | 77 | C 78 | */ 79 | FixFunctionConstantExpr(Func); 80 | BasicBlock *A = &(Func->getEntryBlock()); 81 | BasicBlock *C = A->splitBasicBlock(A->getFirstNonPHIOrDbgOrLifetime()); 82 | C->setName("PrecedingBlock"); 83 | BasicBlock *B = 84 | BasicBlock::Create(Func->getContext(), "StringDecryptionBB", Func, C); 85 | // Change A's terminator to jump to B 86 | // We'll add new terminator to jump C later 87 | BranchInst *newBr = BranchInst::Create(B); 88 | ReplaceInstWithInst(A->getTerminator(), newBr); 89 | set Globals; 90 | set Users; 91 | for (BasicBlock &BB : *Func) { 92 | for (Instruction &I : BB) { 93 | for (Value *Op : I.operands()) { 94 | if (GlobalVariable *G = dyn_cast(Op->stripPointerCasts())) { 95 | if(User* U=dyn_cast(Op)){ 96 | Users.insert(U); 97 | } 98 | Users.insert(&I); 99 | Globals.insert(G); 100 | } 101 | } 102 | } 103 | } 104 | IRBuilder<> IRB(A->getFirstNonPHIOrDbgOrLifetime()); 105 | set rawStrings; 106 | set objCStrings; 107 | map GV2Keys; 108 | map old2new; 109 | for (GlobalVariable *GV : Globals) { 110 | if (GV->hasInitializer() && 111 | GV->getSection() != StringRef("llvm.metadata") && 112 | GV->getSection().find(StringRef("__objc")) == string::npos && 113 | GV->getName().find("OBJC") == string::npos) { 114 | if (GV->getInitializer()->getType() == 115 | #if LLVM_VERSION_MAJOR >= 13 116 | StructType::getTypeByName(Func->getParent()->getContext(), "struct.__NSConstantString_tag")) { 117 | #else 118 | Func->getParent()->getTypeByName("struct.__NSConstantString_tag")) { 119 | #endif 120 | objCStrings.insert(GV); 121 | rawStrings.insert( 122 | cast(cast(GV->getInitializer()) 123 | ->getOperand(2) 124 | ->stripPointerCasts())); 125 | 126 | } else if (isa(GV->getInitializer())) { 127 | rawStrings.insert(GV); 128 | }else if(isa(GV->getInitializer())){ 129 | ConstantArray* CA=cast(GV->getInitializer()); 130 | for(unsigned i=0;igetNumOperands();i++){ 131 | Value* op=CA->getOperand(i)->stripPointerCasts(); 132 | if(GlobalVariable* GV=dyn_cast(op)){ 133 | Globals.insert(GV); 134 | } 135 | } 136 | 137 | } 138 | } 139 | } 140 | for (GlobalVariable *GV : rawStrings) { 141 | if (GV->getInitializer()->isZeroValue() || 142 | GV->getInitializer()->isNullValue()) { 143 | continue; 144 | } 145 | ConstantDataSequential *CDS = 146 | cast(GV->getInitializer()); 147 | Type *memberType = CDS->getElementType(); 148 | // Ignore non-IntegerType 149 | if (!isa(memberType)) { 150 | continue; 151 | } 152 | IntegerType *intType = cast(memberType); 153 | Constant *KeyConst = NULL; 154 | Constant *EncryptedConst = NULL; 155 | if (intType == Type::getInt8Ty(GV->getParent()->getContext())) { 156 | vector keys; 157 | vector encry; 158 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 159 | uint8_t K = cryptoutils->get_uint8_t(); 160 | uint64_t V = CDS->getElementAsInteger(i); 161 | keys.push_back(K); 162 | encry.push_back(K ^ V); 163 | } 164 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 165 | ArrayRef(keys)); 166 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 167 | ArrayRef(encry)); 168 | } else if (intType == Type::getInt16Ty(GV->getParent()->getContext())) { 169 | vector keys; 170 | vector encry; 171 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 172 | uint16_t K = cryptoutils->get_uint16_t(); 173 | uint64_t V = CDS->getElementAsInteger(i); 174 | keys.push_back(K); 175 | encry.push_back(K ^ V); 176 | } 177 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 178 | ArrayRef(keys)); 179 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 180 | ArrayRef(encry)); 181 | } else if (intType == Type::getInt32Ty(GV->getParent()->getContext())) { 182 | vector keys; 183 | vector encry; 184 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 185 | uint32_t K = cryptoutils->get_uint32_t(); 186 | uint64_t V = CDS->getElementAsInteger(i); 187 | keys.push_back(K); 188 | encry.push_back(K ^ V); 189 | } 190 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 191 | ArrayRef(keys)); 192 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 193 | ArrayRef(encry)); 194 | } else if (intType == Type::getInt64Ty(GV->getParent()->getContext())) { 195 | vector keys; 196 | vector encry; 197 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 198 | uint64_t K = cryptoutils->get_uint64_t(); 199 | uint64_t V = CDS->getElementAsInteger(i); 200 | keys.push_back(K); 201 | encry.push_back(K ^ V); 202 | } 203 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 204 | ArrayRef(keys)); 205 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 206 | ArrayRef(encry)); 207 | } else { 208 | errs() << "Unsupported CDS Type\n"; 209 | abort(); 210 | } 211 | // Prepare new rawGV 212 | GlobalVariable *EncryptedRawGV = new GlobalVariable( 213 | *(GV->getParent()), EncryptedConst->getType(), false, 214 | GV->getLinkage(), EncryptedConst, "EncryptedString", nullptr, 215 | GV->getThreadLocalMode(), GV->getType()->getAddressSpace()); 216 | old2new[GV] = EncryptedRawGV; 217 | GV2Keys[EncryptedRawGV] = KeyConst; 218 | } 219 | // Now prepare ObjC new GV 220 | for (GlobalVariable *GV : objCStrings) { 221 | Value *zero = ConstantInt::get(Type::getInt32Ty(GV->getContext()), 0); 222 | ConstantStruct *CS = cast(GV->getInitializer()); 223 | vector vals; 224 | vals.push_back(CS->getOperand(0)); 225 | vals.push_back(CS->getOperand(1)); 226 | GlobalVariable *oldrawString = 227 | cast(CS->getOperand(2)->stripPointerCasts()); 228 | if (old2new.find(oldrawString) == 229 | old2new.end()) { // Filter out zero initializers 230 | continue; 231 | } 232 | Constant *GEPed = ConstantExpr::getInBoundsGetElementPtr( 233 | nullptr, old2new[oldrawString], {zero, zero}); 234 | if (GEPed->getType() == CS->getOperand(2)->getType()) { 235 | vals.push_back(GEPed); 236 | } else { 237 | Constant *BitCasted = ConstantExpr::getBitCast( 238 | old2new[oldrawString], CS->getOperand(2)->getType()); 239 | vals.push_back(BitCasted); 240 | } 241 | vals.push_back(CS->getOperand(3)); 242 | Constant *newCS = 243 | ConstantStruct::get(CS->getType(), ArrayRef(vals)); 244 | GlobalVariable *EncryptedOCGV = new GlobalVariable( 245 | *(GV->getParent()), newCS->getType(), false, GV->getLinkage(), newCS, 246 | "EncryptedObjCString", nullptr, GV->getThreadLocalMode(), 247 | GV->getType()->getAddressSpace()); 248 | old2new[GV] = EncryptedOCGV; 249 | } // End prepare ObjC new GV 250 | // Replace Uses 251 | for (User *U : Users) { 252 | for (map::iterator iter = 253 | old2new.begin(); 254 | iter != old2new.end(); ++iter) { 255 | U->replaceUsesOfWith(iter->first, iter->second); 256 | iter->first->removeDeadConstantUsers(); 257 | } 258 | } // End Replace Uses 259 | // CleanUp Old ObjC GVs 260 | for (GlobalVariable *GV : objCStrings) { 261 | if (GV->getNumUses() == 0) { 262 | GV->dropAllReferences(); 263 | old2new.erase(GV); 264 | GV->eraseFromParent(); 265 | } 266 | } 267 | // CleanUp Old Raw GVs 268 | for (map::iterator iter = 269 | old2new.begin(); 270 | iter != old2new.end(); ++iter) { 271 | GlobalVariable *toDelete = iter->first; 272 | toDelete->removeDeadConstantUsers(); 273 | if (toDelete->getNumUses() == 0) { 274 | toDelete->dropAllReferences(); 275 | toDelete->eraseFromParent(); 276 | } 277 | } 278 | GlobalVariable *StatusGV = encstatus[Func]; 279 | // Insert DecryptionCode 280 | HandleDecryptionBlock(B, C, GV2Keys); 281 | // Add atomic load checking status in A 282 | #if LLVM_VERSION_MAJOR >= 13 283 | LoadInst *LI = IRB.CreateLoad(StatusGV->getType()->getPointerElementType(), StatusGV, "LoadEncryptionStatus"); 284 | #else 285 | LoadInst *LI = IRB.CreateLoad(StatusGV, "LoadEncryptionStatus"); 286 | #endif 287 | LI->setAtomic(AtomicOrdering::Acquire); // Will be released at the start of 288 | // C 289 | #if LLVM_VERSION_MAJOR >= 10 290 | LI->setAlignment(llvm::Align(4)); 291 | #else 292 | LI->setAlignment(4); 293 | #endif 294 | 295 | Value *condition = IRB.CreateICmpEQ( 296 | LI, ConstantInt::get(Type::getInt32Ty(Func->getContext()), 0)); 297 | A->getTerminator()->eraseFromParent(); 298 | BranchInst::Create(B, C, condition, A); 299 | // Add StoreInst atomically in C start 300 | // No matter control flow is coming from A or B, the GVs must be decrypted 301 | IRBuilder<> IRBC(C->getFirstNonPHIOrDbgOrLifetime()); 302 | StoreInst *SI = IRBC.CreateStore( 303 | ConstantInt::get(Type::getInt32Ty(Func->getContext()), 1), StatusGV); 304 | #if LLVM_VERSION_MAJOR >= 10 305 | SI->setAlignment(llvm::Align(4)); 306 | #else 307 | SI->setAlignment(4); 308 | #endif 309 | 310 | SI->setAtomic(AtomicOrdering::Release); // Release the lock acquired in LI 311 | 312 | } // End of HandleFunction 313 | void HandleDecryptionBlock(BasicBlock *B, BasicBlock *C, 314 | map &GV2Keys) { 315 | IRBuilder<> IRB(B); 316 | Value *zero = ConstantInt::get(Type::getInt32Ty(B->getContext()), 0); 317 | for (map::iterator iter = GV2Keys.begin(); 318 | iter != GV2Keys.end(); ++iter) { 319 | ConstantDataArray *CastedCDA = cast(iter->second); 320 | // Element-By-Element XOR so the fucking verifier won't complain 321 | // Also, this hides keys 322 | for (unsigned i = 0; i < CastedCDA->getType()->getNumElements(); i++) { 323 | Value *offset = ConstantInt::get(Type::getInt32Ty(B->getContext()), i); 324 | #if LLVM_VERSION_MAJOR >= 13 325 | Value *GEP = IRB.CreateGEP(iter->first->getType()->getPointerElementType(), iter->first, {zero, offset}); 326 | LoadInst *LI = IRB.CreateLoad(GEP->getType()->getPointerElementType(), GEP, "EncryptedChar"); 327 | #else 328 | Value *GEP = IRB.CreateGEP(iter->first, {zero, offset}); 329 | LoadInst *LI = IRB.CreateLoad(GEP, "EncryptedChar"); 330 | #endif 331 | Value *XORed = IRB.CreateXor(LI, CastedCDA->getElementAsConstant(i)); 332 | IRB.CreateStore(XORed, GEP); 333 | } 334 | } 335 | IRB.CreateBr(C); 336 | } // End of HandleDecryptionBlock 337 | bool doFinalization(Module &M) override { 338 | encstatus.clear(); 339 | return false; 340 | } 341 | }; 342 | ModulePass *createStringEncryptionPass() { return new StringEncryption(); } 343 | ModulePass *createStringEncryptionPass(bool flag) { 344 | return new StringEncryption(flag); 345 | } 346 | } // namespace llvm 347 | 348 | char StringEncryption::ID = 0; 349 | INITIALIZE_PASS(StringEncryption, "strcry", "Enable String Encryption", true, 350 | true) 351 | 352 | #if LLVM_VERSION_MAJOR >= 13 353 | PreservedAnalyses StringEncryptionPass::run(Module &M, ModuleAnalysisManager& AM) { 354 | StringEncryption SE; 355 | SE.runOnModule(M); 356 | 357 | return PreservedAnalyses::all(); 358 | } 359 | #endif 360 | -------------------------------------------------------------------------------- /Hikari/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Transforms/Obfuscation/Utils.h" 2 | #include "llvm/IR/IRBuilder.h" 3 | #include "llvm/IR/InstIterator.h" 4 | #include "llvm/IR/Module.h" 5 | #include "llvm/Support/raw_ostream.h" 6 | #include "llvm/IR/IRBuilder.h" 7 | #include "llvm/IR/NoFolder.h" 8 | // Shamefully borrowed from ../Scalar/RegToMem.cpp :( 9 | bool valueEscapes(Instruction *Inst) { 10 | BasicBlock *BB = Inst->getParent(); 11 | for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; 12 | ++UI) { 13 | Instruction *I = cast(*UI); 14 | if (I->getParent() != BB || isa(I)) { 15 | return true; 16 | } 17 | } 18 | return false; 19 | } 20 | void appendToAnnotations(Module &M, ConstantStruct *Data) { 21 | // Type for the annotation array 22 | // { i8*, i8*, i8*, i32 } 23 | GlobalVariable *AnnotationGV = M.getGlobalVariable("llvm.global.annotations"); 24 | Type *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); 25 | Type *Int32Ty = Type::getInt32Ty(M.getContext()); 26 | if (AnnotationGV == nullptr) { 27 | ArrayType *AT = ArrayType::get(Data->getType(), 1); 28 | ConstantArray *CA = cast(ConstantArray::get(AT, {Data})); 29 | GlobalVariable *newGV = new GlobalVariable(M, CA->getType(), false, 30 | GlobalValue::AppendingLinkage, 31 | CA, "llvm.global.annotations"); 32 | newGV->setSection("llvm.metadata"); 33 | return; 34 | } else { 35 | StructType *ST = StructType::get( 36 | M.getContext(), {Int8PtrTy, Int8PtrTy, Int8PtrTy, Int32Ty}); 37 | vector exists; 38 | for (unsigned i = 0; 39 | i < cast(AnnotationGV->getInitializer()->getType()) 40 | ->getNumElements(); 41 | i++) { 42 | exists.push_back(AnnotationGV->getInitializer()->getAggregateElement(i)); 43 | } 44 | exists.push_back(Data); 45 | ArrayType *AT = ArrayType::get(ST, exists.size()); 46 | ConstantArray *CA = cast( 47 | ConstantArray::get(AT, ArrayRef(exists))); 48 | GlobalVariable *newGV = new GlobalVariable(M, CA->getType(), false, 49 | GlobalValue::AppendingLinkage, 50 | CA, "llvm.global.annotations"); 51 | newGV->setSection("llvm.metadata"); 52 | return; 53 | } 54 | } 55 | void FixFunctionConstantExpr(Function *Func) { 56 | // Replace ConstantExpr with equal instructions 57 | // Otherwise replacing on Constant will crash the compiler 58 | for (BasicBlock &BB : *Func) { 59 | FixBasicBlockConstantExpr(&BB); 60 | } 61 | } 62 | void FixBasicBlockConstantExpr(BasicBlock *BB) { 63 | // Replace ConstantExpr with equal instructions 64 | // Otherwise replacing on Constant will crash the compiler 65 | // Things to note: 66 | // - Phis must be placed at BB start so CEs must be placed prior to current BB 67 | assert(!BB->empty()&&"BasicBlock is empty!"); 68 | assert((BB->getParent()!=NULL)&&"BasicBlock must be in a Function!"); 69 | Instruction* FunctionInsertPt=&*(BB->getParent()->getEntryBlock().getFirstInsertionPt()); 70 | //Instruction* LocalBBInsertPt=&*(BB.getFirstInsertionPt()); 71 | 72 | for (Instruction &I : *BB) { 73 | if(isa(I)||isa(I)){ 74 | continue; 75 | } 76 | for(unsigned i=0;i(I.getOperand(i))){ 78 | Instruction* InsertPt=&I; 79 | IRBuilder IRB(InsertPt); 80 | if(isa(I)){ 81 | IRB.SetInsertPoint(FunctionInsertPt); 82 | } 83 | Instruction *Inst = IRB.Insert(C->getAsInstruction()); 84 | I.setOperand(i,Inst); 85 | } 86 | } 87 | } 88 | } 89 | 90 | 91 | map BuildAnnotateMap(Module &M) { 92 | map VAMap; 93 | GlobalVariable *glob = M.getGlobalVariable("llvm.global.annotations"); 94 | if (glob != nullptr && glob->hasInitializer()) { 95 | ConstantArray *CDA = cast(glob->getInitializer()); 96 | for (Value *op : CDA->operands()) { 97 | ConstantStruct *anStruct = cast(op); 98 | /* 99 | Structure: [Value,Annotation,SourceFilePath,LineNumber] 100 | Usually wrapped inside GEP/BitCast 101 | We only care about Value and Annotation Here 102 | */ 103 | GlobalValue *Value = 104 | cast(anStruct->getOperand(0)->getOperand(0)); 105 | GlobalVariable *Annotation = 106 | cast(anStruct->getOperand(1)->getOperand(0)); 107 | if (Annotation->hasInitializer()) { 108 | VAMap[Value] = 109 | cast(Annotation->getInitializer()) 110 | ->getAsCString(); 111 | } 112 | } 113 | } 114 | return VAMap; 115 | } 116 | 117 | void fixStack(Function *f) { 118 | // Try to remove phi node and demote reg to stack 119 | std::vector tmpPhi; 120 | std::vector tmpReg; 121 | BasicBlock *bbEntry = &*f->begin(); 122 | 123 | do { 124 | tmpPhi.clear(); 125 | tmpReg.clear(); 126 | 127 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 128 | 129 | for (BasicBlock::iterator j = i->begin(); j != i->end(); ++j) { 130 | 131 | if (isa(j)) { 132 | PHINode *phi = cast(j); 133 | tmpPhi.push_back(phi); 134 | continue; 135 | } 136 | if (!(isa(j) && j->getParent() == bbEntry) && 137 | (valueEscapes(&*j) || j->isUsedOutsideOfBlock(&*i))) { 138 | tmpReg.push_back(&*j); 139 | continue; 140 | } 141 | } 142 | } 143 | for (unsigned int i = 0; i != tmpReg.size(); ++i) { 144 | DemoteRegToStack(*tmpReg.at(i), f->begin()->getTerminator()); 145 | } 146 | 147 | for (unsigned int i = 0; i != tmpPhi.size(); ++i) { 148 | DemotePHIToStack(tmpPhi.at(i), f->begin()->getTerminator()); 149 | } 150 | 151 | } while (tmpReg.size() != 0 || tmpPhi.size() != 0); 152 | } 153 | 154 | std::string readAnnotate(Function *f) { 155 | std::string annotation = ""; 156 | 157 | // Get annotation variable 158 | GlobalVariable *glob = 159 | f->getParent()->getGlobalVariable("llvm.global.annotations"); 160 | 161 | if (glob != NULL) { 162 | // Get the array 163 | if (ConstantArray *ca = dyn_cast(glob->getInitializer())) { 164 | for (unsigned i = 0; i < ca->getNumOperands(); ++i) { 165 | // Get the struct 166 | if (ConstantStruct *structAn = 167 | dyn_cast(ca->getOperand(i))) { 168 | if (ConstantExpr *expr = 169 | dyn_cast(structAn->getOperand(0))) { 170 | // If it's a bitcast we can check if the annotation is concerning 171 | // the current function 172 | if (expr->getOpcode() == Instruction::BitCast && 173 | expr->getOperand(0) == f) { 174 | ConstantExpr *note = cast(structAn->getOperand(1)); 175 | // If it's a GetElementPtr, that means we found the variable 176 | // containing the annotations 177 | if (note->getOpcode() == Instruction::GetElementPtr) { 178 | if (GlobalVariable *annoteStr = 179 | dyn_cast(note->getOperand(0))) { 180 | if (ConstantDataSequential *data = 181 | dyn_cast( 182 | annoteStr->getInitializer())) { 183 | if (data->isString()) { 184 | annotation += data->getAsString().lower() + " "; 185 | } 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | } 195 | return annotation; 196 | } 197 | 198 | // Unlike O-LLVM which uses __attribute__ that is not supported by the ObjC CFE. 199 | // We use a dummy call here and remove the call later 200 | // Very dumb and definitely slower than the function attribute method 201 | // Merely a hack 202 | bool readFlag(Function *f, std::string attribute) { 203 | for (inst_iterator I = inst_begin(f); I != inst_end(f); I++) { 204 | Instruction *Inst = &*I; 205 | if (CallInst *CI = dyn_cast(Inst)) { 206 | if (CI->getCalledFunction() != nullptr && 207 | CI->getCalledFunction()->getName().contains("hikari_" + attribute)) { 208 | CI->eraseFromParent(); 209 | return true; 210 | } 211 | } 212 | } 213 | return false; 214 | } 215 | bool toObfuscate(bool flag, Function *f, std::string attribute) { 216 | 217 | // Check if declaration 218 | if (f->isDeclaration()) { 219 | return false; 220 | } 221 | // Check external linkage 222 | if (f->hasAvailableExternallyLinkage() != 0) { 223 | return false; 224 | } 225 | std::string attr = attribute; 226 | std::string attrNo = "no" + attr; 227 | // We have to check the nofla flag first 228 | // Because .find("fla") is true for a string like "fla" or 229 | // "nofla" 230 | if (readAnnotate(f).find(attrNo) != std::string::npos || 231 | readFlag(f, attrNo)) { 232 | return false; 233 | } 234 | if (readAnnotate(f).find(attr) != std::string::npos || readFlag(f, attr)) { 235 | return true; 236 | } 237 | if (flag == true) { 238 | return true; 239 | } 240 | return false; 241 | } 242 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/AntiClassDump.h: -------------------------------------------------------------------------------- 1 | #ifndef _ANTI_CLASSDUMP_H_ 2 | #define _ANTI_CLASSDUMP_H_ 3 | #include "llvm/Pass.h" 4 | #include "llvm/IR/LegacyPassManager.h" 5 | #if LLVM_VERSION_MAJOR >= 13 6 | #include "llvm/Passes/PassBuilder.h" 7 | #endif 8 | using namespace std; 9 | using namespace llvm; 10 | 11 | // Namespace 12 | namespace llvm { 13 | ModulePass* createAntiClassDumpPass(); 14 | void initializeAntiClassDumpPass(PassRegistry &Registry); 15 | #if LLVM_VERSION_MAJOR >= 13 16 | class AntiClassDumpPass : public PassInfoMixin{ 17 | public: 18 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 19 | static bool isRequired() { return true; } 20 | }; 21 | #endif 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/BogusControlFlow.h: -------------------------------------------------------------------------------- 1 | //===- BogusControlFlow.h - BogusControlFlow Obfuscation pass-------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===--------------------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the bogusControlFlow pass 11 | // 12 | //===--------------------------------------------------------------------------------===// 13 | 14 | #ifndef _BOGUSCONTROLFLOW_H_ 15 | #define _BOGUSCONTROLFLOW_H_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Module.h" 21 | #include "llvm/IR/Function.h" 22 | #include "llvm/IR/BasicBlock.h" 23 | #include "llvm/IR/Instructions.h" 24 | #include "llvm/IR/InstrTypes.h" 25 | #include "llvm/IR/Constants.h" 26 | #include "llvm/IR/Type.h" 27 | #include "llvm/ADT/Statistic.h" 28 | #include "llvm/IR/GlobalValue.h" 29 | #include "llvm/IR/LLVMContext.h" 30 | #include "llvm/Transforms/Utils/Cloning.h" 31 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 32 | #include "llvm/CodeGen/ISDOpcodes.h" 33 | #include "llvm/Support/raw_ostream.h" 34 | #include "llvm/Support/Debug.h" 35 | #include "llvm/Support/CommandLine.h" 36 | #include "llvm/Transforms/IPO.h" 37 | #include "Transforms/Obfuscation/CryptoUtils.h" 38 | #include 39 | 40 | using namespace std; 41 | using namespace llvm; 42 | 43 | // Namespace 44 | namespace llvm { 45 | FunctionPass *createBogusControlFlowPass(); 46 | FunctionPass *createBogusControlFlowPass(bool flag); 47 | void initializeBogusControlFlowPass(PassRegistry &Registry); 48 | #if LLVM_VERSION_MAJOR >= 13 49 | class BogusControlFlowPass : public PassInfoMixin{ 50 | public: 51 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 52 | static bool isRequired() { return true; } 53 | }; 54 | #endif 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/CryptoUtils.h: -------------------------------------------------------------------------------- 1 | //===- CryptoUtils.h - Cryptographically Secure Pseudo-Random 2 | // Generator------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | // 11 | // This file contains includes and defines for the AES CTR PRNG 12 | // The AES implementation has been derived and adapted 13 | // from libtomcrypt (see http://libtom.org) 14 | // Created on: 22 juin 2012 15 | // Author(s): jrinaldini, pjunod 16 | //===----------------------------------------------------------------------===// 17 | 18 | #ifndef LLVM_CryptoUtils_H 19 | #define LLVM_CryptoUtils_H 20 | 21 | #include "llvm/Support/ManagedStatic.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace llvm { 28 | 29 | class CryptoUtils; 30 | extern ManagedStatic cryptoutils; 31 | 32 | #define BYTE(x, n) (((x) >> (8 * (n))) & 0xFF) 33 | 34 | #if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 35 | defined(INTEL_CC) 36 | 37 | #ifndef ENDIAN_LITTLE 38 | #define ENDIAN_LITTLE 39 | #endif 40 | #define ENDIAN_32BITWORD 41 | #define UNALIGNED 42 | 43 | #elif defined(__alpha) 44 | 45 | #ifndef ENDIAN_LITTLE 46 | #define ENDIAN_LITTLE 47 | #endif 48 | #define ENDIAN_64BITWORD 49 | 50 | #elif defined(__x86_64__) 51 | 52 | #ifndef ENDIAN_LITTLE 53 | #define ENDIAN_LITTLE 54 | #endif 55 | #define ENDIAN_64BITWORD 56 | #define UNALIGNED 57 | 58 | #elif(defined(__R5900) || defined(R5900) || defined(__R5900__)) && \ 59 | (defined(_mips) || defined(__mips__) || defined(mips)) 60 | 61 | #ifndef ENDIAN_LITTLE 62 | #define ENDIAN_LITTLE 63 | #endif 64 | #define ENDIAN_64BITWORD 65 | 66 | #elif defined(__sparc) 67 | 68 | #ifndef ENDIAN_BIG 69 | #define ENDIAN_BIG 70 | #endif 71 | #if defined(__arch64__) 72 | #define ENDIAN_64BITWORD 73 | #else 74 | #define ENDIAN_32BITWORD 75 | #endif 76 | 77 | #endif 78 | 79 | #if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) 80 | #define ENDIAN_BIG 81 | #endif 82 | 83 | #if !defined(ENDIAN_BIG) && !defined(ENDIAN_LITTLE) 84 | #error \ 85 | "Unknown endianness of the compilation platform, check this header aes_encrypt.h" 86 | #endif 87 | 88 | #ifdef ENDIAN_LITTLE 89 | 90 | #define STORE32H(y, x) \ 91 | { \ 92 | (y)[0] = (uint8_t)(((x) >> 24) & 0xFF); \ 93 | (y)[1] = (uint8_t)(((x) >> 16) & 0xFF); \ 94 | (y)[2] = (uint8_t)(((x) >> 8) & 0xFF); \ 95 | (y)[3] = (uint8_t)(((x) >> 0) & 0xFF); \ 96 | } 97 | #define LOAD32H(x, y) \ 98 | { \ 99 | (x) = ((uint32_t)((y)[0] & 0xFF) << 24) | \ 100 | ((uint32_t)((y)[1] & 0xFF) << 16) | \ 101 | ((uint32_t)((y)[2] & 0xFF) << 8) | ((uint32_t)((y)[3] & 0xFF) << 0); \ 102 | } 103 | 104 | #define LOAD64H(x, y) \ 105 | { \ 106 | (x) = ((uint64_t)((y)[0] & 0xFF) << 56) | \ 107 | ((uint64_t)((y)[1] & 0xFF) << 48) | \ 108 | ((uint64_t)((y)[2] & 0xFF) << 40) | \ 109 | ((uint64_t)((y)[3] & 0xFF) << 32) | \ 110 | ((uint64_t)((y)[4] & 0xFF) << 24) | \ 111 | ((uint64_t)((y)[5] & 0xFF) << 16) | \ 112 | ((uint64_t)((y)[6] & 0xFF) << 8) | ((uint64_t)((y)[7] & 0xFF) << 0); \ 113 | } 114 | 115 | #define STORE64H(y, x) \ 116 | { \ 117 | (y)[0] = (uint8_t)(((x) >> 56) & 0xFF); \ 118 | (y)[1] = (uint8_t)(((x) >> 48) & 0xFF); \ 119 | (y)[2] = (uint8_t)(((x) >> 40) & 0xFF); \ 120 | (y)[3] = (uint8_t)(((x) >> 32) & 0xFF); \ 121 | (y)[4] = (uint8_t)(((x) >> 24) & 0xFF); \ 122 | (y)[5] = (uint8_t)(((x) >> 16) & 0xFF); \ 123 | (y)[6] = (uint8_t)(((x) >> 8) & 0xFF); \ 124 | (y)[7] = (uint8_t)(((x) >> 0) & 0xFF); \ 125 | } 126 | 127 | #endif /* ENDIAN_LITTLE */ 128 | 129 | #ifdef ENDIAN_BIG 130 | 131 | #define STORE32H(y, x) \ 132 | { \ 133 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 134 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 135 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 136 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 137 | } 138 | #define STORE64H(y, x) \ 139 | { \ 140 | (y)[7] = (uint8_t)(((x) >> 56) & 0xFF); \ 141 | (y)[6] = (uint8_t)(((x) >> 48) & 0xFF); \ 142 | (y)[5] = (uint8_t)(((x) >> 40) & 0xFF); \ 143 | (y)[4] = (uint8_t)(((x) >> 32) & 0xFF); \ 144 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 145 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 146 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 147 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 148 | } 149 | #define LOAD32H(x, y) \ 150 | { \ 151 | (x) = ((uint32_t)((y)[3] & 0xFF) << 24) | \ 152 | ((uint32_t)((y)[2] & 0xFF) << 16) | \ 153 | ((uint32_t)((y)[1] & 0xFF) << 8) | ((uint32_t)((y)[0] & 0xFF) << 0); \ 154 | } 155 | 156 | #define LOAD64H(x, y) \ 157 | { \ 158 | (x) = ((uint64_t)((y)[7] & 0xFF) << 56) | \ 159 | ((uint64_t)((y)[6] & 0xFF) << 48) | \ 160 | ((uint64_t)((y)[5] & 0xFF) << 40) | \ 161 | ((uint64_t)((y)[4] & 0xFF) << 32) | \ 162 | ((uint64_t)((y)[3] & 0xFF) << 24) | \ 163 | ((uint64_t)((y)[2] & 0xFF) << 16) | \ 164 | ((uint64_t)((y)[1] & 0xFF) << 8) | ((uint64_t)((y)[0] & 0xFF) << 0); \ 165 | } 166 | 167 | #endif /* ENDIAN_BIG */ 168 | 169 | #define AES_TE0(x) AES_PRECOMP_TE0[(x)] 170 | #define AES_TE1(x) AES_PRECOMP_TE1[(x)] 171 | #define AES_TE2(x) AES_PRECOMP_TE2[(x)] 172 | #define AES_TE3(x) AES_PRECOMP_TE3[(x)] 173 | 174 | #define AES_TE4_0(x) AES_PRECOMP_TE4_0[(x)] 175 | #define AES_TE4_1(x) AES_PRECOMP_TE4_1[(x)] 176 | #define AES_TE4_2(x) AES_PRECOMP_TE4_2[(x)] 177 | #define AES_TE4_3(x) AES_PRECOMP_TE4_3[(x)] 178 | 179 | #define CryptoUtils_POOL_SIZE (0x1 << 17) // 2^17 180 | 181 | #define DUMP(x, l, s) \ 182 | fprintf(stderr, "%s :", (s)); \ 183 | for (int ii = 0; ii < (l); ii++) { \ 184 | fprintf(stderr, "%02hhX", *((x) + ii)); \ 185 | } \ 186 | fprintf(stderr, "\n"); 187 | 188 | // SHA256 189 | /* Various logical functions */ 190 | #define Ch(x, y, z) (z ^ (x &(y ^ z))) 191 | #define Maj(x, y, z) (((x | y) & z) | (x &y)) 192 | #define __S(x, n) RORc((x), (n)) 193 | #define R1(x, n) (((x) & 0xFFFFFFFFUL) >> (n)) 194 | #define Sigma0(x) (__S(x, 2) ^ __S(x, 13) ^ __S(x, 22)) 195 | #define Sigma1(x) (__S(x, 6) ^ __S(x, 11) ^ __S(x, 25)) 196 | #define Gamma0(x) (__S(x, 7) ^ __S(x, 18) ^ R1(x, 3)) 197 | #define Gamma1(x) (__S(x, 17) ^ __S(x, 19) ^ R1(x, 10)) 198 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 199 | 200 | #define RND(a, b, c, d, e, f, g, h, i, ki) \ 201 | t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ 202 | t1 = Sigma0(a) + Maj(a, b, c); \ 203 | d += t0; \ 204 | h = t0 + t1; 205 | 206 | #define RORc(x, y) \ 207 | (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ 208 | ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & \ 209 | 0xFFFFFFFFUL) 210 | 211 | class CryptoUtils { 212 | public: 213 | CryptoUtils(); 214 | ~CryptoUtils(); 215 | 216 | char *get_seed(); 217 | void get_bytes(char *buffer, const int len); 218 | char get_char(); 219 | bool prng_seed(const std::string seed); 220 | 221 | // Returns a uniformly distributed 8-bit value 222 | uint8_t get_uint8_t(); 223 | // Returns a uniformly distributed 16-bit value 224 | uint16_t get_uint16_t(); 225 | // Returns a uniformly distributed 32-bit value 226 | uint32_t get_uint32_t(); 227 | // Returns an integer uniformly distributed on [0, max[ 228 | uint32_t get_range(const uint32_t max); 229 | // Returns a uniformly distributed 64-bit value 230 | uint64_t get_uint64_t(); 231 | 232 | // Scramble a 32-bit value depending on a 128-bit value 233 | unsigned scramble32(const unsigned in, const char key[16]); 234 | 235 | int sha256(const char *msg, unsigned char *hash); 236 | 237 | private: 238 | uint32_t ks[44]; 239 | char key[16]; 240 | char ctr[16]; 241 | char pool[CryptoUtils_POOL_SIZE]; 242 | uint32_t idx; 243 | std::string seed; 244 | bool seeded; 245 | 246 | typedef struct { 247 | uint64_t length; 248 | uint32_t state[8], curlen; 249 | unsigned char buf[64]; 250 | } sha256_state; 251 | 252 | void aes_compute_ks(uint32_t *ks, const char *k); 253 | void aes_encrypt(char *out, const char *in, const uint32_t *ks); 254 | bool prng_seed(); 255 | void inc_ctr(); 256 | void populate_pool(); 257 | int sha256_done(sha256_state *md, unsigned char *out); 258 | int sha256_init(sha256_state *md); 259 | static int sha256_compress(sha256_state *md, unsigned char *buf); 260 | int sha256_process(sha256_state *md, const unsigned char *in, 261 | unsigned long inlen); 262 | }; 263 | } 264 | 265 | #endif // LLVM_CryptoUtils_H 266 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/Flattening.h: -------------------------------------------------------------------------------- 1 | //===- FlatteningIncludes.h - Flattening Obfuscation pass------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the flattening pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _FLATTENING_INCLUDES_ 15 | #define _FLATTENING_INCLUDES_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Function.h" 21 | #include "llvm/ADT/Statistic.h" 22 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/Transforms/Scalar.h" 25 | #include "llvm/IR/Module.h" 26 | #include "llvm/Support/CommandLine.h" 27 | #include "Transforms/Obfuscation/CryptoUtils.h" 28 | #include "Transforms/Obfuscation/Utils.h" 29 | 30 | // Namespace 31 | using namespace std; 32 | 33 | namespace llvm { 34 | FunctionPass *createFlatteningPass(); 35 | FunctionPass *createFlatteningPass(bool flag); 36 | void initializeFlatteningPass(PassRegistry &Registry); 37 | #if LLVM_VERSION_MAJOR >= 13 38 | class FlatteningPass : public PassInfoMixin{ 39 | public: 40 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 41 | static bool isRequired() { return true; } 42 | }; 43 | #endif 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/FunctionCallObfuscate.h: -------------------------------------------------------------------------------- 1 | #ifndef _FUNCTION_CALL_OBFUSCATION_H_ 2 | #define _FUNCTION_CALL_OBFUSCATION_H_ 3 | #include "llvm/Pass.h" 4 | #include "llvm/IR/LegacyPassManager.h" 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | // Namespace 9 | namespace llvm { 10 | FunctionPass* createFunctionCallObfuscatePass(); 11 | FunctionPass* createFunctionCallObfuscatePass(bool flag); 12 | void initializeFunctionCallObfuscatePass(PassRegistry &Registry); 13 | #if LLVM_VERSION_MAJOR >= 13 14 | class FunctionCallObfuscatePass : public PassInfoMixin{ 15 | public: 16 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 17 | static bool isRequired() { return true; } 18 | }; 19 | #endif 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/FunctionWrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef _FUNCTION_WRAPPER_H_ 2 | #define _FUNCTION_WRAPPER_H_ 3 | #include "llvm/Pass.h" 4 | #if LLVM_VERSION_MAJOR >= 13 5 | #include "llvm/Passes/PassBuilder.h" 6 | #endif 7 | using namespace std; 8 | using namespace llvm; 9 | 10 | // Namespace 11 | namespace llvm { 12 | ModulePass* createFunctionWrapperPass(); 13 | ModulePass* createFunctionWrapperPass(bool flag); 14 | void initializeFunctionWrapperPass(PassRegistry &Registry); 15 | #if LLVM_VERSION_MAJOR >= 13 16 | class FunctionWrapperPass : public PassInfoMixin{ 17 | public: 18 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 19 | static bool isRequired() { return true; } 20 | }; 21 | #endif 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/IndirectBranch.h: -------------------------------------------------------------------------------- 1 | #ifndef _INDIRECT_BRANCH_H_ 2 | #define _INDIRECT_BRANCH_H_ 3 | #include "llvm/Pass.h" 4 | #include "llvm/IR/LegacyPassManager.h" 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | // Namespace 9 | namespace llvm { 10 | FunctionPass* createIndirectBranchPass(); 11 | FunctionPass* createIndirectBranchPass(bool flag); 12 | void initializeIndirectBranchPass(PassRegistry &Registry); 13 | #if LLVM_VERSION_MAJOR >= 13 14 | class IndirectBranchPass : public PassInfoMixin{ 15 | public: 16 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 17 | static bool isRequired() { return true; } 18 | }; 19 | #endif 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/Obfuscation.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBFUSCATION_H_ 2 | #define _OBFUSCATION_H_ 3 | #include "Transforms/Obfuscation/AntiClassDump.h" 4 | #include "Transforms/Obfuscation/Flattening.h" 5 | #include "Transforms/Obfuscation/StringEncryption.h" 6 | #include "Transforms/Obfuscation/FunctionCallObfuscate.h" 7 | #include "Transforms/Obfuscation/Substitution.h" 8 | #include "Transforms/Obfuscation/BogusControlFlow.h" 9 | #include "Transforms/Obfuscation/Split.h" 10 | #include "Transforms/Obfuscation/IndirectBranch.h" 11 | #include "Transforms/Obfuscation/FunctionWrapper.h" 12 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 13 | #include "llvm/Transforms/Utils/ModuleUtils.h" 14 | #include "llvm/IR/Verifier.h" 15 | #include "llvm/IR/NoFolder.h" 16 | #include "llvm/IR/CFG.h" 17 | #include "llvm/IR/Dominators.h" 18 | #include "llvm/IR/IRBuilder.h" 19 | #include "llvm/IR/InlineAsm.h" 20 | #include "Transforms/Obfuscation/CryptoUtils.h" 21 | #include "llvm/Transforms/Scalar.h" 22 | #if __has_include("llvm/Transforms/Utils.h") 23 | #include "llvm/Transforms/Utils.h" 24 | #endif 25 | using namespace std; 26 | using namespace llvm; 27 | 28 | // Namespace 29 | namespace llvm { 30 | ModulePass* createObfuscationPass(); 31 | void initializeObfuscationPass(PassRegistry &Registry); 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/Split.h: -------------------------------------------------------------------------------- 1 | //===- FlatteningIncludes.h - Flattening Obfuscation pass------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the split basicblock pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _SPLIT_INCLUDES_ 15 | #define _SPLIT_INCLUDES_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/BasicBlock.h" 21 | #include "llvm/ADT/Statistic.h" 22 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/Transforms/Scalar.h" 25 | #include "llvm/IR/Module.h" 26 | #include "llvm/Support/CommandLine.h" 27 | #include "Transforms/Obfuscation/Utils.h" 28 | #include "Transforms/Obfuscation/CryptoUtils.h" 29 | 30 | // Namespace 31 | namespace llvm { 32 | FunctionPass *createSplitBasicBlockPass(); 33 | FunctionPass *createSplitBasicBlockPass(bool flag); 34 | void initializeSplitBasicBlockPass(PassRegistry &Registry); 35 | #if LLVM_VERSION_MAJOR >= 13 36 | class SplitBasicBlockPass : public PassInfoMixin{ 37 | public: 38 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 39 | static bool isRequired() { return true; } 40 | }; 41 | #endif 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/StringEncryption.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_ENCRYPTION_H_ 2 | #define _STRING_ENCRYPTION_H_ 3 | #include "llvm/Pass.h" 4 | #include "llvm/IR/LegacyPassManager.h" 5 | #include "llvm/PassRegistry.h" 6 | #if LLVM_VERSION_MAJOR >= 13 7 | #include "llvm/Passes/PassBuilder.h" 8 | #endif 9 | using namespace std; 10 | using namespace llvm; 11 | 12 | // Namespace 13 | namespace llvm { 14 | ModulePass* createStringEncryptionPass(); 15 | ModulePass* createStringEncryptionPass(bool flag); 16 | void initializeStringEncryptionPass(PassRegistry &Registry); 17 | #if LLVM_VERSION_MAJOR >= 13 18 | class StringEncryptionPass : public PassInfoMixin{ 19 | public: 20 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); 21 | static bool isRequired() { return true; } 22 | }; 23 | #endif 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/Substitution.h: -------------------------------------------------------------------------------- 1 | //===- SubstitutionIncludes.h - Substitution Obfuscation pass-------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the substitution pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _SUBSTITUTIONS_H_ 15 | #define _SUBSTITUTIONS_H_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Function.h" 21 | #include "llvm/IR/Instructions.h" 22 | #include "llvm/ADT/Statistic.h" 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/IR/Module.h" 25 | #include "llvm/Support/CommandLine.h" 26 | #include "Transforms/Obfuscation/CryptoUtils.h" 27 | #if LLVM_VERSION_MAJOR >= 13 28 | #include "llvm/Passes/PassBuilder.h" 29 | #endif 30 | 31 | // Namespace 32 | using namespace llvm; 33 | using namespace std; 34 | 35 | namespace llvm { 36 | FunctionPass *createSubstitutionPass(); 37 | FunctionPass *createSubstitutionPass(bool flag); 38 | void initializeSubstitutionPass(PassRegistry &Registry); 39 | #if LLVM_VERSION_MAJOR >= 13 40 | class SubstitutionPass : public PassInfoMixin{ 41 | public: 42 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 43 | static bool isRequired() { return true; } 44 | }; 45 | #endif 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /Hikari/include/Transforms/Obfuscation/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_OBF__ 2 | #define __UTILS_OBF__ 3 | 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace llvm; 13 | 14 | void fixStack(Function *f); 15 | std::string readAnnotate(Function *f); 16 | map BuildAnnotateMap(Module& M); 17 | bool toObfuscate(bool flag, Function *f, std::string attribute); 18 | void FixBasicBlockConstantExpr(BasicBlock *BB); 19 | void FixFunctionConstantExpr(Function *Func); 20 | void appendToAnnotations(Module &M,ConstantStruct *Data); 21 | #endif 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Based on code from Adrian Sampson 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Adrian Sampson 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ollvm/armariris port to llvm10 in 2020 2 | 3 | # skeleton port to llvm14 in 2022 4 | 5 | # Hikari port to llvm14 in 2022 by [HimekoEx](https://github.com/HimekoEx) -------------------------------------------------------------------------------- /ollvm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ollvm MODULE 2 | # List your source files here. 3 | BogusControlFlow.cpp 4 | CryptoUtils.cpp 5 | Flattening.cpp 6 | SplitBasicBlocks.cpp 7 | Substitution.cpp 8 | Utils.cpp 9 | include/llvm/CryptoUtils.h 10 | include/Transforms/Obfuscation/BogusControlFlow.h 11 | include/Transforms/Obfuscation/Flattening.h 12 | include/Transforms/Obfuscation/Split.h 13 | include/Transforms/Obfuscation/Substitution.h 14 | include/Transforms/Obfuscation/Utils.h 15 | Enter.cpp 16 | ) 17 | 18 | # Use C++11 to compile your pass (i.e., supply -std=c++11). 19 | target_compile_features(ollvm PRIVATE cxx_range_for cxx_auto_type) 20 | 21 | include_directories(include) 22 | 23 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 24 | # otherwise, we'll get linker errors about missing RTTI data. 25 | set_target_properties(ollvm PROPERTIES 26 | COMPILE_FLAGS "-fno-rtti" 27 | ) 28 | 29 | # Get proper shared-library behavior (where symbols are not necessarily 30 | # resolved when the shared library is linked) on OS X. 31 | if(APPLE) 32 | set_target_properties(ollvm PROPERTIES 33 | LINK_FLAGS "-undefined dynamic_lookup" 34 | ) 35 | endif(APPLE) 36 | -------------------------------------------------------------------------------- /ollvm/Enter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by LeadroyaL on 2018/10/10. 3 | // 4 | 5 | #include "Transforms/Obfuscation/BogusControlFlow.h" 6 | #include "Transforms/Obfuscation/Flattening.h" 7 | #include "Transforms/Obfuscation/Split.h" 8 | #include "Transforms/Obfuscation/Substitution.h" 9 | #include "llvm/IR/LegacyPassManager.h" 10 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 11 | 12 | using namespace llvm; 13 | 14 | static void registerOllvmPass(const PassManagerBuilder &, 15 | legacy::PassManagerBase &PM) { 16 | PM.add(createBogus(true)); 17 | #if LLVM_VERSION_MAJOR >= 9 18 | PM.add(createLowerSwitchPass()); 19 | #endif 20 | PM.add(createFlattening(true)); 21 | PM.add(createSplitBasicBlock(true)); 22 | PM.add(createSubstitution(true)); 23 | } 24 | static RegisterStandardPasses 25 | RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 26 | registerOllvmPass); 27 | -------------------------------------------------------------------------------- /ollvm/Flattening.cpp: -------------------------------------------------------------------------------- 1 | //===- Flattening.cpp - Flattening Obfuscation pass------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file implements the flattening pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "Transforms/Obfuscation/Flattening.h" 15 | #include "Transforms/Obfuscation/Utils.h" 16 | #include "llvm/Transforms/Scalar.h" 17 | #include "llvm/CryptoUtils.h" 18 | 19 | #define DEBUG_TYPE "flattening" 20 | 21 | using namespace llvm; 22 | 23 | // Stats 24 | STATISTIC(Flattened, "Functions flattened"); 25 | 26 | namespace { 27 | struct Flattening : public FunctionPass { 28 | static char ID; // Pass identification, replacement for typeid 29 | bool flag; 30 | 31 | Flattening() : FunctionPass(ID) {} 32 | Flattening(bool flag) : FunctionPass(ID) { this->flag = flag; } 33 | 34 | bool runOnFunction(Function &F); 35 | bool flatten(Function *f); 36 | }; 37 | } 38 | 39 | char Flattening::ID = 0; 40 | static RegisterPass X("flattening", "Call graph flattening"); 41 | Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); } 42 | 43 | bool Flattening::runOnFunction(Function &F) { 44 | Function *tmp = &F; 45 | // Do we obfuscate 46 | if (toObfuscate(flag, tmp, "fla")) { 47 | if (flatten(tmp)) { 48 | ++Flattened; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | bool Flattening::flatten(Function *f) { 56 | vector origBB; 57 | BasicBlock *loopEntry; 58 | BasicBlock *loopEnd; 59 | LoadInst *load; 60 | SwitchInst *switchI; 61 | AllocaInst *switchVar; 62 | 63 | // SCRAMBLER 64 | char scrambling_key[16]; 65 | llvm::cryptoutils->get_bytes(scrambling_key, 16); 66 | // END OF SCRAMBLER 67 | 68 | // Lower switch 69 | #if LLVM_VERSION_MAJOR >= 9 70 | // >=9.0, LowerSwitchPass depends on LazyValueInfoWrapperPass, which cause AssertError. 71 | // So I move LowerSwitchPass into register function, just before FlatteningPass. 72 | #else 73 | FunctionPass *lower = createLowerSwitchPass(); 74 | lower->runOnFunction(*f); 75 | #endif 76 | 77 | // Save all original BB 78 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 79 | BasicBlock *tmp = &*i; 80 | origBB.push_back(tmp); 81 | 82 | BasicBlock *bb = &*i; 83 | if (isa(bb->getTerminator())) { 84 | return false; 85 | } 86 | } 87 | 88 | // Nothing to flatten 89 | if (origBB.size() <= 1) { 90 | return false; 91 | } 92 | 93 | // Remove first BB 94 | origBB.erase(origBB.begin()); 95 | 96 | // Get a pointer on the first BB 97 | Function::iterator tmp = f->begin(); //++tmp; 98 | BasicBlock *insert = &*tmp; 99 | 100 | // If main begin with an if 101 | BranchInst *br = NULL; 102 | if (isa(insert->getTerminator())) { 103 | br = cast(insert->getTerminator()); 104 | } 105 | 106 | if ((br != NULL && br->isConditional()) || 107 | insert->getTerminator()->getNumSuccessors() > 1) { 108 | BasicBlock::iterator i = insert->end(); 109 | --i; 110 | 111 | if (insert->size() > 1) { 112 | --i; 113 | } 114 | 115 | BasicBlock *tmpBB = insert->splitBasicBlock(i, "first"); 116 | origBB.insert(origBB.begin(), tmpBB); 117 | } 118 | 119 | // Remove jump 120 | insert->getTerminator()->eraseFromParent(); 121 | 122 | // Create switch variable and set as it 123 | switchVar = 124 | new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert); 125 | new StoreInst( 126 | ConstantInt::get(Type::getInt32Ty(f->getContext()), 127 | llvm::cryptoutils->scramble32(0, scrambling_key)), 128 | switchVar, insert); 129 | 130 | // Create main loop 131 | loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert); 132 | loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert); 133 | 134 | load = new LoadInst(switchVar, "switchVar", loopEntry); 135 | 136 | // Move first BB on top 137 | insert->moveBefore(loopEntry); 138 | BranchInst::Create(loopEntry, insert); 139 | 140 | // loopEnd jump to loopEntry 141 | BranchInst::Create(loopEntry, loopEnd); 142 | 143 | BasicBlock *swDefault = 144 | BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd); 145 | BranchInst::Create(loopEnd, swDefault); 146 | 147 | // Create switch instruction itself and set condition 148 | switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry); 149 | switchI->setCondition(load); 150 | 151 | // Remove branch jump from 1st BB and make a jump to the while 152 | f->begin()->getTerminator()->eraseFromParent(); 153 | 154 | BranchInst::Create(loopEntry, &*f->begin()); 155 | 156 | // Put all BB in the switch 157 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 158 | ++b) { 159 | BasicBlock *i = *b; 160 | ConstantInt *numCase = NULL; 161 | 162 | // Move the BB inside the switch (only visual, no code logic) 163 | i->moveBefore(loopEnd); 164 | 165 | // Add case to switch 166 | numCase = cast(ConstantInt::get( 167 | switchI->getCondition()->getType(), 168 | llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); 169 | switchI->addCase(numCase, i); 170 | } 171 | 172 | // Recalculate switchVar 173 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 174 | ++b) { 175 | BasicBlock *i = *b; 176 | ConstantInt *numCase = NULL; 177 | 178 | // Ret BB 179 | if (i->getTerminator()->getNumSuccessors() == 0) { 180 | continue; 181 | } 182 | 183 | // If it's a non-conditional jump 184 | if (i->getTerminator()->getNumSuccessors() == 1) { 185 | // Get successor and delete terminator 186 | BasicBlock *succ = i->getTerminator()->getSuccessor(0); 187 | i->getTerminator()->eraseFromParent(); 188 | 189 | // Get next case 190 | numCase = switchI->findCaseDest(succ); 191 | 192 | // If next case == default case (switchDefault) 193 | if (numCase == NULL) { 194 | numCase = cast( 195 | ConstantInt::get(switchI->getCondition()->getType(), 196 | llvm::cryptoutils->scramble32( 197 | switchI->getNumCases() - 1, scrambling_key))); 198 | } 199 | 200 | // Update switchVar and jump to the end of loop 201 | new StoreInst(numCase, load->getPointerOperand(), i); 202 | BranchInst::Create(loopEnd, i); 203 | continue; 204 | } 205 | 206 | // If it's a conditional jump 207 | if (i->getTerminator()->getNumSuccessors() == 2) { 208 | // Get next cases 209 | ConstantInt *numCaseTrue = 210 | switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); 211 | ConstantInt *numCaseFalse = 212 | switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); 213 | 214 | // Check if next case == default case (switchDefault) 215 | if (numCaseTrue == NULL) { 216 | numCaseTrue = cast( 217 | ConstantInt::get(switchI->getCondition()->getType(), 218 | llvm::cryptoutils->scramble32( 219 | switchI->getNumCases() - 1, scrambling_key))); 220 | } 221 | 222 | if (numCaseFalse == NULL) { 223 | numCaseFalse = cast( 224 | ConstantInt::get(switchI->getCondition()->getType(), 225 | llvm::cryptoutils->scramble32( 226 | switchI->getNumCases() - 1, scrambling_key))); 227 | } 228 | 229 | // Create a SelectInst 230 | BranchInst *br = cast(i->getTerminator()); 231 | SelectInst *sel = 232 | SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", 233 | i->getTerminator()); 234 | 235 | // Erase terminator 236 | i->getTerminator()->eraseFromParent(); 237 | 238 | // Update switchVar and jump to the end of loop 239 | new StoreInst(sel, load->getPointerOperand(), i); 240 | BranchInst::Create(loopEnd, i); 241 | continue; 242 | } 243 | } 244 | 245 | fixStack(f); 246 | 247 | return true; 248 | } 249 | -------------------------------------------------------------------------------- /ollvm/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 | -------------------------------------------------------------------------------- /ollvm/SplitBasicBlocks.cpp: -------------------------------------------------------------------------------- 1 | //===- SplitBasicBlock.cpp - SplitBasicBlokc Obfuscation pass--------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file implements the split basic block pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "Transforms/Obfuscation/Split.h" 15 | #include "Transforms/Obfuscation/Utils.h" 16 | #include "llvm/CryptoUtils.h" 17 | 18 | #define DEBUG_TYPE "split" 19 | 20 | using namespace llvm; 21 | using namespace std; 22 | 23 | // Stats 24 | STATISTIC(Split, "Basicblock splitted"); 25 | 26 | static cl::opt SplitNum("split_num", cl::init(2), 27 | cl::desc("Split time each BB")); 28 | 29 | namespace { 30 | struct SplitBasicBlock : public FunctionPass { 31 | static char ID; // Pass identification, replacement for typeid 32 | bool flag; 33 | 34 | SplitBasicBlock() : FunctionPass(ID) {} 35 | SplitBasicBlock(bool flag) : FunctionPass(ID) { 36 | 37 | this->flag = flag; 38 | } 39 | 40 | bool runOnFunction(Function &F); 41 | void split(Function *f); 42 | 43 | bool containsPHI(BasicBlock *b); 44 | void shuffle(std::vector &vec); 45 | }; 46 | } 47 | 48 | char SplitBasicBlock::ID = 0; 49 | static RegisterPass X("splitbbl", "BasicBlock splitting"); 50 | 51 | Pass *llvm::createSplitBasicBlock(bool flag) { 52 | return new SplitBasicBlock(flag); 53 | } 54 | 55 | bool SplitBasicBlock::runOnFunction(Function &F) { 56 | // Check if the number of applications is correct 57 | if (!((SplitNum > 1) && (SplitNum <= 10))) { 58 | errs()<<"Split application basic block percentage\ 59 | -split_num=x must be 1 < x <= 10"; 60 | return false; 61 | } 62 | 63 | Function *tmp = &F; 64 | 65 | // Do we obfuscate 66 | if (toObfuscate(flag, tmp, "split")) { 67 | split(tmp); 68 | ++Split; 69 | } 70 | 71 | return false; 72 | } 73 | 74 | void SplitBasicBlock::split(Function *f) { 75 | std::vector origBB; 76 | int splitN = SplitNum; 77 | 78 | // Save all basic blocks 79 | for (Function::iterator I = f->begin(), IE = f->end(); I != IE; ++I) { 80 | origBB.push_back(&*I); 81 | } 82 | 83 | for (std::vector::iterator I = origBB.begin(), 84 | IE = origBB.end(); 85 | I != IE; ++I) { 86 | BasicBlock *curr = *I; 87 | 88 | // No need to split a 1 inst bb 89 | // Or ones containing a PHI node 90 | if (curr->size() < 2 || containsPHI(curr)) { 91 | continue; 92 | } 93 | 94 | // Check splitN and current BB size 95 | if ((size_t)splitN > curr->size()) { 96 | splitN = curr->size() - 1; 97 | } 98 | 99 | // Generate splits point 100 | std::vector test; 101 | for (unsigned i = 1; i < curr->size(); ++i) { 102 | test.push_back(i); 103 | } 104 | 105 | // Shuffle 106 | if (test.size() != 1) { 107 | shuffle(test); 108 | std::sort(test.begin(), test.begin() + splitN); 109 | } 110 | 111 | // Split 112 | BasicBlock::iterator it = curr->begin(); 113 | BasicBlock *toSplit = curr; 114 | int last = 0; 115 | for (int i = 0; i < splitN; ++i) { 116 | for (int j = 0; j < test[i] - last; ++j) { 117 | ++it; 118 | } 119 | last = test[i]; 120 | if(toSplit->size() < 2) 121 | continue; 122 | toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split"); 123 | } 124 | 125 | ++Split; 126 | } 127 | } 128 | 129 | bool SplitBasicBlock::containsPHI(BasicBlock *b) { 130 | for (BasicBlock::iterator I = b->begin(), IE = b->end(); I != IE; ++I) { 131 | if (isa(I)) { 132 | return true; 133 | } 134 | } 135 | return false; 136 | } 137 | 138 | void SplitBasicBlock::shuffle(std::vector &vec) { 139 | int n = vec.size(); 140 | for (int i = n - 1; i > 0; --i) { 141 | std::swap(vec[i], vec[cryptoutils->get_uint32_t() % (i + 1)]); 142 | } 143 | } 144 | 145 | -------------------------------------------------------------------------------- /ollvm/Substitution.cpp: -------------------------------------------------------------------------------- 1 | //===- Substitution.cpp - Substitution Obfuscation 2 | // pass-------------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | // 11 | // This file implements operators substitution's pass 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #include "Transforms/Obfuscation/Substitution.h" 16 | #include "llvm/IR/LLVMContext.h" 17 | #include "llvm/Support/raw_ostream.h" 18 | #include "Transforms/Obfuscation/Utils.h" 19 | #include "llvm/IR/Intrinsics.h" 20 | 21 | #define DEBUG_TYPE "substitution" 22 | 23 | #define NUMBER_ADD_SUBST 4 24 | #define NUMBER_SUB_SUBST 3 25 | #define NUMBER_AND_SUBST 2 26 | #define NUMBER_OR_SUBST 2 27 | #define NUMBER_XOR_SUBST 2 28 | 29 | static cl::opt 30 | ObfTimes("sub_loop", 31 | cl::desc("Choose how many time the -sub pass loops on a function"), 32 | cl::value_desc("number of times"), cl::init(1), cl::Optional); 33 | 34 | 35 | // Stats 36 | STATISTIC(Add, "Add substitued"); 37 | STATISTIC(Sub, "Sub substitued"); 38 | // STATISTIC(Mul, "Mul substitued"); 39 | // STATISTIC(Div, "Div substitued"); 40 | // STATISTIC(Rem, "Rem substitued"); 41 | // STATISTIC(Shi, "Shift substitued"); 42 | STATISTIC(And, "And substitued"); 43 | STATISTIC(Or, "Or substitued"); 44 | STATISTIC(Xor, "Xor substitued"); 45 | 46 | namespace { 47 | 48 | struct Substitution : public FunctionPass { 49 | static char ID; // Pass identification, replacement for typeid 50 | void (Substitution::*funcAdd[NUMBER_ADD_SUBST])(BinaryOperator *bo); 51 | void (Substitution::*funcSub[NUMBER_SUB_SUBST])(BinaryOperator *bo); 52 | void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo); 53 | void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo); 54 | void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo); 55 | bool flag; 56 | 57 | Substitution() : FunctionPass(ID) {} 58 | 59 | Substitution(bool flag) : FunctionPass(ID) { 60 | this->flag = flag; 61 | funcAdd[0] = &Substitution::addNeg; 62 | funcAdd[1] = &Substitution::addDoubleNeg; 63 | funcAdd[2] = &Substitution::addRand; 64 | funcAdd[3] = &Substitution::addRand2; 65 | 66 | funcSub[0] = &Substitution::subNeg; 67 | funcSub[1] = &Substitution::subRand; 68 | funcSub[2] = &Substitution::subRand2; 69 | 70 | funcAnd[0] = &Substitution::andSubstitution; 71 | funcAnd[1] = &Substitution::andSubstitutionRand; 72 | 73 | funcOr[0] = &Substitution::orSubstitution; 74 | funcOr[1] = &Substitution::orSubstitutionRand; 75 | 76 | funcXor[0] = &Substitution::xorSubstitution; 77 | funcXor[1] = &Substitution::xorSubstitutionRand; 78 | } 79 | 80 | bool runOnFunction(Function &F); 81 | bool substitute(Function *f); 82 | 83 | void addNeg(BinaryOperator *bo); 84 | void addDoubleNeg(BinaryOperator *bo); 85 | void addRand(BinaryOperator *bo); 86 | void addRand2(BinaryOperator *bo); 87 | 88 | void subNeg(BinaryOperator *bo); 89 | void subRand(BinaryOperator *bo); 90 | void subRand2(BinaryOperator *bo); 91 | 92 | void andSubstitution(BinaryOperator *bo); 93 | void andSubstitutionRand(BinaryOperator *bo); 94 | 95 | void orSubstitution(BinaryOperator *bo); 96 | void orSubstitutionRand(BinaryOperator *bo); 97 | 98 | void xorSubstitution(BinaryOperator *bo); 99 | void xorSubstitutionRand(BinaryOperator *bo); 100 | }; 101 | } 102 | 103 | char Substitution::ID = 0; 104 | static RegisterPass X("substitution", "operators substitution"); 105 | Pass *llvm::createSubstitution(bool flag) { return new Substitution(flag); } 106 | 107 | bool Substitution::runOnFunction(Function &F) { 108 | // Check if the percentage is correct 109 | if (ObfTimes <= 0) { 110 | errs()<<"Substitution application number -sub_loop=x must be x > 0"; 111 | return false; 112 | } 113 | 114 | Function *tmp = &F; 115 | // Do we obfuscate 116 | if (toObfuscate(flag, tmp, "sub")) { 117 | substitute(tmp); 118 | return true; 119 | } 120 | 121 | return false; 122 | } 123 | 124 | bool Substitution::substitute(Function *f) { 125 | Function *tmp = f; 126 | 127 | // Loop for the number of time we run the pass on the function 128 | int times = ObfTimes; 129 | do { 130 | for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) { 131 | for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { 132 | if (inst->isBinaryOp()) { 133 | switch (inst->getOpcode()) { 134 | case BinaryOperator::Add: 135 | // case BinaryOperator::FAdd: 136 | // Substitute with random add operation 137 | (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])( 138 | cast(inst)); 139 | ++Add; 140 | break; 141 | case BinaryOperator::Sub: 142 | // case BinaryOperator::FSub: 143 | // Substitute with random sub operation 144 | (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])( 145 | cast(inst)); 146 | ++Sub; 147 | break; 148 | case BinaryOperator::Mul: 149 | case BinaryOperator::FMul: 150 | //++Mul; 151 | break; 152 | case BinaryOperator::UDiv: 153 | case BinaryOperator::SDiv: 154 | case BinaryOperator::FDiv: 155 | //++Div; 156 | break; 157 | case BinaryOperator::URem: 158 | case BinaryOperator::SRem: 159 | case BinaryOperator::FRem: 160 | //++Rem; 161 | break; 162 | case Instruction::Shl: 163 | //++Shi; 164 | break; 165 | case Instruction::LShr: 166 | //++Shi; 167 | break; 168 | case Instruction::AShr: 169 | //++Shi; 170 | break; 171 | case Instruction::And: 172 | (this->* 173 | funcAnd[llvm::cryptoutils->get_range(2)])(cast(inst)); 174 | ++And; 175 | break; 176 | case Instruction::Or: 177 | (this->* 178 | funcOr[llvm::cryptoutils->get_range(2)])(cast(inst)); 179 | ++Or; 180 | break; 181 | case Instruction::Xor: 182 | (this->* 183 | funcXor[llvm::cryptoutils->get_range(2)])(cast(inst)); 184 | ++Xor; 185 | break; 186 | default: 187 | break; 188 | } // End switch 189 | } // End isBinaryOp 190 | } // End for basickblock 191 | } // End for Function 192 | } while (--times > 0); // for times 193 | return false; 194 | } 195 | 196 | // Implementation of a = b - (-c) 197 | void Substitution::addNeg(BinaryOperator *bo) { 198 | BinaryOperator *op = NULL; 199 | 200 | // Create sub 201 | if (bo->getOpcode() == Instruction::Add) { 202 | op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 203 | op = 204 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo); 205 | 206 | // Check signed wrap 207 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 208 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 209 | 210 | bo->replaceAllUsesWith(op); 211 | }/* else { 212 | op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo); 213 | op = BinaryOperator::Create(Instruction::FSub, bo->getOperand(0), op, "", 214 | bo); 215 | }*/ 216 | } 217 | 218 | // Implementation of a = -(-b + (-c)) 219 | void Substitution::addDoubleNeg(BinaryOperator *bo) { 220 | BinaryOperator *op, *op2 = NULL; 221 | 222 | if (bo->getOpcode() == Instruction::Add) { 223 | op = BinaryOperator::CreateNeg(bo->getOperand(0), "", bo); 224 | op2 = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 225 | op = BinaryOperator::Create(Instruction::Add, op, op2, "", bo); 226 | op = BinaryOperator::CreateNeg(op, "", bo); 227 | 228 | // Check signed wrap 229 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 230 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 231 | } else { 232 | op = BinaryOperator::CreateFNeg(bo->getOperand(0), "", bo); 233 | op2 = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo); 234 | op = BinaryOperator::Create(Instruction::FAdd, op, op2, "", bo); 235 | op = BinaryOperator::CreateFNeg(op, "", bo); 236 | } 237 | 238 | bo->replaceAllUsesWith(op); 239 | } 240 | 241 | // Implementation of r = rand (); a = b + r; a = a + c; a = a - r 242 | void Substitution::addRand(BinaryOperator *bo) { 243 | BinaryOperator *op = NULL; 244 | 245 | if (bo->getOpcode() == Instruction::Add) { 246 | Type *ty = bo->getType(); 247 | ConstantInt *co = 248 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 249 | op = 250 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo); 251 | op = 252 | BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo); 253 | op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo); 254 | 255 | // Check signed wrap 256 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 257 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 258 | 259 | bo->replaceAllUsesWith(op); 260 | } 261 | /* else { 262 | Type *ty = bo->getType(); 263 | ConstantFP *co = 264 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 265 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 266 | op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo); 267 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 268 | } */ 269 | } 270 | 271 | // Implementation of r = rand (); a = b - r; a = a + b; a = a + r 272 | void Substitution::addRand2(BinaryOperator *bo) { 273 | BinaryOperator *op = NULL; 274 | 275 | if (bo->getOpcode() == Instruction::Add) { 276 | Type *ty = bo->getType(); 277 | ConstantInt *co = 278 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 279 | op = 280 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo); 281 | op = 282 | BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo); 283 | op = BinaryOperator::Create(Instruction::Add, op, co, "", bo); 284 | 285 | // Check signed wrap 286 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 287 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 288 | 289 | bo->replaceAllUsesWith(op); 290 | } 291 | /* else { 292 | Type *ty = bo->getType(); 293 | ConstantFP *co = 294 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 295 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 296 | op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo); 297 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 298 | } */ 299 | } 300 | 301 | // Implementation of a = b + (-c) 302 | void Substitution::subNeg(BinaryOperator *bo) { 303 | BinaryOperator *op = NULL; 304 | 305 | if (bo->getOpcode() == Instruction::Sub) { 306 | op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 307 | op = 308 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo); 309 | 310 | // Check signed wrap 311 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 312 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 313 | } else { 314 | op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo); 315 | op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op, "", 316 | bo); 317 | } 318 | 319 | bo->replaceAllUsesWith(op); 320 | } 321 | 322 | // Implementation of r = rand (); a = b + r; a = a - c; a = a - r 323 | void Substitution::subRand(BinaryOperator *bo) { 324 | BinaryOperator *op = NULL; 325 | 326 | if (bo->getOpcode() == Instruction::Sub) { 327 | Type *ty = bo->getType(); 328 | ConstantInt *co = 329 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 330 | op = 331 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo); 332 | op = 333 | BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo); 334 | op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo); 335 | 336 | // Check signed wrap 337 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 338 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 339 | 340 | bo->replaceAllUsesWith(op); 341 | } 342 | /* else { 343 | Type *ty = bo->getType(); 344 | ConstantFP *co = 345 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 346 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 347 | op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo); 348 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 349 | } */ 350 | } 351 | 352 | // Implementation of r = rand (); a = b - r; a = a - c; a = a + r 353 | void Substitution::subRand2(BinaryOperator *bo) { 354 | BinaryOperator *op = NULL; 355 | 356 | if (bo->getOpcode() == Instruction::Sub) { 357 | Type *ty = bo->getType(); 358 | ConstantInt *co = 359 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 360 | op = 361 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo); 362 | op = 363 | BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo); 364 | op = BinaryOperator::Create(Instruction::Add, op, co, "", bo); 365 | 366 | // Check signed wrap 367 | //op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 368 | //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 369 | 370 | bo->replaceAllUsesWith(op); 371 | } 372 | /* else { 373 | Type *ty = bo->getType(); 374 | ConstantFP *co = 375 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 376 | op = BinaryOperator::Create(Instruction::FSub,bo->getOperand(0),co,"",bo); 377 | op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo); 378 | op = BinaryOperator::Create(Instruction::FAdd,op,co,"",bo); 379 | } */ 380 | } 381 | 382 | // Implementation of a = b & c => a = (b^~c)& b 383 | void Substitution::andSubstitution(BinaryOperator *bo) { 384 | BinaryOperator *op = NULL; 385 | 386 | // Create NOT on second operand => ~c 387 | op = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 388 | 389 | // Create XOR => (b^~c) 390 | BinaryOperator *op1 = 391 | BinaryOperator::Create(Instruction::Xor, bo->getOperand(0), op, "", bo); 392 | 393 | // Create AND => (b^~c) & b 394 | op = BinaryOperator::Create(Instruction::And, op1, bo->getOperand(0), "", bo); 395 | bo->replaceAllUsesWith(op); 396 | } 397 | 398 | // Implementation of a = a && b <=> !(!a | !b) && (r | !r) 399 | void Substitution::andSubstitutionRand(BinaryOperator *bo) { 400 | // Copy of the BinaryOperator type to create the random number with the 401 | // same type of the operands 402 | Type *ty = bo->getType(); 403 | 404 | // r (Random number) 405 | ConstantInt *co = 406 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 407 | 408 | // !a 409 | BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 410 | 411 | // !b 412 | BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 413 | 414 | // !r 415 | BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo); 416 | 417 | // (!a | !b) 418 | BinaryOperator *opa = 419 | BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 420 | 421 | // (r | !r) 422 | opr = BinaryOperator::Create(Instruction::Or, co, opr, "", bo); 423 | 424 | // !(!a | !b) 425 | op = BinaryOperator::CreateNot(opa, "", bo); 426 | 427 | // !(!a | !b) && (r | !r) 428 | op = BinaryOperator::Create(Instruction::And, op, opr, "", bo); 429 | 430 | // We replace all the old AND operators with the new one transformed 431 | bo->replaceAllUsesWith(op); 432 | } 433 | 434 | // Implementation of a = b | c => a = (b & c) | (b ^ c) 435 | void Substitution::orSubstitutionRand(BinaryOperator *bo) { 436 | 437 | Type *ty = bo->getType(); 438 | ConstantInt *co = 439 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 440 | 441 | // !a 442 | BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 443 | 444 | // !b 445 | BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 446 | 447 | // !r 448 | BinaryOperator *op2 = BinaryOperator::CreateNot(co, "", bo); 449 | 450 | // !a && r 451 | BinaryOperator *op3 = 452 | BinaryOperator::Create(Instruction::And, op, co, "", bo); 453 | 454 | // a && !r 455 | BinaryOperator *op4 = 456 | BinaryOperator::Create(Instruction::And, bo->getOperand(0), op2, "", bo); 457 | 458 | // !b && r 459 | BinaryOperator *op5 = 460 | BinaryOperator::Create(Instruction::And, op1, co, "", bo); 461 | 462 | // b && !r 463 | BinaryOperator *op6 = 464 | BinaryOperator::Create(Instruction::And, bo->getOperand(1), op2, "", bo); 465 | 466 | // (!a && r) || (a && !r) 467 | op3 = BinaryOperator::Create(Instruction::Or, op3, op4, "", bo); 468 | 469 | // (!b && r) ||(b && !r) 470 | op4 = BinaryOperator::Create(Instruction::Or, op5, op6, "", bo); 471 | 472 | // (!a && r) || (a && !r) ^ (!b && r) ||(b && !r) 473 | op5 = BinaryOperator::Create(Instruction::Xor, op3, op4, "", bo); 474 | 475 | // !a || !b 476 | op3 = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 477 | 478 | // !(!a || !b) 479 | op3 = BinaryOperator::CreateNot(op3, "", bo); 480 | 481 | // r || !r 482 | op4 = BinaryOperator::Create(Instruction::Or, co, op2, "", bo); 483 | 484 | // !(!a || !b) && (r || !r) 485 | op4 = BinaryOperator::Create(Instruction::And, op3, op4, "", bo); 486 | 487 | // [(!a && r) || (a && !r) ^ (!b && r) ||(b && !r) ] || [!(!a || !b) && (r || 488 | // !r)] 489 | op = BinaryOperator::Create(Instruction::Or, op5, op4, "", bo); 490 | bo->replaceAllUsesWith(op); 491 | } 492 | 493 | void Substitution::orSubstitution(BinaryOperator *bo) { 494 | BinaryOperator *op = NULL; 495 | 496 | // Creating first operand (b & c) 497 | op = BinaryOperator::Create(Instruction::And, bo->getOperand(0), 498 | bo->getOperand(1), "", bo); 499 | 500 | // Creating second operand (b ^ c) 501 | BinaryOperator *op1 = BinaryOperator::Create( 502 | Instruction::Xor, bo->getOperand(0), bo->getOperand(1), "", bo); 503 | 504 | // final op 505 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 506 | bo->replaceAllUsesWith(op); 507 | } 508 | 509 | // Implementation of a = a ~ b => a = (!a && b) || (a && !b) 510 | void Substitution::xorSubstitution(BinaryOperator *bo) { 511 | BinaryOperator *op = NULL; 512 | 513 | // Create NOT on first operand 514 | op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); // !a 515 | 516 | // Create AND 517 | op = BinaryOperator::Create(Instruction::And, bo->getOperand(1), op, "", 518 | bo); // !a && b 519 | 520 | // Create NOT on second operand 521 | BinaryOperator *op1 = 522 | BinaryOperator::CreateNot(bo->getOperand(1), "", bo); // !b 523 | 524 | // Create AND 525 | op1 = BinaryOperator::Create(Instruction::And, bo->getOperand(0), op1, "", 526 | bo); // a && !b 527 | 528 | // Create OR 529 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", 530 | bo); // (!a && b) || (a && !b) 531 | bo->replaceAllUsesWith(op); 532 | } 533 | 534 | // implementation of a = a ^ b <=> (a ^ r) ^ (b ^ r) <=> (!a && r || a && !r) ^ 535 | // (!b && r || b && !r) 536 | // note : r is a random number 537 | void Substitution::xorSubstitutionRand(BinaryOperator *bo) { 538 | BinaryOperator *op = NULL; 539 | 540 | Type *ty = bo->getType(); 541 | ConstantInt *co = 542 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 543 | 544 | // !a 545 | op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 546 | 547 | // !a && r 548 | op = BinaryOperator::Create(Instruction::And, co, op, "", bo); 549 | 550 | // !r 551 | BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo); 552 | 553 | // a && !r 554 | BinaryOperator *op1 = 555 | BinaryOperator::Create(Instruction::And, bo->getOperand(0), opr, "", bo); 556 | 557 | // !b 558 | BinaryOperator *op2 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 559 | 560 | // !b && r 561 | op2 = BinaryOperator::Create(Instruction::And, op2, co, "", bo); 562 | 563 | // b && !r 564 | BinaryOperator *op3 = 565 | BinaryOperator::Create(Instruction::And, bo->getOperand(1), opr, "", bo); 566 | 567 | // (!a && r) || (a && !r) 568 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 569 | 570 | // (!b && r) || (b && !r) 571 | op1 = BinaryOperator::Create(Instruction::Or, op2, op3, "", bo); 572 | 573 | // (!a && r) || (a && !r) ^ (!b && r) || (b && !r) 574 | op = BinaryOperator::Create(Instruction::Xor, op, op1, "", bo); 575 | bo->replaceAllUsesWith(op); 576 | } 577 | 578 | -------------------------------------------------------------------------------- /ollvm/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Transforms/Obfuscation/Utils.h" 2 | #include "llvm/Support/raw_ostream.h" 3 | #include 4 | #include "llvm/IR/Module.h" 5 | 6 | // Shamefully borrowed from ../Scalar/RegToMem.cpp :( 7 | bool valueEscapes(Instruction *Inst) { 8 | BasicBlock *BB = Inst->getParent(); 9 | for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; 10 | ++UI) { 11 | Instruction *I = cast(*UI); 12 | if (I->getParent() != BB || isa(I)) { 13 | return true; 14 | } 15 | } 16 | return false; 17 | } 18 | 19 | void fixStack(Function *f) { 20 | // Try to remove phi node and demote reg to stack 21 | std::vector tmpPhi; 22 | std::vector tmpReg; 23 | BasicBlock *bbEntry = &*f->begin(); 24 | 25 | do { 26 | tmpPhi.clear(); 27 | tmpReg.clear(); 28 | 29 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 30 | 31 | for (BasicBlock::iterator j = i->begin(); j != i->end(); ++j) { 32 | 33 | if (isa(j)) { 34 | PHINode *phi = cast(j); 35 | tmpPhi.push_back(phi); 36 | continue; 37 | } 38 | if (!(isa(j) && j->getParent() == bbEntry) && 39 | (valueEscapes(&*j) || j->isUsedOutsideOfBlock(&*i))) { 40 | tmpReg.push_back(&*j); 41 | continue; 42 | } 43 | } 44 | } 45 | for (unsigned int i = 0; i != tmpReg.size(); ++i) { 46 | DemoteRegToStack(*tmpReg.at(i), f->begin()->getTerminator()); 47 | } 48 | 49 | for (unsigned int i = 0; i != tmpPhi.size(); ++i) { 50 | DemotePHIToStack(tmpPhi.at(i), f->begin()->getTerminator()); 51 | } 52 | 53 | } while (tmpReg.size() != 0 || tmpPhi.size() != 0); 54 | } 55 | 56 | std::string readAnnotate(Function *f) { 57 | std::string annotation = ""; 58 | 59 | // Get annotation variable 60 | GlobalVariable *glob = 61 | f->getParent()->getGlobalVariable("llvm.global.annotations"); 62 | 63 | if (glob != NULL) { 64 | // Get the array 65 | if (ConstantArray *ca = dyn_cast(glob->getInitializer())) { 66 | for (unsigned i = 0; i < ca->getNumOperands(); ++i) { 67 | // Get the struct 68 | if (ConstantStruct *structAn = 69 | dyn_cast(ca->getOperand(i))) { 70 | if (ConstantExpr *expr = 71 | dyn_cast(structAn->getOperand(0))) { 72 | // If it's a bitcast we can check if the annotation is concerning 73 | // the current function 74 | if (expr->getOpcode() == Instruction::BitCast && 75 | expr->getOperand(0) == f) { 76 | ConstantExpr *note = cast(structAn->getOperand(1)); 77 | // If it's a GetElementPtr, that means we found the variable 78 | // containing the annotations 79 | if (note->getOpcode() == Instruction::GetElementPtr) { 80 | if (GlobalVariable *annoteStr = 81 | dyn_cast(note->getOperand(0))) { 82 | if (ConstantDataSequential *data = 83 | dyn_cast( 84 | annoteStr->getInitializer())) { 85 | if (data->isString()) { 86 | annotation += data->getAsString().lower() + " "; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | return annotation; 98 | } 99 | 100 | bool toObfuscate(bool flag, Function *f, std::string attribute) { 101 | std::string attr = attribute; 102 | std::string attrNo = "no" + attr; 103 | 104 | // Check if declaration 105 | if (f->isDeclaration()) { 106 | return false; 107 | } 108 | 109 | // Check external linkage 110 | if(f->hasAvailableExternallyLinkage() != 0) { 111 | return false; 112 | } 113 | 114 | // We have to check the nofla flag first 115 | // Because .find("fla") is true for a string like "fla" or 116 | // "nofla" 117 | if (readAnnotate(f).find(attrNo) != std::string::npos) { 118 | return false; 119 | } 120 | 121 | // If fla annotations 122 | if (readAnnotate(f).find(attr) != std::string::npos) { 123 | return true; 124 | } 125 | 126 | // If fla flag is set 127 | if (flag == true) { 128 | /* Check if the number of applications is correct 129 | if (!((Percentage > 0) && (Percentage <= 100))) { 130 | LLVMContext &ctx = llvm::getGlobalContext(); 131 | ctx.emitError(Twine("Flattening application function\ 132 | percentage -perFLA=x must be 0 < x <= 100")); 133 | } 134 | // Check name 135 | else if (func.size() != 0 && func.find(f->getName()) != std::string::npos) { 136 | return true; 137 | } 138 | 139 | if ((((int)llvm::cryptoutils->get_range(100))) < Percentage) { 140 | return true; 141 | } 142 | */ 143 | return true; 144 | } 145 | 146 | return false; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /ollvm/include/Transforms/Obfuscation/BogusControlFlow.h: -------------------------------------------------------------------------------- 1 | //===- BogusControlFlow.h - BogusControlFlow Obfuscation pass-------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===--------------------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the bogusControlFlow pass 11 | // 12 | //===--------------------------------------------------------------------------------===// 13 | 14 | #ifndef _BOGUSCONTROLFLOW_H_ 15 | #define _BOGUSCONTROLFLOW_H_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Module.h" 21 | #include "llvm/IR/Function.h" 22 | #include "llvm/IR/BasicBlock.h" 23 | #include "llvm/IR/Instructions.h" 24 | #include "llvm/IR/InstrTypes.h" 25 | #include "llvm/IR/Constants.h" 26 | #include "llvm/IR/Type.h" 27 | #include "llvm/ADT/Statistic.h" 28 | #include "llvm/IR/GlobalValue.h" 29 | #include "llvm/IR/LLVMContext.h" 30 | #include "llvm/Transforms/Utils/Cloning.h" 31 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 32 | #include "llvm/CodeGen/ISDOpcodes.h" 33 | #include "llvm/Support/raw_ostream.h" 34 | #include "llvm/Support/Debug.h" 35 | #include "llvm/Support/CommandLine.h" 36 | #include "llvm/Transforms/IPO.h" 37 | #include "llvm/CryptoUtils.h" 38 | #include 39 | 40 | using namespace std; 41 | using namespace llvm; 42 | 43 | // Namespace 44 | namespace llvm { 45 | Pass *createBogus (); 46 | Pass *createBogus (bool flag); 47 | } 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /ollvm/include/Transforms/Obfuscation/Flattening.h: -------------------------------------------------------------------------------- 1 | //===- FlatteningIncludes.h - Flattening Obfuscation pass------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the flattening pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _FLATTENING_INCLUDES_ 15 | #define _FLATTENING_INCLUDES_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Function.h" 21 | #include "llvm/ADT/Statistic.h" 22 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/Transforms/Scalar.h" 25 | #include "llvm/IR/Module.h" 26 | #include "llvm/Support/CommandLine.h" 27 | #include "llvm/CryptoUtils.h" 28 | #include "llvm/Transforms/Utils.h" 29 | 30 | // Namespace 31 | using namespace std; 32 | 33 | namespace llvm { 34 | Pass *createFlattening(); 35 | Pass *createFlattening(bool flag); 36 | } 37 | 38 | #endif 39 | 40 | -------------------------------------------------------------------------------- /ollvm/include/Transforms/Obfuscation/Split.h: -------------------------------------------------------------------------------- 1 | //===- FlatteningIncludes.h - Flattening Obfuscation pass------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the split basicblock pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _SPLIT_INCLUDES_ 15 | #define _SPLIT_INCLUDES_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/BasicBlock.h" 21 | #include "llvm/ADT/Statistic.h" 22 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/Transforms/Scalar.h" 25 | #include "llvm/IR/Module.h" 26 | #include "llvm/Support/CommandLine.h" 27 | #include "Transforms/Obfuscation/Utils.h" 28 | #include "llvm/CryptoUtils.h" 29 | 30 | // Namespace 31 | namespace llvm { 32 | Pass *createSplitBasicBlock(bool flag); 33 | } 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /ollvm/include/Transforms/Obfuscation/Substitution.h: -------------------------------------------------------------------------------- 1 | //===- SubstitutionIncludes.h - Substitution Obfuscation pass-------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains includes and defines for the substitution pass 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef _SUBSTITUTIONS_H_ 15 | #define _SUBSTITUTIONS_H_ 16 | 17 | 18 | // LLVM include 19 | #include "llvm/Pass.h" 20 | #include "llvm/IR/Function.h" 21 | #include "llvm/IR/Instructions.h" 22 | #include "llvm/ADT/Statistic.h" 23 | #include "llvm/Transforms/IPO.h" 24 | #include "llvm/IR/Module.h" 25 | #include "llvm/Support/CommandLine.h" 26 | #include "llvm/CryptoUtils.h" 27 | 28 | // Namespace 29 | using namespace llvm; 30 | using namespace std; 31 | 32 | namespace llvm { 33 | Pass *createSubstitution (); 34 | Pass *createSubstitution (bool flag); 35 | } 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /ollvm/include/Transforms/Obfuscation/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_OBF__ 2 | #define __UTILS_OBF__ 3 | 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | void fixStack(Function *f); 12 | std::string readAnnotate(Function *f); 13 | bool toObfuscate(bool flag, Function *f, std::string attribute); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /ollvm/include/llvm/CryptoUtils.h: -------------------------------------------------------------------------------- 1 | //===- CryptoUtils.h - Cryptographically Secure Pseudo-Random 2 | // Generator------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | // 11 | // This file contains includes and defines for the AES CTR PRNG 12 | // The AES implementation has been derived and adapted 13 | // from libtomcrypt (see http://libtom.org) 14 | // Created on: 22 juin 2012 15 | // Author(s): jrinaldini, pjunod 16 | //===----------------------------------------------------------------------===// 17 | 18 | #ifndef LLVM_CryptoUtils_H 19 | #define LLVM_CryptoUtils_H 20 | 21 | #include "llvm/Support/ManagedStatic.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace llvm { 28 | 29 | class CryptoUtils; 30 | extern ManagedStatic cryptoutils; 31 | 32 | #define BYTE(x, n) (((x) >> (8 * (n))) & 0xFF) 33 | 34 | #if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 35 | defined(INTEL_CC) 36 | 37 | #ifndef ENDIAN_LITTLE 38 | #define ENDIAN_LITTLE 39 | #endif 40 | #define ENDIAN_32BITWORD 41 | #define UNALIGNED 42 | 43 | #elif defined(__alpha) 44 | 45 | #ifndef ENDIAN_LITTLE 46 | #define ENDIAN_LITTLE 47 | #endif 48 | #define ENDIAN_64BITWORD 49 | 50 | #elif defined(__x86_64__) 51 | 52 | #ifndef ENDIAN_LITTLE 53 | #define ENDIAN_LITTLE 54 | #endif 55 | #define ENDIAN_64BITWORD 56 | #define UNALIGNED 57 | 58 | #elif(defined(__R5900) || defined(R5900) || defined(__R5900__)) && \ 59 | (defined(_mips) || defined(__mips__) || defined(mips)) 60 | 61 | #ifndef ENDIAN_LITTLE 62 | #define ENDIAN_LITTLE 63 | #endif 64 | #define ENDIAN_64BITWORD 65 | 66 | #elif defined(__sparc) 67 | 68 | #ifndef ENDIAN_BIG 69 | #define ENDIAN_BIG 70 | #endif 71 | #if defined(__arch64__) 72 | #define ENDIAN_64BITWORD 73 | #else 74 | #define ENDIAN_32BITWORD 75 | #endif 76 | 77 | #endif 78 | 79 | #if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) 80 | #define ENDIAN_BIG 81 | #endif 82 | 83 | #if !defined(ENDIAN_BIG) && !defined(ENDIAN_LITTLE) 84 | #error \ 85 | "Unknown endianness of the compilation platform, check this header aes_encrypt.h" 86 | #endif 87 | 88 | #ifdef ENDIAN_LITTLE 89 | 90 | #define STORE32H(y, x) \ 91 | { \ 92 | (y)[0] = (uint8_t)(((x) >> 24) & 0xFF); \ 93 | (y)[1] = (uint8_t)(((x) >> 16) & 0xFF); \ 94 | (y)[2] = (uint8_t)(((x) >> 8) & 0xFF); \ 95 | (y)[3] = (uint8_t)(((x) >> 0) & 0xFF); \ 96 | } 97 | #define LOAD32H(x, y) \ 98 | { \ 99 | (x) = ((uint32_t)((y)[0] & 0xFF) << 24) | \ 100 | ((uint32_t)((y)[1] & 0xFF) << 16) | \ 101 | ((uint32_t)((y)[2] & 0xFF) << 8) | ((uint32_t)((y)[3] & 0xFF) << 0); \ 102 | } 103 | 104 | #define LOAD64H(x, y) \ 105 | { \ 106 | (x) = ((uint64_t)((y)[0] & 0xFF) << 56) | \ 107 | ((uint64_t)((y)[1] & 0xFF) << 48) | \ 108 | ((uint64_t)((y)[2] & 0xFF) << 40) | \ 109 | ((uint64_t)((y)[3] & 0xFF) << 32) | \ 110 | ((uint64_t)((y)[4] & 0xFF) << 24) | \ 111 | ((uint64_t)((y)[5] & 0xFF) << 16) | \ 112 | ((uint64_t)((y)[6] & 0xFF) << 8) | ((uint64_t)((y)[7] & 0xFF) << 0); \ 113 | } 114 | 115 | #define STORE64H(y, x) \ 116 | { \ 117 | (y)[0] = (uint8_t)(((x) >> 56) & 0xFF); \ 118 | (y)[1] = (uint8_t)(((x) >> 48) & 0xFF); \ 119 | (y)[2] = (uint8_t)(((x) >> 40) & 0xFF); \ 120 | (y)[3] = (uint8_t)(((x) >> 32) & 0xFF); \ 121 | (y)[4] = (uint8_t)(((x) >> 24) & 0xFF); \ 122 | (y)[5] = (uint8_t)(((x) >> 16) & 0xFF); \ 123 | (y)[6] = (uint8_t)(((x) >> 8) & 0xFF); \ 124 | (y)[7] = (uint8_t)(((x) >> 0) & 0xFF); \ 125 | } 126 | 127 | #endif /* ENDIAN_LITTLE */ 128 | 129 | #ifdef ENDIAN_BIG 130 | 131 | #define STORE32H(y, x) \ 132 | { \ 133 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 134 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 135 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 136 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 137 | } 138 | #define STORE64H(y, x) \ 139 | { \ 140 | (y)[7] = (uint8_t)(((x) >> 56) & 0xFF); \ 141 | (y)[6] = (uint8_t)(((x) >> 48) & 0xFF); \ 142 | (y)[5] = (uint8_t)(((x) >> 40) & 0xFF); \ 143 | (y)[4] = (uint8_t)(((x) >> 32) & 0xFF); \ 144 | (y)[3] = (uint8_t)(((x) >> 24) & 0xFF); \ 145 | (y)[2] = (uint8_t)(((x) >> 16) & 0xFF); \ 146 | (y)[1] = (uint8_t)(((x) >> 8) & 0xFF); \ 147 | (y)[0] = (uint8_t)(((x) >> 0) & 0xFF); \ 148 | } 149 | #define LOAD32H(x, y) \ 150 | { \ 151 | (x) = ((uint32_t)((y)[3] & 0xFF) << 24) | \ 152 | ((uint32_t)((y)[2] & 0xFF) << 16) | \ 153 | ((uint32_t)((y)[1] & 0xFF) << 8) | ((uint32_t)((y)[0] & 0xFF) << 0); \ 154 | } 155 | 156 | #define LOAD64H(x, y) \ 157 | { \ 158 | (x) = ((uint64_t)((y)[7] & 0xFF) << 56) | \ 159 | ((uint64_t)((y)[6] & 0xFF) << 48) | \ 160 | ((uint64_t)((y)[5] & 0xFF) << 40) | \ 161 | ((uint64_t)((y)[4] & 0xFF) << 32) | \ 162 | ((uint64_t)((y)[3] & 0xFF) << 24) | \ 163 | ((uint64_t)((y)[2] & 0xFF) << 16) | \ 164 | ((uint64_t)((y)[1] & 0xFF) << 8) | ((uint64_t)((y)[0] & 0xFF) << 0); \ 165 | } 166 | 167 | #endif /* ENDIAN_BIG */ 168 | 169 | #define AES_TE0(x) AES_PRECOMP_TE0[(x)] 170 | #define AES_TE1(x) AES_PRECOMP_TE1[(x)] 171 | #define AES_TE2(x) AES_PRECOMP_TE2[(x)] 172 | #define AES_TE3(x) AES_PRECOMP_TE3[(x)] 173 | 174 | #define AES_TE4_0(x) AES_PRECOMP_TE4_0[(x)] 175 | #define AES_TE4_1(x) AES_PRECOMP_TE4_1[(x)] 176 | #define AES_TE4_2(x) AES_PRECOMP_TE4_2[(x)] 177 | #define AES_TE4_3(x) AES_PRECOMP_TE4_3[(x)] 178 | 179 | #define CryptoUtils_POOL_SIZE (0x1 << 17) // 2^17 180 | 181 | #define DUMP(x, l, s) \ 182 | fprintf(stderr, "%s :", (s)); \ 183 | for (int ii = 0; ii < (l); ii++) { \ 184 | fprintf(stderr, "%02hhX", *((x) + ii)); \ 185 | } \ 186 | fprintf(stderr, "\n"); 187 | 188 | // SHA256 189 | /* Various logical functions */ 190 | #define Ch(x, y, z) (z ^ (x &(y ^ z))) 191 | #define Maj(x, y, z) (((x | y) & z) | (x &y)) 192 | #define __S(x, n) RORc((x), (n)) 193 | #define R1(x, n) (((x) & 0xFFFFFFFFUL) >> (n)) 194 | #define Sigma0(x) (__S(x, 2) ^ __S(x, 13) ^ __S(x, 22)) 195 | #define Sigma1(x) (__S(x, 6) ^ __S(x, 11) ^ __S(x, 25)) 196 | #define Gamma0(x) (__S(x, 7) ^ __S(x, 18) ^ R1(x, 3)) 197 | #define Gamma1(x) (__S(x, 17) ^ __S(x, 19) ^ R1(x, 10)) 198 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 199 | 200 | #define RND(a, b, c, d, e, f, g, h, i, ki) \ 201 | t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ 202 | t1 = Sigma0(a) + Maj(a, b, c); \ 203 | d += t0; \ 204 | h = t0 + t1; 205 | 206 | #define RORc(x, y) \ 207 | (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \ 208 | ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & \ 209 | 0xFFFFFFFFUL) 210 | 211 | class CryptoUtils { 212 | public: 213 | CryptoUtils(); 214 | ~CryptoUtils(); 215 | 216 | char *get_seed(); 217 | void get_bytes(char *buffer, const int len); 218 | char get_char(); 219 | bool prng_seed(const std::string seed); 220 | 221 | // Returns a uniformly distributed 8-bit value 222 | uint8_t get_uint8_t(); 223 | // Returns a uniformly distributed 32-bit value 224 | uint32_t get_uint32_t(); 225 | // Returns an integer uniformly distributed on [0, max[ 226 | uint32_t get_range(const uint32_t max); 227 | // Returns a uniformly distributed 64-bit value 228 | uint64_t get_uint64_t(); 229 | 230 | // Scramble a 32-bit value depending on a 128-bit value 231 | unsigned scramble32(const unsigned in, const char key[16]); 232 | 233 | int sha256(const char *msg, unsigned char *hash); 234 | 235 | private: 236 | uint32_t ks[44]; 237 | char key[16]; 238 | char ctr[16]; 239 | char pool[CryptoUtils_POOL_SIZE]; 240 | uint32_t idx; 241 | std::string seed; 242 | bool seeded; 243 | 244 | typedef struct { 245 | uint64_t length; 246 | uint32_t state[8], curlen; 247 | unsigned char buf[64]; 248 | } sha256_state; 249 | 250 | void aes_compute_ks(uint32_t *ks, const char *k); 251 | void aes_encrypt(char *out, const char *in, const uint32_t *ks); 252 | bool prng_seed(); 253 | void inc_ctr(); 254 | void populate_pool(); 255 | int sha256_done(sha256_state *md, unsigned char *out); 256 | int sha256_init(sha256_state *md); 257 | static int sha256_compress(sha256_state *md, unsigned char *buf); 258 | int sha256_process(sha256_state *md, const unsigned char *in, 259 | unsigned long inlen); 260 | }; 261 | } 262 | 263 | #endif // LLVM_CryptoUtils_H 264 | 265 | -------------------------------------------------------------------------------- /skeleton/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(SkeletonPass MODULE 2 | # List your source files here. 3 | Skeleton.cpp 4 | ) 5 | 6 | # Use C++11 to compile your pass (i.e., supply -std=c++11). 7 | target_compile_features(SkeletonPass PRIVATE cxx_range_for cxx_auto_type) 8 | 9 | # LLVM is (typically) built with no C++ RTTI. We need to match that; 10 | # otherwise, we'll get linker errors about missing RTTI data. 11 | set_target_properties(SkeletonPass PROPERTIES 12 | COMPILE_FLAGS "-fno-rtti" 13 | ) 14 | 15 | # Get proper shared-library behavior (where symbols are not necessarily 16 | # resolved when the shared library is linked) on OS X. 17 | if(APPLE) 18 | set_target_properties(SkeletonPass PROPERTIES 19 | LINK_FLAGS "-undefined dynamic_lookup" 20 | ) 21 | endif(APPLE) 22 | -------------------------------------------------------------------------------- /skeleton/Skeleton.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm/Pass.h" 2 | #include "llvm/IR/Function.h" 3 | #include "llvm/Passes/PassBuilder.h" 4 | #include "llvm/Passes/PassPlugin.h" 5 | #include "llvm/Support/raw_ostream.h" 6 | #include "llvm/IR/LegacyPassManager.h" 7 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 8 | 9 | using namespace llvm; 10 | 11 | namespace { 12 | struct SkeletonPass : public FunctionPass { 13 | static char ID; 14 | SkeletonPass() : FunctionPass(ID) {} 15 | 16 | virtual bool runOnFunction(Function &F) { 17 | errs() << "I saw a function called " << F.getName() << "!\n"; 18 | return false; 19 | } 20 | }; 21 | } 22 | 23 | char SkeletonPass::ID = 0; 24 | 25 | // Automatically enable the pass. 26 | // http://adriansampson.net/blog/clangpass.html 27 | static void registerSkeletonPass(const PassManagerBuilder &, 28 | legacy::PassManagerBase &PM) { 29 | PM.add(new SkeletonPass()); 30 | } 31 | static RegisterStandardPasses 32 | RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 33 | registerSkeletonPass); 34 | 35 | #if LLVM_VERSION_MAJOR >= 13 36 | 37 | struct NewSkeletonPass : PassInfoMixin { 38 | public: 39 | static bool isRequired() { 40 | errs() << "isRequired invoked\n"; 41 | return true; 42 | } 43 | 44 | static PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { 45 | errs() << "Module name is " << M.getName() << "!\n"; 46 | return PreservedAnalyses::all(); 47 | } 48 | }; 49 | 50 | void myCallback(llvm::ModulePassManager &PM, llvm::PassBuilder::OptimizationLevel Level) { 51 | PM.addPass(NewSkeletonPass()); 52 | } 53 | 54 | /* New PM Registration */ 55 | extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo 56 | llvmGetPassPluginInfo() { 57 | errs() << "llvmGetPassPluginInfo\n"; 58 | return {LLVM_PLUGIN_API_VERSION, 59 | "skeleton", 60 | LLVM_VERSION_STRING, 61 | [](PassBuilder &PB) { 62 | PB.registerPipelineStartEPCallback(myCallback); 63 | // TODO: handle opt 64 | // PB.registerPipelineParsingCallback 65 | }}; 66 | } 67 | #endif --------------------------------------------------------------------------------