├── .gitignore ├── AntiClassDump.cpp ├── BogusControlFlow.cpp ├── CMakeLists.txt ├── CryptoUtils.cpp ├── Flattening.cpp ├── FunctionCallObfuscate.cpp ├── FunctionWrapper.cpp ├── IndirectBranch.cpp ├── LLVMBuild.txt ├── Obfuscation.cpp ├── README.md ├── SplitBasicBlocks.cpp ├── StringEncryption.cpp ├── Substitution.cpp ├── Utils.cpp └── json.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /AntiClassDump.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | /* 4 | For maximum usability. We provide two modes for this pass, as defined in 5 | llvm/Transforms/Obfuscation/AntiClassDump.h THIN mode is used on per-module 6 | basis without LTO overhead and structs are left in the module where possible. 7 | This is particularly useful for cases where LTO is not possible. For example 8 | static library. Full mode is used at LTO stage, this mode constructs 9 | dependency graph and perform full wipe-out as well as llvm.global_ctors 10 | injection. 11 | This pass only provides thin mode 12 | */ 13 | 14 | #include "llvm/ADT/Triple.h" 15 | #include "llvm/IR/Constants.h" 16 | #include "llvm/IR/IRBuilder.h" 17 | #include "llvm/IR/InlineAsm.h" 18 | #include "llvm/IR/Instructions.h" 19 | #include "llvm/IR/Module.h" 20 | #include "llvm/IR/Value.h" 21 | #include "llvm/Pass.h" 22 | #include "llvm/Support/CommandLine.h" 23 | #include "llvm/Support/raw_ostream.h" 24 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 25 | #include "llvm/Transforms/Utils/ModuleUtils.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | using namespace llvm; 33 | using namespace std; 34 | static cl::opt 35 | UseInitialize("acd-use-initialize", cl::init(true), cl::NotHidden, 36 | cl::desc("[AntiClassDump]Inject codes to +initialize")); 37 | namespace llvm { 38 | struct AntiClassDump : public ModulePass { 39 | static char ID; 40 | AntiClassDump() : ModulePass(ID) {} 41 | StringRef getPassName() const override { return StringRef("AntiClassDump"); } 42 | virtual bool doInitialization(Module &M) override { 43 | // Basic Defs 44 | Triple tri(M.getTargetTriple()); 45 | if (tri.getVendor() != Triple::VendorType::Apple) { 46 | // We only support AAPL's ObjC Implementation ATM 47 | errs() 48 | << M.getTargetTriple() 49 | << " is Not Supported For LLVM AntiClassDump\nProbably GNU Step?\n"; 50 | return false; 51 | } 52 | Type *Int64Ty = Type::getInt64Ty(M.getContext()); 53 | Type *Int32Ty = Type::getInt32Ty(M.getContext()); 54 | Type *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); 55 | Type *Int8Ty = Type::getInt8Ty(M.getContext()); 56 | // Generic ObjC Runtime Declarations 57 | FunctionType *IMPType = 58 | FunctionType::get(Int8PtrTy, {Int8PtrTy, Int8PtrTy}, true); 59 | PointerType *IMPPointerType = PointerType::get(IMPType, 0); 60 | vector classReplaceMethodTypeArgs; 61 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 62 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 63 | classReplaceMethodTypeArgs.push_back(IMPPointerType); 64 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 65 | FunctionType *class_replaceMethod_type = 66 | FunctionType::get(IMPPointerType, classReplaceMethodTypeArgs, false); 67 | M.getOrInsertFunction("class_replaceMethod", class_replaceMethod_type); 68 | FunctionType *sel_registerName_type = 69 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 70 | M.getOrInsertFunction("sel_registerName", sel_registerName_type); 71 | FunctionType *objc_getClass_type = 72 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 73 | M.getOrInsertFunction("objc_getClass", objc_getClass_type); 74 | M.getOrInsertFunction("objc_getMetaClass", objc_getClass_type); 75 | StructType *objc_property_attribute_t_type = reinterpret_cast( 76 | M.getTypeByName("struct.objc_property_attribute_t")); 77 | if (objc_property_attribute_t_type == NULL) { 78 | vector types; 79 | types.push_back(Int8PtrTy); 80 | types.push_back(Int8PtrTy); 81 | objc_property_attribute_t_type = StructType::create( 82 | ArrayRef(types), "struct.objc_property_attribute_t"); 83 | M.getOrInsertGlobal("struct.objc_property_attribute_t", 84 | objc_property_attribute_t_type); 85 | } 86 | vector allocaClsTypeVector; 87 | vector addIvarTypeVector; 88 | vector addPropTypeVector; 89 | allocaClsTypeVector.push_back(Int8PtrTy); 90 | allocaClsTypeVector.push_back(Int8PtrTy); 91 | addIvarTypeVector.push_back(Int8PtrTy); 92 | addIvarTypeVector.push_back(Int8PtrTy); 93 | addPropTypeVector.push_back(Int8PtrTy); 94 | addPropTypeVector.push_back(Int8PtrTy); 95 | addPropTypeVector.push_back(objc_property_attribute_t_type->getPointerTo()); 96 | if (tri.isArch64Bit()) { 97 | // We are 64Bit Device 98 | allocaClsTypeVector.push_back(Int64Ty); 99 | addIvarTypeVector.push_back(Int64Ty); 100 | addPropTypeVector.push_back(Int64Ty); 101 | } else { 102 | // Not 64Bit.However we are still on apple platform.So We are 103 | // ARMV7/ARMV7S/i386 104 | // PowerPC is ignored, feel free to open a PR if you want to 105 | allocaClsTypeVector.push_back(Int32Ty); 106 | addIvarTypeVector.push_back(Int32Ty); 107 | addPropTypeVector.push_back(Int32Ty); 108 | } 109 | addIvarTypeVector.push_back(Int8Ty); 110 | addIvarTypeVector.push_back(Int8PtrTy); 111 | // Types Collected. Now Inject Functions 112 | FunctionType *addIvarType = 113 | FunctionType::get(Int8Ty, ArrayRef(addIvarTypeVector), false); 114 | M.getOrInsertFunction("class_addIvar", addIvarType); 115 | FunctionType *addPropType = 116 | FunctionType::get(Int8Ty, ArrayRef(addPropTypeVector), false); 117 | M.getOrInsertFunction("class_addProperty", addPropType); 118 | FunctionType *class_getName_Type = 119 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 120 | M.getOrInsertFunction("class_getName", class_getName_Type); 121 | FunctionType *objc_getMetaClass_Type = 122 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 123 | M.getOrInsertFunction("objc_getMetaClass", objc_getMetaClass_Type); 124 | return true; 125 | } 126 | bool runOnModule(Module &M) override { 127 | errs() << "Running AntiClassDump On " << M.getSourceFileName() << "\n"; 128 | GlobalVariable *OLCGV = M.getGlobalVariable("OBJC_LABEL_CLASS_$", true); 129 | if (OLCGV == NULL) { 130 | errs() << "No ObjC Class Found in :" << M.getSourceFileName() << "\n"; 131 | // No ObjC class found. 132 | return false; 133 | } 134 | /*// Create our own Initializer 135 | FunctionType *InitializerType = FunctionType::get( 136 | Type::getVoidTy(M.getContext()), ArrayRef(), false); 137 | Function *Initializer = Function::Create( 138 | InitializerType, GlobalValue::LinkageTypes::PrivateLinkage, "", &M); 139 | BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "", Initializer); 140 | // 141 | IRBuilder<> IRB(EntryBB); 142 | IRB.CreateRetVoid();*/ 143 | assert(OLCGV->hasInitializer() && 144 | "OBJC_LABEL_CLASS_$ Doesn't Have Initializer."); 145 | ConstantArray *OBJC_LABEL_CLASS_CDS = 146 | dyn_cast(OLCGV->getInitializer()); 147 | 148 | assert(OBJC_LABEL_CLASS_CDS && 149 | "OBJC_LABEL_CLASS_$ Not ConstantArray.Is the target using " 150 | "unsupported legacy runtime?"); 151 | vector readyclses; // This is for storing classes that can be used 152 | // in handleClass() 153 | deque tmpclses; // This is temporary storage for classes 154 | map dependency; 155 | map 156 | GVMapping; // Map ClassName to corresponding GV 157 | for (unsigned i = 0; i < OBJC_LABEL_CLASS_CDS->getNumOperands(); i++) { 158 | ConstantExpr *clsEXPR = 159 | dyn_cast(OBJC_LABEL_CLASS_CDS->getOperand(i)); 160 | GlobalVariable *CEGV = dyn_cast(clsEXPR->getOperand(0)); 161 | ConstantStruct *clsCS = dyn_cast(CEGV->getInitializer()); 162 | /* 163 | First Operand MetaClass. 164 | Second Operand SuperClass 165 | Fifth Operand ClassRO 166 | */ 167 | GlobalVariable *SuperClassGV = 168 | (clsCS->getOperand(1) == NULL) 169 | ? NULL 170 | : dyn_cast(clsCS->getOperand(1)); 171 | string supclsName = ""; 172 | string clsName = CEGV->getName().str(); 173 | clsName.replace(clsName.find("OBJC_CLASS_$_"), strlen("OBJC_CLASS_$_"), 174 | ""); 175 | 176 | if (SuperClassGV != 177 | NULL) { // We need to handle Classed that doesn't have a base 178 | supclsName = SuperClassGV->getName().str(); 179 | supclsName.replace(supclsName.find("OBJC_CLASS_$_"), 180 | strlen("OBJC_CLASS_$_"), ""); 181 | } 182 | dependency[clsName] = supclsName; 183 | GVMapping[clsName] = CEGV; 184 | if (supclsName == "" /*NULL Super Class*/ || 185 | (SuperClassGV != NULL && 186 | !SuperClassGV->hasInitializer() /*External Super Class*/)) { 187 | readyclses.push_back(clsName); 188 | } else { 189 | tmpclses.push_back(clsName); 190 | } 191 | } 192 | // Sort Initialize Sequence Based On Dependency 193 | while (tmpclses.size() > 0) { 194 | string clstmp = tmpclses.front(); 195 | tmpclses.pop_front(); 196 | string SuperClassName = dependency[clstmp]; 197 | if (SuperClassName != "" && 198 | std::find(readyclses.begin(), readyclses.end(), SuperClassName) == 199 | readyclses.end()) { 200 | // SuperClass is unintialized non-null class.Push back and waiting until 201 | // baseclass is allocated 202 | tmpclses.push_back(clstmp); 203 | } else { 204 | // BaseClass Ready. Push into ReadyClasses 205 | readyclses.push_back(clstmp); 206 | } 207 | } 208 | 209 | // Now run handleClass for each class 210 | for (string className : readyclses) { 211 | handleClass(GVMapping[className], &M); 212 | } 213 | return true; 214 | } // runOnModule 215 | map 216 | splitclass_ro_t(ConstantStruct *class_ro, 217 | Module *M) { // Split a class_ro_t structure 218 | map info; 219 | StructType *objc_method_list_t_type = 220 | M->getTypeByName("struct.__method_list_t"); 221 | StructType *ivar_list_t_type = M->getTypeByName("struct._ivar_list_t"); 222 | StructType *property_list_t_type = M->getTypeByName("struct._prop_list_t"); 223 | for (unsigned i = 0; i < class_ro->getType()->getNumElements(); i++) { 224 | Constant *tmp = dyn_cast(class_ro->getAggregateElement(i)); 225 | if (tmp->isNullValue()) { 226 | continue; 227 | } 228 | Type *type = tmp->getType(); 229 | if (type == ivar_list_t_type->getPointerTo()) { 230 | info["IVARLIST"] = cast(tmp); 231 | } else if (type == property_list_t_type->getPointerTo()) { 232 | info["PROPLIST"] = cast(tmp); 233 | } else if (type == objc_method_list_t_type->getPointerTo()) { 234 | // Insert Methods 235 | ConstantExpr *methodListCE = cast(tmp); 236 | // Note:methodListCE is also a BitCastConstantExpr 237 | GlobalVariable *methodListGV = 238 | cast(methodListCE->getOperand(0)); 239 | // Now BitCast is stripped out. 240 | assert(methodListGV->hasInitializer() && 241 | "MethodListGV doesn't have initializer"); 242 | ConstantStruct *methodListStruct = 243 | cast(methodListGV->getInitializer()); 244 | // Extracting %struct._objc_method array from %struct.__method_list_t = 245 | // type { i32, i32, [0 x %struct._objc_method] } 246 | info["METHODLIST"] = 247 | cast(methodListStruct->getOperand(2)); 248 | } 249 | } 250 | return info; 251 | } // splitclass_ro_t 252 | void handleClass(GlobalVariable *GV, Module *M) { 253 | assert(GV->hasInitializer() && 254 | "ObjC Class Structure's Initializer Missing"); 255 | ConstantStruct *CS = dyn_cast(GV->getInitializer()); 256 | StringRef ClassName = GV->getName(); 257 | ClassName = ClassName.substr(strlen("OBJC_CLASS_$_")); 258 | StringRef SuperClassName = CS->getOperand(1)->getName(); 259 | SuperClassName = SuperClassName.substr(strlen("OBJC_CLASS_$_")); 260 | errs() << "Handling Class:" << ClassName 261 | << " With SuperClass:" << SuperClassName << "\n"; 262 | 263 | // Let's extract stuffs 264 | // struct _class_t { 265 | // struct _class_t *isa; 266 | // struct _class_t * const superclass; 267 | // void *cache; 268 | // IMP *vtable; 269 | // struct class_ro_t *ro; 270 | // } 271 | GlobalVariable *metaclassGV = cast(CS->getOperand(0)); 272 | GlobalVariable *class_ro = cast(CS->getOperand(4)); 273 | assert(metaclassGV->hasInitializer() && "MetaClass GV Initializer Missing"); 274 | GlobalVariable *metaclass_ro = 275 | cast(metaclassGV->getInitializer()->getOperand( 276 | metaclassGV->getInitializer()->getNumOperands() - 1)); 277 | IRBuilder<> *IRB = NULL; 278 | // Begin IRBuilder Initializing 279 | map Info = splitclass_ro_t( 280 | cast(metaclass_ro->getInitializer()), M); 281 | BasicBlock *EntryBB = NULL; 282 | if (Info.find("METHODLIST") != Info.end()) { 283 | ConstantArray *method_list = cast(Info["METHODLIST"]); 284 | for (unsigned i = 0; i < method_list->getNumOperands(); i++) { 285 | ConstantStruct *methodStruct = 286 | cast(method_list->getOperand(i)); 287 | // methodStruct has type %struct._objc_method = type { i8*, i8*, i8* } 288 | // which contains {GEP(NAME),GEP(TYPE),BitCast(IMP)} 289 | // Let's extract these info now 290 | // methodStruct->getOperand(0)->getOperand(0) is SELName 291 | GlobalVariable *SELNameGV = 292 | cast(methodStruct->getOperand(0)->getOperand(0)); 293 | ConstantDataSequential *SELNameCDS = 294 | cast(SELNameGV->getInitializer()); 295 | StringRef selname = SELNameCDS->getAsCString(); 296 | if ((selname == StringRef("initialize") && UseInitialize) || 297 | (selname == StringRef("load") && !UseInitialize)) { 298 | Function *IMPFunc = 299 | cast(methodStruct->getOperand(2)->getOperand(0)); 300 | errs() << "Found Existing initializer\n"; 301 | EntryBB = &(IMPFunc->getEntryBlock()); 302 | } 303 | } 304 | } else { 305 | errs() << "Didn't Find ClassMethod List\n"; 306 | } 307 | bool NeedTerminator = false; 308 | if (EntryBB == NULL) { 309 | NeedTerminator = true; 310 | // We failed to find existing +initializer,create new one 311 | errs() << "Creating initializer\n"; 312 | FunctionType *InitializerType = FunctionType::get( 313 | Type::getVoidTy(M->getContext()), ArrayRef(), false); 314 | Function *Initializer = Function::Create( 315 | InitializerType, GlobalValue::LinkageTypes::PrivateLinkage, 316 | "AntiClassDumpInitializer", M); 317 | EntryBB = BasicBlock::Create(M->getContext(), "", Initializer); 318 | } 319 | if (NeedTerminator) { 320 | IRBuilder<> foo(EntryBB); 321 | foo.CreateRetVoid(); 322 | } 323 | IRB = new IRBuilder<>(EntryBB, EntryBB->getFirstInsertionPt()); 324 | // End IRBuilder Initializing 325 | // We now prepare ObjC API Definitions 326 | Function *objc_getClass = M->getFunction("objc_getClass"); 327 | // Type *Int8PtrTy = Type::getInt8PtrTy(M->getContext()); 328 | // End of ObjC API Definitions 329 | Value *ClassNameGV = IRB->CreateGlobalStringPtr(ClassName); 330 | // Now Scan For Props and Ivars in OBJC_CLASS_RO AND OBJC_METACLASS_RO 331 | // Note that class_ro_t's structure is different for 32 and 64bit runtime 332 | CallInst *Class = IRB->CreateCall(objc_getClass, {ClassNameGV}); 333 | // Add Methods 334 | ConstantStruct *metaclassCS = 335 | cast(class_ro->getInitializer()); 336 | ConstantStruct *classCS = 337 | cast(metaclass_ro->getInitializer()); 338 | if (!metaclassCS->getAggregateElement(5)->isNullValue()) { 339 | errs() << "Handling Instance Methods For Class:" << ClassName << "\n"; 340 | HandleMethods(metaclassCS, IRB, M, Class, false); 341 | 342 | errs() << "Updating Class Method Map For Class:" << ClassName << "\n"; 343 | Type *objc_method_type = M->getTypeByName("struct._objc_method"); 344 | ArrayType *AT = ArrayType::get(objc_method_type, 0); 345 | Constant *newMethodList = ConstantArray::get(AT, ArrayRef()); 346 | GlobalVariable *methodListGV = 347 | cast(metaclassCS->getAggregateElement(5)->getOperand( 348 | 0)); // is striped MethodListGV 349 | StructType *oldGVType = 350 | cast(methodListGV->getInitializer()->getType()); 351 | vector newStructType; 352 | vector newStructValue; 353 | // I'm fully aware that it's consistent Int32 on all platforms 354 | // This is future-proof 355 | newStructType.push_back(oldGVType->getElementType(0)); 356 | newStructValue.push_back( 357 | methodListGV->getInitializer()->getAggregateElement(0u)); 358 | newStructType.push_back(oldGVType->getElementType(1)); 359 | newStructValue.push_back( 360 | ConstantInt::get(oldGVType->getElementType(1), 0)); 361 | newStructType.push_back(AT); 362 | newStructValue.push_back(newMethodList); 363 | StructType *newType = 364 | StructType::get(M->getContext(), ArrayRef(newStructType)); 365 | Constant *newMethodStruct = ConstantStruct::get( 366 | newType, 367 | ArrayRef(newStructValue)); // l_OBJC_$_CLASS_METHODS_ 368 | GlobalVariable *newMethodStructGV = new GlobalVariable( 369 | *M, newType, true, GlobalValue::LinkageTypes::PrivateLinkage, 370 | newMethodStruct, "ACDNewInstanceMethodMap"); 371 | appendToCompilerUsed(*M, {newMethodStructGV}); 372 | newMethodStructGV->copyAttributesFrom(methodListGV); 373 | Constant *bitcastExpr = ConstantExpr::getBitCast( 374 | newMethodStructGV, 375 | M->getTypeByName("struct.__method_list_t")->getPointerTo()); 376 | metaclassCS->handleOperandChange(metaclassCS->getAggregateElement(5), 377 | bitcastExpr); 378 | methodListGV->replaceAllUsesWith(ConstantExpr::getBitCast( 379 | newMethodStructGV, 380 | methodListGV->getType())); // llvm.compiler.used doesn't allow 381 | // Null/Undef Value 382 | methodListGV->dropAllReferences(); 383 | methodListGV->eraseFromParent(); 384 | errs() << "Updated Instance Method Map of:" << class_ro->getName() 385 | << "\n"; 386 | } 387 | // MethodList has index of 5 388 | // We need to create a new type first then bitcast to required type later 389 | // Since the original type's contained arraytype has count of 0 390 | GlobalVariable *methodListGV = NULL; // is striped MethodListGV 391 | if (!classCS->getAggregateElement(5)->isNullValue()) { 392 | errs() << "Handling Class Methods For Class:" << ClassName << "\n"; 393 | HandleMethods(classCS, IRB, M, Class, true); 394 | methodListGV = 395 | cast(classCS->getAggregateElement(5)->getOperand(0)); 396 | } 397 | errs() << "Updating Class Method Map For Class:" << ClassName << "\n"; 398 | Type *objc_method_type = M->getTypeByName("struct._objc_method"); 399 | ArrayType *AT = ArrayType::get(objc_method_type, 1); 400 | Constant *MethName = NULL; 401 | if (UseInitialize) { 402 | MethName = cast(IRB->CreateGlobalStringPtr("initialize")); 403 | } else { 404 | MethName = cast(IRB->CreateGlobalStringPtr("load")); 405 | } 406 | // This method signature is generated by clang 407 | // See 408 | // http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?revision=320954&view=markup 409 | // ASTContext::getObjCEncodingForMethodDecl 410 | // The one hard-coded here is generated for macOS 64Bit 411 | Triple tri = Triple(M->getTargetTriple()); 412 | Constant *MethType = NULL; 413 | if (tri.isOSDarwin() && tri.isArch64Bit()) { 414 | MethType = cast(IRB->CreateGlobalStringPtr("v16@0:8")); 415 | } else if (tri.isOSDarwin() && tri.isArch32Bit()) { 416 | MethType = cast(IRB->CreateGlobalStringPtr("v8@0:4")); 417 | } else { 418 | errs() << "Unknown Platform.Blindly applying method signature for " 419 | "macOS 64Bit\n"; 420 | MethType = cast(IRB->CreateGlobalStringPtr("v16@0:8")); 421 | } 422 | Constant *BitCastedIMP = cast( 423 | IRB->CreateBitCast(IRB->GetInsertBlock()->getParent(), 424 | objc_getClass->getFunctionType()->getParamType(0))); 425 | vector methodStructContents; //{GEP(NAME),GEP(TYPE),IMP} 426 | methodStructContents.push_back(MethName); 427 | methodStructContents.push_back(MethType); 428 | methodStructContents.push_back(BitCastedIMP); 429 | Constant *newMethod = ConstantStruct::get( 430 | cast(objc_method_type), 431 | ArrayRef(methodStructContents)); // objc_method_t 432 | Constant *newMethodList = ConstantArray::get( 433 | AT, ArrayRef(newMethod)); // Container of objc_method_t 434 | vector newStructType; 435 | vector newStructValue; 436 | // I'm fully aware that it's consistent Int32 on all platforms 437 | // This is future-proof 438 | newStructType.push_back(Type::getInt32Ty(M->getContext())); 439 | newStructValue.push_back(ConstantInt::get(Type::getInt32Ty(M->getContext()), 440 | 0x18)); // 0x18 is extracted from 441 | // built-code on macOS.No 442 | // idea what does it mean 443 | newStructType.push_back(Type::getInt32Ty(M->getContext())); 444 | newStructValue.push_back(ConstantInt::get(Type::getInt32Ty(M->getContext()), 445 | 1)); // this is class count 446 | newStructType.push_back(AT); 447 | newStructValue.push_back(newMethodList); 448 | StructType *newType = 449 | StructType::get(M->getContext(), ArrayRef(newStructType)); 450 | Constant *newMethodStruct = ConstantStruct::get( 451 | newType, 452 | ArrayRef(newStructValue)); // l_OBJC_$_CLASS_METHODS_ 453 | GlobalVariable *newMethodStructGV = new GlobalVariable( 454 | *M, newType, true, GlobalValue::LinkageTypes::PrivateLinkage, 455 | newMethodStruct, "ACDNewInstanceMethodMap"); 456 | appendToCompilerUsed(*M, {newMethodStructGV}); 457 | if (methodListGV) { 458 | newMethodStructGV->copyAttributesFrom(methodListGV); 459 | } 460 | Constant *bitcastExpr = ConstantExpr::getBitCast( 461 | newMethodStructGV, 462 | M->getTypeByName("struct.__method_list_t")->getPointerTo()); 463 | classCS->handleOperandChange(classCS->getAggregateElement(5), bitcastExpr); 464 | if (methodListGV) { 465 | methodListGV->replaceAllUsesWith(ConstantExpr::getBitCast( 466 | newMethodStructGV, 467 | methodListGV->getType())); // llvm.compiler.used doesn't allow 468 | // Null/Undef Value 469 | methodListGV->dropAllReferences(); 470 | methodListGV->eraseFromParent(); 471 | } 472 | errs() << "Updated Class Method Map of:" << class_ro->getName() << "\n"; 473 | // End ClassCS Handling 474 | } // handleClass 475 | void HandleMethods(ConstantStruct *class_ro, IRBuilder<> *IRB, Module *M, 476 | Value *Class, bool isMetaClass) { 477 | Function *sel_registerName = M->getFunction("sel_registerName"); 478 | Function *class_replaceMethod = M->getFunction("class_replaceMethod"); 479 | Function *class_getName = M->getFunction("class_getName"); 480 | Function *objc_getMetaClass = M->getFunction("objc_getMetaClass"); 481 | StructType *objc_method_list_t_type = 482 | M->getTypeByName("struct.__method_list_t"); 483 | for (unsigned i = 0; i < class_ro->getType()->getNumElements(); i++) { 484 | Constant *tmp = dyn_cast(class_ro->getAggregateElement(i)); 485 | if (tmp->isNullValue()) { 486 | continue; 487 | } 488 | Type *type = tmp->getType(); 489 | if (type == objc_method_list_t_type->getPointerTo()) { 490 | // Insert Methods 491 | ConstantExpr *methodListCE = cast(tmp); 492 | // Note:methodListCE is also a BitCastConstantExpr 493 | GlobalVariable *methodListGV = 494 | dyn_cast(methodListCE->getOperand(0)); 495 | // Now BitCast is stripped out. 496 | assert(methodListGV->hasInitializer() && 497 | "MethodListGV doesn't have initializer"); 498 | ConstantStruct *methodListStruct = 499 | cast(methodListGV->getInitializer()); 500 | // Extracting %struct._objc_method array from %struct.__method_list_t = 501 | // type { i32, i32, [0 x %struct._objc_method] } 502 | if (methodListStruct->getOperand(2)->isZeroValue()) { 503 | return; 504 | } 505 | ConstantArray *methodList = 506 | cast(methodListStruct->getOperand(2)); 507 | for (unsigned i = 0; i < methodList->getNumOperands(); i++) { 508 | ConstantStruct *methodStruct = 509 | cast(methodList->getOperand(i)); 510 | // methodStruct has type %struct._objc_method = type { i8*, i8*, i8* } 511 | // which contains {GEP(NAME),GEP(TYPE),IMP} 512 | // Let's extract these info now 513 | // We should first register the selector 514 | CallInst *SEL = 515 | IRB->CreateCall(sel_registerName, {methodStruct->getOperand(0)}); 516 | Type *IMPType = 517 | class_replaceMethod->getFunctionType()->getParamType(2); 518 | Value *BitCastedIMP = 519 | IRB->CreateBitCast(methodStruct->getOperand(2), IMPType); 520 | vector replaceMethodArgs; 521 | if (isMetaClass) { 522 | CallInst *className = IRB->CreateCall(class_getName, {Class}); 523 | CallInst *MetaClass = 524 | IRB->CreateCall(objc_getMetaClass, {className}); 525 | replaceMethodArgs.push_back(MetaClass); // Class 526 | } else { 527 | replaceMethodArgs.push_back(Class); // Class 528 | } 529 | replaceMethodArgs.push_back(SEL); // SEL 530 | replaceMethodArgs.push_back(BitCastedIMP); // imp 531 | replaceMethodArgs.push_back(methodStruct->getOperand(1)); // type 532 | IRB->CreateCall(class_replaceMethod, 533 | ArrayRef(replaceMethodArgs)); 534 | } 535 | } 536 | } 537 | } 538 | void HandlePropertyIvar(ConstantStruct *class_ro, IRBuilder<> *IRB, Module *M, 539 | Value *Class) { 540 | StructType *objc_property_attribute_t_type = reinterpret_cast( 541 | M->getTypeByName("struct.objc_property_attribute_t")); 542 | Function *class_addProperty = M->getFunction("class_addProperty"); 543 | Function *class_addIvar = M->getFunction("class_addIvar"); 544 | StructType *ivar_list_t_type = M->getTypeByName("struct._ivar_list_t"); 545 | StructType *property_list_t_type = M->getTypeByName("struct._prop_list_t"); 546 | StructType *property_t_type = M->getTypeByName("struct._prop_t"); 547 | ConstantExpr *ivar_list = NULL; 548 | ConstantExpr *property_list = NULL; 549 | /* 550 | struct class_ro_t { 551 | uint32_t flags; 552 | uint32_t instanceStart; 553 | uint32_t instanceSize; 554 | #ifdef __LP64__ 555 | uint32_t reserved; 556 | #endif 557 | const uint8_t * ivarLayout; 558 | const char * name; 559 | method_list_t * baseMethodList; 560 | protocol_list_t * baseProtocols; 561 | const ivar_list_t * ivars; 562 | const uint8_t * weakIvarLayout; 563 | property_list_t *baseProperties; 564 | method_list_t *baseMethods() const { 565 | return baseMethodList; 566 | } 567 | };*/ 568 | 569 | // This is outrageous mess. Can we do better? 570 | for (unsigned i = 0; i < class_ro->getType()->getNumElements(); i++) { 571 | Constant *tmp = dyn_cast(class_ro->getAggregateElement(i)); 572 | if (tmp->isNullValue()) { 573 | continue; 574 | } 575 | Type *type = tmp->getType(); 576 | if (type == ivar_list_t_type->getPointerTo()) { 577 | ivar_list = dyn_cast(tmp); 578 | } else if (type == property_list_t_type->getPointerTo()) { 579 | property_list = dyn_cast(tmp); 580 | } 581 | } 582 | // End Struct Loading 583 | // The ConstantExprs are actually BitCasts 584 | // We need to extract correct operands,which point to corresponding 585 | // GlobalVariable 586 | if (ivar_list != NULL) { 587 | GlobalVariable *GV = dyn_cast( 588 | ivar_list->getOperand(0)); // Equal to casted stripPointerCasts()n 589 | assert(GV && "_OBJC_$_INSTANCE_VARIABLES Missing"); 590 | assert(GV->hasInitializer() && 591 | "_OBJC_$_INSTANCE_VARIABLES Missing Initializer"); 592 | ConstantArray *ivarArray = 593 | dyn_cast(GV->getInitializer()->getOperand(2)); 594 | for (unsigned i = 0; i < ivarArray->getNumOperands(); i++) { 595 | // struct _ivar_t 596 | ConstantStruct *ivar = 597 | dyn_cast(ivarArray->getOperand(i)); 598 | ConstantExpr *GEPName = dyn_cast(ivar->getOperand(1)); 599 | ConstantExpr *GEPType = dyn_cast(ivar->getOperand(2)); 600 | uint64_t alignment_junk = 601 | dyn_cast(ivar->getOperand(3))->getZExtValue(); 602 | uint64_t size_junk = 603 | dyn_cast(ivar->getOperand(4))->getZExtValue(); 604 | // Note alignment and size are int32 on both 32/64bit Target 605 | // However ObjC APIs take size_t argument, which is platform 606 | // dependent.WTF Apple? We need to re-create ConstantInt with correct 607 | // type so we can pass verifier Instead of doing Triple Switching 608 | // Again.Let's extract type from function definition 609 | Constant *size = ConstantInt::get( 610 | class_addIvar->getFunctionType()->getParamType(2), size_junk); 611 | Constant *alignment = ConstantInt::get( 612 | class_addIvar->getFunctionType()->getParamType(3), alignment_junk); 613 | vector addIvar_args; 614 | addIvar_args.push_back(Class); 615 | addIvar_args.push_back(GEPName); 616 | addIvar_args.push_back(size); 617 | addIvar_args.push_back(alignment); 618 | addIvar_args.push_back(GEPType); 619 | IRB->CreateCall(class_addIvar, ArrayRef(addIvar_args)); 620 | } 621 | } 622 | if (property_list != NULL) { 623 | 624 | GlobalVariable *GV = cast( 625 | property_list->getOperand(0)); // Equal to casted stripPointerCasts() 626 | assert(GV && "OBJC_$_PROP_LIST Missing"); 627 | assert(GV->hasInitializer() && "OBJC_$_PROP_LIST Missing Initializer"); 628 | ConstantArray *propArray = 629 | dyn_cast(GV->getInitializer()->getOperand(2)); 630 | for (unsigned i = 0; i < propArray->getNumOperands(); i++) { 631 | // struct _prop_t 632 | ConstantStruct *prop = 633 | dyn_cast(propArray->getOperand(i)); 634 | ConstantExpr *GEPName = dyn_cast(prop->getOperand(0)); 635 | ConstantExpr *GEPAttri = dyn_cast(prop->getOperand(1)); 636 | GlobalVariable *AttrGV = 637 | dyn_cast(GEPAttri->getOperand(0)); 638 | assert(AttrGV->hasInitializer() && 639 | "ObjC Property GV Don't Have Initializer"); 640 | StringRef attrString = 641 | dyn_cast(AttrGV->getInitializer()) 642 | ->getAsCString(); 643 | SmallVector attrComponents; 644 | attrString.split(attrComponents, ','); 645 | map propMap; // First character is key, remaining parts 646 | // are value.This is used to generate pairs 647 | // of attributes 648 | vector attrs; // Save Each Single Attr for later use 649 | vector zeroes; // Indexes used for creating GEP 650 | zeroes.push_back( 651 | ConstantInt::get(Type::getInt32Ty(M->getContext()), 0)); 652 | zeroes.push_back( 653 | ConstantInt::get(Type::getInt32Ty(M->getContext()), 0)); 654 | for (StringRef s : attrComponents) { 655 | StringRef key = s.substr(0, 1); 656 | StringRef value = s.substr(1); 657 | propMap[key] = value; 658 | vector tmp; 659 | Constant *KeyConst = 660 | dyn_cast(IRB->CreateGlobalStringPtr(key)); 661 | Constant *ValueConst = 662 | dyn_cast(IRB->CreateGlobalStringPtr(value)); 663 | tmp.push_back(KeyConst); 664 | tmp.push_back(ValueConst); 665 | Constant *attr = 666 | ConstantStruct::get(property_t_type, ArrayRef(tmp)); 667 | attrs.push_back(attr); 668 | } 669 | ArrayType *ATType = ArrayType::get(property_t_type, attrs.size()); 670 | Constant *CA = ConstantArray::get(ATType, ArrayRef(attrs)); 671 | AllocaInst *attrInMem = IRB->CreateAlloca(ATType); 672 | IRB->CreateStore(CA, attrInMem); 673 | // attrInMem has type [n x %struct.objc_property_attribute_t]* 674 | // We need to bitcast it to %struct.objc_property_attribute_t* to silent 675 | // GEP's type check 676 | Value *BitCastedFromArrayToPtr = IRB->CreateBitCast( 677 | attrInMem, objc_property_attribute_t_type->getPointerTo()); 678 | Value *GEP = IRB->CreateInBoundsGEP(BitCastedFromArrayToPtr, zeroes); 679 | // Now GEP is done. 680 | // BitCast it back to our required type 681 | Value *GEPBitCasedToArg = IRB->CreateBitCast( 682 | GEP, class_addProperty->getFunctionType()->getParamType(2)); 683 | vector addProp_args; 684 | addProp_args.push_back(Class); 685 | addProp_args.push_back(GEPName); 686 | addProp_args.push_back(GEPBitCasedToArg); 687 | addProp_args.push_back(ConstantInt::get( 688 | class_addProperty->getFunctionType()->getParamType(3), 689 | attrs.size())); 690 | IRB->CreateCall(class_addProperty, ArrayRef(addProp_args)); 691 | } 692 | } 693 | } 694 | }; 695 | } // namespace llvm 696 | ModulePass *llvm::createAntiClassDumpPass() { return new AntiClassDump(); } 697 | char AntiClassDump::ID = 0; 698 | INITIALIZE_PASS(AntiClassDump, "acd", "Enable Anti-ClassDump.", true, true) 699 | -------------------------------------------------------------------------------- /BogusControlFlow.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | //===- BogusControlFlow.cpp - BogusControlFlow Obfuscation 4 | // pass-------------------------===// 5 | // 6 | // This file implements BogusControlFlow's pass, inserting bogus control flow. 7 | // It adds bogus flow to a given basic block this way: 8 | // 9 | // Before : 10 | // entry 11 | // | 12 | // ______v______ 13 | // | Original | 14 | // |_____________| 15 | // | 16 | // v 17 | // return 18 | // 19 | // After : 20 | // entry 21 | // | 22 | // ____v_____ 23 | // |condition*| (false) 24 | // |__________|----+ 25 | // (true)| | 26 | // | | 27 | // ______v______ | 28 | // +-->| Original* | | 29 | // | |_____________| (true) 30 | // | (false)| !-----------> return 31 | // | ______v______ | 32 | // | | Altered |<--! 33 | // | |_____________| 34 | // |__________| 35 | // 36 | // * The results of these terminator's branch's conditions are always true, but 37 | // these predicates are 38 | // opacificated. For this, we declare two global values: x and y, and replace 39 | // the FCMP_TRUE predicate with (y < 10 || x * (x + 1) % 2 == 0) (this could 40 | // be improved, as the global values give a hint on where are the opaque 41 | // predicates) 42 | // 43 | // The altered bloc is a copy of the original's one with junk instructions 44 | // added accordingly to the type of instructions we found in the bloc 45 | // 46 | // Each basic block of the function is choosen if a random number in the range 47 | // [0,100] is smaller than the choosen probability rate. The default value 48 | // is 30. This value can be modify using the option -boguscf-prob=[value]. 49 | // Value must be an integer in the range [0, 100], otherwise the default value 50 | // is taken. Exemple: -boguscf -boguscf-prob=60 51 | // 52 | // The pass can also be loop many times on a function, including on the basic 53 | // blocks added in a previous loop. Be careful if you use a big probability 54 | // number and choose to run the loop many times wich may cause the pass to run 55 | // for a very long time. The default value is one loop, but you can change it 56 | // with -boguscf-loop=[value]. Value must be an integer greater than 1, 57 | // otherwise the default value is taken. Exemple: -boguscf -boguscf-loop=2 58 | // 59 | // 60 | // Defined debug types: 61 | // - "gen" : general informations 62 | // - "opt" : concerning the given options (parameter) 63 | // - "cfg" : printing the various function's cfg before transformation 64 | // and after transformation if it has been modified, and all 65 | // the functions at end of the pass, after doFinalization. 66 | // 67 | // To use them all, simply use the -debug option. 68 | // To use only one of them, follow the pass' command by -debug-only=name. 69 | // Exemple, -boguscf -debug-only=cfg 70 | // 71 | // 72 | // Stats: 73 | // The following statistics will be printed if you use 74 | // the -stats command: 75 | // 76 | // a. Number of functions in this module 77 | // b. Number of times we run on each function 78 | // c. Initial number of basic blocks in this module 79 | // d. Number of modified basic blocks 80 | // e. Number of added basic blocks in this module 81 | // f. Final number of basic blocks in this module 82 | // 83 | // file : lib/Transforms/Obfuscation/BogusControlFlow.cpp 84 | // date : june 2012 85 | // version: 1.0 86 | // author : julie.michielin@gmail.com 87 | // modifications: pjunod, Rinaldini Julien 88 | // project: Obfuscator 89 | // option : -boguscf 90 | // 91 | //===----------------------------------------------------------------------------------===// 92 | 93 | #include "llvm/Transforms/Obfuscation/BogusControlFlow.h" 94 | #include "llvm/IR/IRBuilder.h" 95 | #include "llvm/IR/NoFolder.h" 96 | #include "llvm/Support/TargetSelect.h" 97 | #include "llvm/Transforms/Obfuscation/Utils.h" 98 | #include "llvm/Transforms/Utils/Local.h" 99 | #include 100 | 101 | 102 | // Options for the pass 103 | const int defaultObfRate = 70, defaultObfTime = 1; 104 | 105 | static cl::opt 106 | ObfProbRate("bcf_prob", 107 | cl::desc("Choose the probability [%] each basic blocks will be " 108 | "obfuscated by the -bcf pass"), 109 | cl::value_desc("probability rate"), cl::init(defaultObfRate), 110 | cl::Optional); 111 | 112 | static cl::opt 113 | ObfTimes("bcf_loop", 114 | cl::desc("Choose how many time the -bcf pass loop on a function"), 115 | cl::value_desc("number of times"), cl::init(defaultObfTime), 116 | cl::Optional); 117 | static cl::opt ConditionExpressionComplexity( 118 | "bcf_cond_compl", 119 | cl::desc("The complexity of the expression used to generate branching " 120 | "condition"), 121 | cl::value_desc("Complexity"), cl::init(3), cl::Optional); 122 | static Instruction::BinaryOps ops[] = {Instruction::Add, Instruction::Sub, 123 | Instruction::And, Instruction::Or, 124 | Instruction::Xor}; 125 | static CmpInst::Predicate preds[] = {CmpInst::ICMP_EQ, CmpInst::ICMP_NE, 126 | CmpInst::ICMP_UGT, CmpInst::ICMP_UGE, 127 | CmpInst::ICMP_ULT, CmpInst::ICMP_ULE}; 128 | namespace { 129 | static bool OnlyUsedBy(Value *V, Value *Usr) { 130 | for (User *U : V->users()) 131 | if (U != Usr) 132 | return false; 133 | 134 | return true; 135 | } 136 | static void RemoveDeadConstant(Constant *C) { 137 | assert(C->use_empty() && "Constant is not dead!"); 138 | SmallPtrSet Operands; 139 | for (Value *Op : C->operands()) 140 | if (OnlyUsedBy(Op, C)) 141 | Operands.insert(cast(Op)); 142 | if (GlobalVariable *GV = dyn_cast(C)) { 143 | if (!GV->hasLocalLinkage()) return; // Don't delete non-static globals. 144 | GV->eraseFromParent(); 145 | } 146 | else if (!isa(C)) 147 | if (isa(C->getType())) 148 | C->destroyConstant(); 149 | 150 | // If the constant referenced anything, see if we can delete it as well. 151 | for (Constant *O : Operands) 152 | RemoveDeadConstant(O); 153 | } 154 | struct BogusControlFlow : public FunctionPass { 155 | static char ID; // Pass identification 156 | bool flag; 157 | BogusControlFlow() : FunctionPass(ID) { this->flag = true; } 158 | BogusControlFlow(bool flag) : FunctionPass(ID) { this->flag = flag; } 159 | /* runOnFunction 160 | * 161 | * Overwrite FunctionPass method to apply the transformation 162 | * to the function. See header for more details. 163 | */ 164 | bool runOnFunction(Function &F) override { 165 | // Check if the percentage is correct 166 | if (ObfTimes <= 0) { 167 | errs() << "BogusControlFlow application number -bcf_loop=x must be x > 0"; 168 | return false; 169 | } 170 | 171 | // Check if the number of applications is correct 172 | if (!((ObfProbRate > 0) && (ObfProbRate <= 100))) { 173 | errs() << "BogusControlFlow application basic blocks percentage " 174 | "-bcf_prob=x must be 0 < x <= 100"; 175 | return false; 176 | } 177 | // If fla annotations 178 | if (toObfuscate(flag, &F, "bcf")) { 179 | errs() << "Running BogusControlFlow On " << F.getName() << "\n"; 180 | bogus(F); 181 | doF(*F.getParent()); 182 | return true; 183 | } 184 | 185 | return false; 186 | } // end of runOnFunction() 187 | 188 | void bogus(Function &F) { 189 | // For statistics and debug 190 | int NumBasicBlocks = 0; 191 | bool firstTime = true; // First time we do the loop in this function 192 | bool hasBeenModified = false; 193 | DEBUG_WITH_TYPE("opt", errs() << "bcf: Started on function " << F.getName() 194 | << "\n"); 195 | DEBUG_WITH_TYPE("opt", 196 | errs() << "bcf: Probability rate: " << ObfProbRate << "\n"); 197 | if (ObfProbRate < 0 || ObfProbRate > 100) { 198 | DEBUG_WITH_TYPE("opt", errs() 199 | << "bcf: Incorrect value," 200 | << " probability rate set to default value: " 201 | << defaultObfRate << " \n"); 202 | ObfProbRate = defaultObfRate; 203 | } 204 | DEBUG_WITH_TYPE("opt", errs() 205 | << "bcf: How many times: " << ObfTimes << "\n"); 206 | if (ObfTimes <= 0) { 207 | DEBUG_WITH_TYPE("opt", errs() 208 | << "bcf: Incorrect value," 209 | << " must be greater than 1. Set to default: " 210 | << defaultObfTime << " \n"); 211 | ObfTimes = defaultObfTime; 212 | } 213 | int NumObfTimes = ObfTimes; 214 | 215 | // Real begining of the pass 216 | // Loop for the number of time we run the pass on the function 217 | do { 218 | DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function " << F.getName() 219 | << ", before the pass:\n"); 220 | DEBUG_WITH_TYPE("cfg", F.viewCFG()); 221 | // Put all the function's block in a list 222 | std::list basicBlocks; 223 | for (Function::iterator i = F.begin(); i != F.end(); ++i) { 224 | BasicBlock *BB = &*i; 225 | if (!BB->isEHPad() && !BB->isLandingPad()) { 226 | basicBlocks.push_back(BB); 227 | } 228 | } 229 | DEBUG_WITH_TYPE( 230 | "gen", errs() << "bcf: Iterating on the Function's Basic Blocks\n"); 231 | 232 | while (!basicBlocks.empty()) { 233 | NumBasicBlocks++; 234 | // Basic Blocks' selection 235 | if ((int)llvm::cryptoutils->get_range(100) <= ObfProbRate) { 236 | DEBUG_WITH_TYPE("opt", errs() << "bcf: Block " << NumBasicBlocks 237 | << " selected. \n"); 238 | hasBeenModified = true; 239 | // Add bogus flow to the given Basic Block (see description) 240 | BasicBlock *basicBlock = basicBlocks.front(); 241 | addBogusFlow(basicBlock, F); 242 | } else { 243 | DEBUG_WITH_TYPE("opt", errs() << "bcf: Block " << NumBasicBlocks 244 | << " not selected.\n"); 245 | } 246 | // remove the block from the list 247 | basicBlocks.pop_front(); 248 | } // end of while(!basicBlocks.empty()) 249 | DEBUG_WITH_TYPE("gen", 250 | errs() << "bcf: End of function " << F.getName() << "\n"); 251 | if (hasBeenModified) { // if the function has been modified 252 | DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function " << F.getName() 253 | << ", after the pass: \n"); 254 | DEBUG_WITH_TYPE("cfg", F.viewCFG()); 255 | } else { 256 | DEBUG_WITH_TYPE("cfg", errs() 257 | << "bcf: Function's not been modified \n"); 258 | } 259 | firstTime = false; 260 | } while (--NumObfTimes > 0); 261 | } 262 | 263 | /* addBogusFlow 264 | * 265 | * Add bogus flow to a given basic block, according to the header's 266 | * description 267 | */ 268 | virtual void addBogusFlow(BasicBlock *basicBlock, Function &F) { 269 | 270 | // Split the block: first part with only the phi nodes and debug info and 271 | // terminator 272 | // created by splitBasicBlock. (-> No instruction) 273 | // Second part with every instructions from the original 274 | // block 275 | // We do this way, so we don't have to adjust all the phi nodes, metadatas 276 | // and so on for the first block. We have to let the phi nodes in the first 277 | // part, because they actually are updated in the second part according to 278 | // them. 279 | BasicBlock::iterator i1 = basicBlock->begin(); 280 | if (basicBlock->getFirstNonPHIOrDbgOrLifetime()) 281 | i1 = (BasicBlock::iterator)basicBlock->getFirstNonPHIOrDbgOrLifetime(); 282 | Twine *var; 283 | var = new Twine("originalBB"); 284 | BasicBlock *originalBB = basicBlock->splitBasicBlock(i1, *var); 285 | DEBUG_WITH_TYPE("gen", errs() 286 | << "bcf: First and original basic blocks: ok\n"); 287 | 288 | // Creating the altered basic block on which the first basicBlock will jump 289 | Twine *var3 = new Twine("alteredBB"); 290 | BasicBlock *alteredBB = createAlteredBasicBlock(originalBB, *var3, &F); 291 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Altered basic block: ok\n"); 292 | 293 | // Now that all the blocks are created, 294 | // we modify the terminators to adjust the control flow. 295 | 296 | alteredBB->getTerminator()->eraseFromParent(); 297 | basicBlock->getTerminator()->eraseFromParent(); 298 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Terminator removed from the altered" 299 | << " and first basic blocks\n"); 300 | 301 | // Preparing a condition.. 302 | // For now, the condition is an always true comparaison between 2 float 303 | // This will be complicated after the pass (in doFinalization()) 304 | 305 | // We need to use ConstantInt instead of ConstantFP as ConstantFP results in strange dead-loop 306 | // when injected into Xcode 307 | Value *LHS = ConstantInt::get(Type::getInt32Ty(F.getContext()), 1); 308 | Value *RHS = ConstantInt::get(Type::getInt32Ty(F.getContext()), 1); 309 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Value LHS and RHS created\n"); 310 | 311 | // The always true condition. End of the first block 312 | ICmpInst *condition = 313 | new ICmpInst(*basicBlock, ICmpInst::ICMP_EQ, LHS, RHS,"BCFPlaceHolderPred"); 314 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Always true condition created\n"); 315 | 316 | // Jump to the original basic block if the condition is true or 317 | // to the altered block if false. 318 | BranchInst::Create(originalBB, alteredBB, (Value *)condition, basicBlock); 319 | DEBUG_WITH_TYPE( 320 | "gen", 321 | errs() << "bcf: Terminator instruction in first basic block: ok\n"); 322 | 323 | // The altered block loop back on the original one. 324 | BranchInst::Create(originalBB, alteredBB); 325 | DEBUG_WITH_TYPE( 326 | "gen", errs() << "bcf: Terminator instruction in altered block: ok\n"); 327 | 328 | // The end of the originalBB is modified to give the impression that 329 | // sometimes it continues in the loop, and sometimes it return the desired 330 | // value (of course it's always true, so it always use the original 331 | // terminator.. 332 | // but this will be obfuscated too;) ) 333 | 334 | // iterate on instruction just before the terminator of the originalBB 335 | BasicBlock::iterator i = originalBB->end(); 336 | 337 | // Split at this point (we only want the terminator in the second part) 338 | Twine *var5 = new Twine("originalBBpart2"); 339 | BasicBlock *originalBBpart2 = originalBB->splitBasicBlock(--i, *var5); 340 | DEBUG_WITH_TYPE("gen", 341 | errs() << "bcf: Terminator part of the original basic block" 342 | << " is isolated\n"); 343 | // the first part go either on the return statement or on the begining 344 | // of the altered block.. So we erase the terminator created when splitting. 345 | originalBB->getTerminator()->eraseFromParent(); 346 | // We add at the end a new always true condition 347 | ICmpInst *condition2 = 348 | new ICmpInst(*originalBB, CmpInst::ICMP_EQ, LHS, RHS,"BCFPlaceHolderPred"); 349 | // BranchInst::Create(originalBBpart2, alteredBB, (Value 350 | // *)condition2,originalBB); Do random behavior to avoid pattern 351 | // recognition This is achieved by jumping to a random BB 352 | switch (llvm::cryptoutils->get_uint16_t() % 2) { 353 | case 0: { 354 | BranchInst::Create(originalBBpart2, originalBB, condition2, originalBB); 355 | break; 356 | } 357 | case 1: { 358 | BranchInst::Create(originalBBpart2, alteredBB, condition2, originalBB); 359 | break; 360 | } 361 | default: { 362 | BranchInst::Create(originalBBpart2, originalBB, condition2, originalBB); 363 | break; 364 | } 365 | } 366 | DEBUG_WITH_TYPE("gen", errs() 367 | << "bcf: Terminator original basic block: ok\n"); 368 | DEBUG_WITH_TYPE("gen", errs() << "bcf: End of addBogusFlow().\n"); 369 | 370 | } // end of addBogusFlow() 371 | 372 | /* createAlteredBasicBlock 373 | * 374 | * This function return a basic block similar to a given one. 375 | * It's inserted just after the given basic block. 376 | * The instructions are similar but junk instructions are added between 377 | * the cloned one. The cloned instructions' phi nodes, metadatas, uses and 378 | * debug locations are adjusted to fit in the cloned basic block and 379 | * behave nicely. 380 | */ 381 | virtual BasicBlock *createAlteredBasicBlock(BasicBlock *basicBlock, 382 | const Twine &Name = "gen", 383 | Function *F = 0) { 384 | // Useful to remap the informations concerning instructions. 385 | ValueToValueMapTy VMap; 386 | BasicBlock *alteredBB = llvm::CloneBasicBlock(basicBlock, VMap, Name, F); 387 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Original basic block cloned\n"); 388 | // Remap operands. 389 | BasicBlock::iterator ji = basicBlock->begin(); 390 | for (BasicBlock::iterator i = alteredBB->begin(), e = alteredBB->end(); 391 | i != e; ++i) { 392 | // Loop over the operands of the instruction 393 | for (User::op_iterator opi = i->op_begin(), ope = i->op_end(); opi != ope; 394 | ++opi) { 395 | // get the value for the operand 396 | Value *v = MapValue(*opi, VMap, RF_None, 0); 397 | if (v != 0) { 398 | *opi = v; 399 | DEBUG_WITH_TYPE("gen", 400 | errs() << "bcf: Value's operand has been setted\n"); 401 | } 402 | } 403 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Operands remapped\n"); 404 | // Remap phi nodes' incoming blocks. 405 | if (PHINode *pn = dyn_cast(i)) { 406 | for (unsigned j = 0, e = pn->getNumIncomingValues(); j != e; ++j) { 407 | Value *v = MapValue(pn->getIncomingBlock(j), VMap, RF_None, 0); 408 | if (v != 0) { 409 | pn->setIncomingBlock(j, cast(v)); 410 | } 411 | } 412 | } 413 | DEBUG_WITH_TYPE("gen", errs() << "bcf: PHINodes remapped\n"); 414 | // Remap attached metadata. 415 | SmallVector, 4> MDs; 416 | i->getAllMetadata(MDs); 417 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Metadatas remapped\n"); 418 | // important for compiling with DWARF, using option -g. 419 | i->setDebugLoc(ji->getDebugLoc()); 420 | ji++; 421 | DEBUG_WITH_TYPE("gen", errs() 422 | << "bcf: Debug information location setted\n"); 423 | 424 | } // The instructions' informations are now all correct 425 | 426 | DEBUG_WITH_TYPE("gen", 427 | errs() << "bcf: The cloned basic block is now correct\n"); 428 | DEBUG_WITH_TYPE( 429 | "gen", 430 | errs() << "bcf: Starting to add junk code in the cloned bloc...\n"); 431 | 432 | // add random instruction in the middle of the bloc. This part can be 433 | // improve 434 | for (BasicBlock::iterator i = alteredBB->begin(), e = alteredBB->end(); 435 | i != e; ++i) { 436 | // in the case we find binary operator, we modify slightly this part by 437 | // randomly insert some instructions 438 | if (i->isBinaryOp()) { // binary instructions 439 | unsigned opcode = i->getOpcode(); 440 | BinaryOperator *op, *op1 = NULL; 441 | Twine *var = new Twine("_"); 442 | // treat differently float or int 443 | // Binary int 444 | if (opcode == Instruction::Add || opcode == Instruction::Sub || 445 | opcode == Instruction::Mul || opcode == Instruction::UDiv || 446 | opcode == Instruction::SDiv || opcode == Instruction::URem || 447 | opcode == Instruction::SRem || opcode == Instruction::Shl || 448 | opcode == Instruction::LShr || opcode == Instruction::AShr || 449 | opcode == Instruction::And || opcode == Instruction::Or || 450 | opcode == Instruction::Xor) { 451 | for (int random = (int)llvm::cryptoutils->get_range(10); random < 10; 452 | ++random) { 453 | switch (llvm::cryptoutils->get_range(4)) { // to improve 454 | case 0: // do nothing 455 | break; 456 | case 1: 457 | op = BinaryOperator::CreateNeg(i->getOperand(0), *var, &*i); 458 | op1 = BinaryOperator::Create(Instruction::Add, op, 459 | i->getOperand(1), "gen", &*i); 460 | break; 461 | case 2: 462 | op1 = BinaryOperator::Create(Instruction::Sub, i->getOperand(0), 463 | i->getOperand(1), *var, &*i); 464 | op = BinaryOperator::Create(Instruction::Mul, op1, 465 | i->getOperand(1), "gen", &*i); 466 | break; 467 | case 3: 468 | op = BinaryOperator::Create(Instruction::Shl, i->getOperand(0), 469 | i->getOperand(1), *var, &*i); 470 | break; 471 | } 472 | } 473 | } 474 | // Binary float 475 | if (opcode == Instruction::FAdd || opcode == Instruction::FSub || 476 | opcode == Instruction::FMul || opcode == Instruction::FDiv || 477 | opcode == Instruction::FRem) { 478 | for (int random = (int)llvm::cryptoutils->get_range(10); random < 10; 479 | ++random) { 480 | switch (llvm::cryptoutils->get_range(3)) { // can be improved 481 | case 0: // do nothing 482 | break; 483 | case 1: 484 | op = BinaryOperator::CreateFNeg(i->getOperand(0), *var, &*i); 485 | op1 = BinaryOperator::Create(Instruction::FAdd, op, 486 | i->getOperand(1), "gen", &*i); 487 | break; 488 | case 2: 489 | op = BinaryOperator::Create(Instruction::FSub, i->getOperand(0), 490 | i->getOperand(1), *var, &*i); 491 | op1 = BinaryOperator::Create(Instruction::FMul, op, 492 | i->getOperand(1), "gen", &*i); 493 | break; 494 | } 495 | } 496 | } 497 | if (opcode == Instruction::ICmp) { // Condition (with int) 498 | ICmpInst *currentI = (ICmpInst *)(&i); 499 | switch (llvm::cryptoutils->get_range(3)) { // must be improved 500 | case 0: // do nothing 501 | break; 502 | case 1: 503 | currentI->swapOperands(); 504 | break; 505 | case 2: // randomly change the predicate 506 | switch (llvm::cryptoutils->get_range(10)) { 507 | case 0: 508 | currentI->setPredicate(ICmpInst::ICMP_EQ); 509 | break; // equal 510 | case 1: 511 | currentI->setPredicate(ICmpInst::ICMP_NE); 512 | break; // not equal 513 | case 2: 514 | currentI->setPredicate(ICmpInst::ICMP_UGT); 515 | break; // unsigned greater than 516 | case 3: 517 | currentI->setPredicate(ICmpInst::ICMP_UGE); 518 | break; // unsigned greater or equal 519 | case 4: 520 | currentI->setPredicate(ICmpInst::ICMP_ULT); 521 | break; // unsigned less than 522 | case 5: 523 | currentI->setPredicate(ICmpInst::ICMP_ULE); 524 | break; // unsigned less or equal 525 | case 6: 526 | currentI->setPredicate(ICmpInst::ICMP_SGT); 527 | break; // signed greater than 528 | case 7: 529 | currentI->setPredicate(ICmpInst::ICMP_SGE); 530 | break; // signed greater or equal 531 | case 8: 532 | currentI->setPredicate(ICmpInst::ICMP_SLT); 533 | break; // signed less than 534 | case 9: 535 | currentI->setPredicate(ICmpInst::ICMP_SLE); 536 | break; // signed less or equal 537 | } 538 | break; 539 | } 540 | } 541 | if (opcode == Instruction::FCmp) { // Conditions (with float) 542 | FCmpInst *currentI = (FCmpInst *)(&i); 543 | switch (llvm::cryptoutils->get_range(3)) { // must be improved 544 | case 0: // do nothing 545 | break; 546 | case 1: 547 | currentI->swapOperands(); 548 | break; 549 | case 2: // randomly change the predicate 550 | switch (llvm::cryptoutils->get_range(10)) { 551 | case 0: 552 | currentI->setPredicate(FCmpInst::FCMP_OEQ); 553 | break; // ordered and equal 554 | case 1: 555 | currentI->setPredicate(FCmpInst::FCMP_ONE); 556 | break; // ordered and operands are unequal 557 | case 2: 558 | currentI->setPredicate(FCmpInst::FCMP_UGT); 559 | break; // unordered or greater than 560 | case 3: 561 | currentI->setPredicate(FCmpInst::FCMP_UGE); 562 | break; // unordered, or greater than, or equal 563 | case 4: 564 | currentI->setPredicate(FCmpInst::FCMP_ULT); 565 | break; // unordered or less than 566 | case 5: 567 | currentI->setPredicate(FCmpInst::FCMP_ULE); 568 | break; // unordered, or less than, or equal 569 | case 6: 570 | currentI->setPredicate(FCmpInst::FCMP_OGT); 571 | break; // ordered and greater than 572 | case 7: 573 | currentI->setPredicate(FCmpInst::FCMP_OGE); 574 | break; // ordered and greater than or equal 575 | case 8: 576 | currentI->setPredicate(FCmpInst::FCMP_OLT); 577 | break; // ordered and less than 578 | case 9: 579 | currentI->setPredicate(FCmpInst::FCMP_OLE); 580 | break; // ordered or less than, or equal 581 | } 582 | break; 583 | } 584 | } 585 | } 586 | } 587 | // Remove DIs from AlterBB 588 | vector toRemove; 589 | vector DeadConstants; 590 | for (Instruction &I : *alteredBB) { 591 | if (CallInst *CI = dyn_cast(&I)) { 592 | if (CI->getCalledFunction() != nullptr && 593 | CI->getCalledFunction()->getName().startswith("llvm.dbg")) { 594 | toRemove.push_back(CI); 595 | } 596 | } 597 | } 598 | // Shamefully stolen from IPO/StripSymbols.cpp 599 | for (CallInst *CI : toRemove) { 600 | Value *Arg1 = CI->getArgOperand(0); 601 | Value *Arg2 = CI->getArgOperand(1); 602 | assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); 603 | CI->eraseFromParent(); 604 | if (Arg1->use_empty()) { 605 | if (Constant *C = dyn_cast(Arg1)) { 606 | DeadConstants.push_back(C); 607 | } else { 608 | RecursivelyDeleteTriviallyDeadInstructions(Arg1); 609 | } 610 | } 611 | if (Arg2->use_empty()) { 612 | if (Constant *C = dyn_cast(Arg2)) { 613 | DeadConstants.push_back(C); 614 | } 615 | } 616 | } 617 | while (!DeadConstants.empty()) { 618 | Constant *C = DeadConstants.back(); 619 | DeadConstants.pop_back(); 620 | if (GlobalVariable *GV = dyn_cast(C)) { 621 | if (GV->hasLocalLinkage()) 622 | RemoveDeadConstant(GV); 623 | } else 624 | RemoveDeadConstant(C); 625 | } 626 | return alteredBB; 627 | } // end of createAlteredBasicBlock() 628 | 629 | /* doFinalization 630 | * 631 | * Overwrite FunctionPass method to apply the transformations to the whole 632 | * module. This part obfuscate all the always true predicates of the module. 633 | * More precisely, the condition which predicate is FCMP_TRUE. 634 | * It also remove all the functions' basic blocks' and instructions' names. 635 | */ 636 | bool doF(Module &M) { 637 | // In this part we extract all always-true predicate and replace them with 638 | // opaque predicate: For this, we declare two global values: x and y, and 639 | // replace the FCMP_TRUE predicate with (y < 10 || x * (x + 1) % 2 == 0) A 640 | // better way to obfuscate the predicates would be welcome. In the meantime 641 | // we will erase the name of the basic blocks, the instructions and the 642 | // functions. 643 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Starting doFinalization...\n"); 644 | std::vector toEdit, toDelete; 645 | // BinaryOperator *op, *op1 = NULL; 646 | // ICmpInst *condition, *condition2; 647 | // Looking for the conditions and branches to transform 648 | for (Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi) { 649 | for (Function::iterator fi = mi->begin(), fe = mi->end(); fi != fe; 650 | ++fi) { 651 | // fi->setName(""); 652 | Instruction *tbb = fi->getTerminator(); 653 | if (tbb->getOpcode() == Instruction::Br) { 654 | BranchInst *br = (BranchInst *)(tbb); 655 | if (br->isConditional()) { 656 | ICmpInst *cond = (ICmpInst *)br->getCondition(); 657 | unsigned opcode = cond->getOpcode(); 658 | if (opcode == Instruction::ICmp) { 659 | if (cond->getPredicate() == ICmpInst::ICMP_EQ && cond->getName().startswith("BCFPlaceHolderPred")) { 660 | DEBUG_WITH_TYPE("gen", 661 | errs() << "bcf: an always true predicate !\n"); 662 | toDelete.push_back(cond); // The condition 663 | toEdit.push_back(tbb); // The branch using the condition 664 | } 665 | } 666 | } 667 | } 668 | /* 669 | for (BasicBlock::iterator bi = fi->begin(), be = fi->end() ; bi != be; 670 | ++bi){ bi->setName(""); // setting the basic blocks' names 671 | } 672 | */ 673 | } 674 | } 675 | // Replacing all the branches we found 676 | for (std::vector::iterator i = toEdit.begin(); 677 | i != toEdit.end(); ++i) { 678 | // Previously We Use LLVM EE To Calculate LHS and RHS 679 | // Since IRBuilder<> uses ConstantFolding to fold constants. 680 | // The return instruction is already returning constants 681 | // The variable names below are the artifact from the Emulation Era 682 | Type *I32Ty = Type::getInt32Ty(M.getContext()); 683 | Module emuModule("HikariBCFEmulator", M.getContext()); 684 | emuModule.setDataLayout(M.getDataLayout()); 685 | emuModule.setTargetTriple(M.getTargetTriple()); 686 | Function *emuFunction = 687 | Function::Create(FunctionType::get(I32Ty, false), 688 | GlobalValue::LinkageTypes::PrivateLinkage, 689 | "BeginExecution", &emuModule); 690 | BasicBlock *EntryBlock = 691 | BasicBlock::Create(M.getContext(), "", emuFunction); 692 | 693 | Instruction *tmp = &*((*i)->getParent()->getFirstInsertionPt()); 694 | IRBuilder<> IRBReal(tmp); 695 | IRBuilder<> IRBEmu(EntryBlock); 696 | // First,Construct a real RHS that will be used in the actual condition 697 | Constant *RealRHS = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t()); 698 | // Prepare Initial LHS and RHS to bootstrap the emulator 699 | Constant *LHSC = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t()); 700 | Constant *RHSC = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t()); 701 | GlobalVariable *LHSGV = 702 | new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false, 703 | GlobalValue::PrivateLinkage, LHSC, "LHSGV"); 704 | GlobalVariable *RHSGV = 705 | new GlobalVariable(M, Type::getInt32Ty(M.getContext()), false, 706 | GlobalValue::PrivateLinkage, RHSC, "RHSGV"); 707 | LoadInst *LHS = IRBReal.CreateLoad(LHSGV, "Initial LHS"); 708 | LoadInst *RHS = IRBReal.CreateLoad(RHSGV, "Initial LHS"); 709 | // To Speed-Up Evaluation 710 | Value *emuLHS = LHSC; 711 | Value *emuRHS = RHSC; 712 | Instruction::BinaryOps initialOp = ops[llvm::cryptoutils->get_uint32_t() % 713 | (sizeof(ops) / sizeof(ops[0]))]; 714 | Value *emuLast = 715 | IRBEmu.CreateBinOp(initialOp, emuLHS, emuRHS, "EmuInitialCondition"); 716 | Value *Last = 717 | IRBReal.CreateBinOp(initialOp, LHS, RHS, "InitialCondition"); 718 | for (int i = 0; i < ConditionExpressionComplexity; i++) { 719 | Constant *newTmp = ConstantInt::get(I32Ty, cryptoutils->get_uint32_t()); 720 | Instruction::BinaryOps initialOp = 721 | ops[llvm::cryptoutils->get_uint32_t() % 722 | (sizeof(ops) / sizeof(ops[0]))]; 723 | emuLast = IRBEmu.CreateBinOp(initialOp, emuLast, newTmp, 724 | "EmuInitialCondition"); 725 | Last = IRBReal.CreateBinOp(initialOp, Last, newTmp, "InitialCondition"); 726 | } 727 | // Randomly Generate Predicate 728 | CmpInst::Predicate pred = preds[llvm::cryptoutils->get_uint32_t() % 729 | (sizeof(preds) / sizeof(preds[0]))]; 730 | Last = IRBReal.CreateICmp(pred, Last, RealRHS); 731 | emuLast = IRBEmu.CreateICmp(pred, emuLast, RealRHS); 732 | ReturnInst *RI = IRBEmu.CreateRet(emuLast); 733 | ConstantInt *emuCI = cast(RI->getReturnValue()); 734 | uint64_t emulateResult = emuCI->getZExtValue(); 735 | vector BBs; // Start To Prepare IndirectBranching 736 | if (emulateResult == 1) { 737 | // Our ConstantExpr evaluates to true; 738 | 739 | BranchInst::Create(((BranchInst *)*i)->getSuccessor(0), 740 | ((BranchInst *)*i)->getSuccessor(1), (Value *)Last, 741 | ((BranchInst *)*i)->getParent()); 742 | } else { 743 | // False, swap operands 744 | 745 | BranchInst::Create(((BranchInst *)*i)->getSuccessor(1), 746 | ((BranchInst *)*i)->getSuccessor(0), (Value *)Last, 747 | ((BranchInst *)*i)->getParent()); 748 | } 749 | EntryBlock->eraseFromParent(); 750 | emuFunction->eraseFromParent(); 751 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Erase branch instruction:" 752 | << *((BranchInst *)*i) << "\n"); 753 | (*i)->eraseFromParent(); // erase the branch 754 | } 755 | // Erase all the associated conditions we found 756 | for (std::vector::iterator i = toDelete.begin(); 757 | i != toDelete.end(); ++i) { 758 | DEBUG_WITH_TYPE("gen", errs() << "bcf: Erase condition instruction:" 759 | << *((Instruction *)*i) << "\n"); 760 | (*i)->eraseFromParent(); 761 | } 762 | 763 | // Only for debug 764 | DEBUG_WITH_TYPE("cfg", errs() << "bcf: End of the pass, here are the " 765 | "graphs after doFinalization\n"); 766 | for (Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi) { 767 | DEBUG_WITH_TYPE("cfg", errs() 768 | << "bcf: Function " << mi->getName() << "\n"); 769 | DEBUG_WITH_TYPE("cfg", mi->viewCFG()); 770 | } 771 | 772 | return true; 773 | } // end of doFinalization 774 | }; // end of struct BogusControlFlow : public FunctionPass 775 | } // namespace 776 | 777 | char BogusControlFlow::ID = 0; 778 | INITIALIZE_PASS(BogusControlFlow, "bcfobf", "Enable BogusControlFlow.", true, 779 | true) 780 | FunctionPass *llvm::createBogusControlFlowPass() { 781 | return new BogusControlFlow(); 782 | } 783 | FunctionPass *llvm::createBogusControlFlowPass(bool flag) { 784 | return new BogusControlFlow(flag); 785 | } 786 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_llvm_library(LLVMObfuscation 2 | FunctionCallObfuscate.cpp 3 | CryptoUtils.cpp 4 | BogusControlFlow.cpp 5 | Substitution.cpp 6 | Flattening.cpp 7 | Utils.cpp 8 | SplitBasicBlocks.cpp 9 | AntiClassDump.cpp 10 | StringEncryption.cpp 11 | IndirectBranch.cpp 12 | FunctionWrapper.cpp 13 | Obfuscation.cpp 14 | DEPENDS 15 | intrinsics_gen 16 | ) 17 | execute_process( 18 | COMMAND git log -1 --format=%H 19 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 20 | OUTPUT_VARIABLE HIKARI_GIT_COMMIT_HASH 21 | OUTPUT_STRIP_TRAILING_WHITESPACE 22 | ) 23 | target_compile_definitions(LLVMObfuscation PRIVATE "-DGIT_COMMIT_HASH=\"${HIKARI_GIT_COMMIT_HASH}\"") 24 | -------------------------------------------------------------------------------- /CryptoUtils.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/Transforms/Obfuscation/CryptoUtils.h" 4 | #include "llvm/ADT/Statistic.h" 5 | #include "llvm/ADT/Twine.h" 6 | #include "llvm/IR/LLVMContext.h" 7 | #include "llvm/Support/Debug.h" 8 | #include "llvm/Support/ErrorHandling.h" 9 | #include "llvm/Support/ManagedStatic.h" 10 | #include "llvm/Support/raw_ostream.h" 11 | #include "llvm/Support/Format.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace llvm; 21 | namespace llvm { 22 | ManagedStatic cryptoutils; 23 | } 24 | CryptoUtils::CryptoUtils() { 25 | 26 | } 27 | 28 | uint32_t CryptoUtils::scramble32(uint32_t in,std::map& VMap) { 29 | if(VMap.find(in)==VMap.end()){ 30 | uint32_t V=get_uint32_t(); 31 | VMap[in]=V; 32 | return V; 33 | } 34 | else{ 35 | return VMap[in]; 36 | } 37 | } 38 | CryptoUtils::~CryptoUtils() { 39 | if(eng!=nullptr){ 40 | delete eng; 41 | } 42 | } 43 | void CryptoUtils::prng_seed(){ 44 | using namespace std::chrono; 45 | std::uint_fast64_t ms = duration_cast< milliseconds >(system_clock::now().time_since_epoch()).count(); 46 | errs()< dis(min, max-1); 64 | return dis(*eng); 65 | } 66 | -------------------------------------------------------------------------------- /Flattening.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 4 | #include "llvm/Transforms/Obfuscation/CryptoUtils.h" 5 | #include 6 | using namespace llvm; 7 | 8 | namespace { 9 | struct Flattening : public FunctionPass { 10 | static char ID; // Pass identification, replacement for typeid 11 | bool flag; 12 | Flattening() : FunctionPass(ID) { this->flag = true; } 13 | Flattening(bool flag) : FunctionPass(ID) { this->flag = flag; } 14 | bool runOnFunction(Function &F); 15 | bool flatten(Function *f); 16 | }; 17 | } // namespace 18 | 19 | char Flattening::ID = 0; 20 | FunctionPass *llvm::createFlatteningPass(bool flag) { 21 | return new Flattening(flag); 22 | } 23 | FunctionPass *llvm::createFlatteningPass() { return new Flattening(); } 24 | INITIALIZE_PASS(Flattening, "cffobf", "Enable Control Flow Flattening.", true, 25 | true) 26 | bool Flattening::runOnFunction(Function &F) { 27 | Function *tmp = &F; 28 | // Do we obfuscate 29 | if (toObfuscate(flag, tmp, "fla")) { 30 | errs() << "Running ControlFlowFlattening On " << F.getName() << "\n"; 31 | flatten(tmp); 32 | } 33 | 34 | return false; 35 | } 36 | 37 | bool Flattening::flatten(Function *f) { 38 | vector origBB; 39 | BasicBlock *loopEntry; 40 | BasicBlock *loopEnd; 41 | LoadInst *load; 42 | SwitchInst *switchI; 43 | AllocaInst *switchVar; 44 | 45 | // SCRAMBLER 46 | std::map scrambling_key; 47 | // END OF SCRAMBLER 48 | 49 | // Lower switch 50 | FunctionPass *lower = createLowerSwitchPass(); 51 | lower->runOnFunction(*f); 52 | 53 | // Save all original BB 54 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 55 | BasicBlock *tmp = &*i; 56 | if (tmp->isEHPad() || tmp->isLandingPad()) { 57 | errs()<getName()<<" Contains Exception Handing Instructions and is unsupported for flattening in the open-source version of Hikari.\n"; 58 | return false; 59 | } 60 | origBB.push_back(tmp); 61 | 62 | BasicBlock *bb = &*i; 63 | if (!isa(bb->getTerminator()) && !isa(bb->getTerminator())) { 64 | return false; 65 | } 66 | } 67 | 68 | // Nothing to flatten 69 | if (origBB.size() <= 1) { 70 | return false; 71 | } 72 | 73 | // Remove first BB 74 | origBB.erase(origBB.begin()); 75 | 76 | // Get a pointer on the first BB 77 | Function::iterator tmp = f->begin(); //++tmp; 78 | BasicBlock *insert = &*tmp; 79 | 80 | // If main begin with an if 81 | BranchInst *br = NULL; 82 | if (isa(insert->getTerminator())) { 83 | br = cast(insert->getTerminator()); 84 | } 85 | 86 | if ((br != NULL && br->isConditional()) || 87 | insert->getTerminator()->getNumSuccessors() > 1) { 88 | BasicBlock::iterator i = insert->end(); 89 | --i; 90 | 91 | if (insert->size() > 1) { 92 | --i; 93 | } 94 | 95 | BasicBlock *tmpBB = insert->splitBasicBlock(i, "first"); 96 | origBB.insert(origBB.begin(), tmpBB); 97 | } 98 | 99 | // Remove jump 100 | Instruction* oldTerm=insert->getTerminator(); 101 | 102 | // Create switch variable and set as it 103 | switchVar = 104 | new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar",oldTerm); 105 | oldTerm->eraseFromParent(); 106 | new StoreInst( 107 | ConstantInt::get(Type::getInt32Ty(f->getContext()), 108 | llvm::cryptoutils->scramble32(0, scrambling_key)), 109 | switchVar, insert); 110 | 111 | // Create main loop 112 | loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert); 113 | loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert); 114 | 115 | load = new LoadInst(switchVar, "switchVar", loopEntry); 116 | 117 | // Move first BB on top 118 | insert->moveBefore(loopEntry); 119 | BranchInst::Create(loopEntry, insert); 120 | 121 | // loopEnd jump to loopEntry 122 | BranchInst::Create(loopEntry, loopEnd); 123 | 124 | BasicBlock *swDefault = 125 | BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd); 126 | BranchInst::Create(loopEnd, swDefault); 127 | 128 | // Create switch instruction itself and set condition 129 | switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry); 130 | switchI->setCondition(load); 131 | 132 | // Remove branch jump from 1st BB and make a jump to the while 133 | f->begin()->getTerminator()->eraseFromParent(); 134 | 135 | BranchInst::Create(loopEntry, &*f->begin()); 136 | 137 | // Put all BB in the switch 138 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 139 | ++b) { 140 | BasicBlock *i = *b; 141 | ConstantInt *numCase = NULL; 142 | 143 | // Move the BB inside the switch (only visual, no code logic) 144 | i->moveBefore(loopEnd); 145 | 146 | // Add case to switch 147 | numCase = cast(ConstantInt::get( 148 | switchI->getCondition()->getType(), 149 | llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); 150 | switchI->addCase(numCase, i); 151 | } 152 | 153 | // Recalculate switchVar 154 | for (vector::iterator b = origBB.begin(); b != origBB.end(); 155 | ++b) { 156 | BasicBlock *i = *b; 157 | ConstantInt *numCase = NULL; 158 | 159 | // Ret BB 160 | if (i->getTerminator()->getNumSuccessors() == 0) { 161 | continue; 162 | } 163 | 164 | // If it's a non-conditional jump 165 | if (i->getTerminator()->getNumSuccessors() == 1) { 166 | // Get successor and delete terminator 167 | BasicBlock *succ = i->getTerminator()->getSuccessor(0); 168 | i->getTerminator()->eraseFromParent(); 169 | 170 | // Get next case 171 | numCase = switchI->findCaseDest(succ); 172 | 173 | // If next case == default case (switchDefault) 174 | if (numCase == NULL) { 175 | numCase = cast( 176 | ConstantInt::get(switchI->getCondition()->getType(), 177 | llvm::cryptoutils->scramble32( 178 | switchI->getNumCases() - 1, scrambling_key))); 179 | } 180 | 181 | // Update switchVar and jump to the end of loop 182 | new StoreInst(numCase, load->getPointerOperand(), i); 183 | BranchInst::Create(loopEnd, i); 184 | continue; 185 | } 186 | 187 | // If it's a conditional jump 188 | if (i->getTerminator()->getNumSuccessors() == 2) { 189 | // Get next cases 190 | ConstantInt *numCaseTrue = 191 | switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); 192 | ConstantInt *numCaseFalse = 193 | switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); 194 | 195 | // Check if next case == default case (switchDefault) 196 | if (numCaseTrue == NULL) { 197 | numCaseTrue = cast( 198 | ConstantInt::get(switchI->getCondition()->getType(), 199 | llvm::cryptoutils->scramble32( 200 | switchI->getNumCases() - 1, scrambling_key))); 201 | } 202 | 203 | if (numCaseFalse == NULL) { 204 | numCaseFalse = cast( 205 | ConstantInt::get(switchI->getCondition()->getType(), 206 | llvm::cryptoutils->scramble32( 207 | switchI->getNumCases() - 1, scrambling_key))); 208 | } 209 | 210 | // Create a SelectInst 211 | BranchInst *br = cast(i->getTerminator()); 212 | SelectInst *sel = 213 | SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", 214 | i->getTerminator()); 215 | 216 | // Erase terminator 217 | i->getTerminator()->eraseFromParent(); 218 | // Update switchVar and jump to the end of loop 219 | new StoreInst(sel, load->getPointerOperand(), i); 220 | BranchInst::Create(loopEnd, i); 221 | continue; 222 | } 223 | } 224 | errs()<<"Fixing Stack\n"; 225 | fixStack(f); 226 | errs()<<"Fixed Stack\n"; 227 | return true; 228 | } 229 | -------------------------------------------------------------------------------- /FunctionCallObfuscate.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "json.hpp" 4 | #include "llvm/ADT/Triple.h" 5 | #include "llvm/IR/CallSite.h" 6 | #include "llvm/IR/Constants.h" 7 | #include "llvm/IR/IRBuilder.h" 8 | #include "llvm/IR/Instructions.h" 9 | #include "llvm/IR/LegacyPassManager.h" 10 | #include "llvm/IR/Module.h" 11 | #include "llvm/IR/Value.h" 12 | #include "llvm/Pass.h" 13 | #include "llvm/Support/Path.h" 14 | #include "llvm/Support/raw_ostream.h" 15 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | using namespace llvm; 23 | using namespace std; 24 | using json = nlohmann::json; 25 | static const int DARWIN_FLAG = 0x2 | 0x8; 26 | static const int ANDROID64_FLAG = 0x00002 | 0x100; 27 | static const int ANDROID32_FLAG = 0x0000 | 0x2; 28 | static cl::opt dlopen_flag( 29 | "fco_flag", 30 | cl::desc("The value of RTLD_DEFAULT on your platform"), 31 | cl::value_desc("value"), cl::init(-1), cl::Optional); 32 | static cl::opt 33 | SymbolConfigPath("fcoconfig", 34 | cl::desc("FunctionCallObfuscate Configuration Path"), 35 | cl::value_desc("filename"), cl::init("+-x/")); 36 | namespace llvm { 37 | struct FunctionCallObfuscate : public FunctionPass { 38 | static char ID; 39 | json Configuration; 40 | bool flag; 41 | FunctionCallObfuscate() : FunctionPass(ID) { this->flag = true; } 42 | FunctionCallObfuscate(bool flag) : FunctionPass(ID) { this->flag = flag; } 43 | StringRef getPassName() const override { 44 | return StringRef("FunctionCallObfuscate"); 45 | } 46 | virtual bool doInitialization(Module &M) override { 47 | // Basic Defs 48 | if (SymbolConfigPath == "+-x/") { 49 | SmallString<32> Path; 50 | if (sys::path::home_directory(Path)) { // Stolen from LineEditor.cpp 51 | sys::path::append(Path, "Hikari", "SymbolConfig.json"); 52 | SymbolConfigPath = Path.str(); 53 | } 54 | } 55 | ifstream infile(SymbolConfigPath); 56 | if (infile.good()) { 57 | errs() << "Loading Symbol Configuration From:" << SymbolConfigPath 58 | << "\n"; 59 | infile >> this->Configuration; 60 | } else { 61 | errs() << "Failed To Loading Symbol Configuration From:" 62 | << SymbolConfigPath << "\n"; 63 | } 64 | Triple tri(M.getTargetTriple()); 65 | if (tri.getVendor() != Triple::VendorType::Apple) { 66 | return false; 67 | } 68 | Type *Int64Ty = Type::getInt64Ty(M.getContext()); 69 | Type *Int32Ty = Type::getInt32Ty(M.getContext()); 70 | Type *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); 71 | Type *Int8Ty = Type::getInt8Ty(M.getContext()); 72 | // Generic ObjC Runtime Declarations 73 | FunctionType *IMPType = 74 | FunctionType::get(Int8PtrTy, {Int8PtrTy, Int8PtrTy}, true); 75 | PointerType *IMPPointerType = PointerType::get(IMPType, 0); 76 | vector classReplaceMethodTypeArgs; 77 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 78 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 79 | classReplaceMethodTypeArgs.push_back(IMPPointerType); 80 | classReplaceMethodTypeArgs.push_back(Int8PtrTy); 81 | FunctionType *class_replaceMethod_type = 82 | FunctionType::get(IMPPointerType, classReplaceMethodTypeArgs, false); 83 | M.getOrInsertFunction("class_replaceMethod", class_replaceMethod_type); 84 | FunctionType *sel_registerName_type = 85 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 86 | M.getOrInsertFunction("sel_registerName", sel_registerName_type); 87 | FunctionType *objc_getClass_type = 88 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 89 | M.getOrInsertFunction("objc_getClass", objc_getClass_type); 90 | M.getOrInsertFunction("objc_getMetaClass", objc_getClass_type); 91 | StructType *objc_property_attribute_t_type = reinterpret_cast( 92 | M.getTypeByName("struct.objc_property_attribute_t")); 93 | if (objc_property_attribute_t_type == NULL) { 94 | vector types; 95 | types.push_back(Int8PtrTy); 96 | types.push_back(Int8PtrTy); 97 | objc_property_attribute_t_type = StructType::create( 98 | ArrayRef(types), "struct.objc_property_attribute_t"); 99 | M.getOrInsertGlobal("struct.objc_property_attribute_t", 100 | objc_property_attribute_t_type); 101 | } 102 | vector allocaClsTypeVector; 103 | vector addIvarTypeVector; 104 | vector addPropTypeVector; 105 | allocaClsTypeVector.push_back(Int8PtrTy); 106 | allocaClsTypeVector.push_back(Int8PtrTy); 107 | addIvarTypeVector.push_back(Int8PtrTy); 108 | addIvarTypeVector.push_back(Int8PtrTy); 109 | addPropTypeVector.push_back(Int8PtrTy); 110 | addPropTypeVector.push_back(Int8PtrTy); 111 | addPropTypeVector.push_back(objc_property_attribute_t_type->getPointerTo()); 112 | if (tri.isArch64Bit()) { 113 | // We are 64Bit Device 114 | allocaClsTypeVector.push_back(Int64Ty); 115 | addIvarTypeVector.push_back(Int64Ty); 116 | addPropTypeVector.push_back(Int64Ty); 117 | } else { 118 | // Not 64Bit.However we are still on apple platform.So We are 119 | // ARMV7/ARMV7S/i386 120 | // PowerPC is ignored, feel free to open a PR if you want to 121 | allocaClsTypeVector.push_back(Int32Ty); 122 | addIvarTypeVector.push_back(Int32Ty); 123 | addPropTypeVector.push_back(Int32Ty); 124 | } 125 | addIvarTypeVector.push_back(Int8Ty); 126 | addIvarTypeVector.push_back(Int8PtrTy); 127 | // Types Collected. Now Inject Functions 128 | FunctionType *addIvarType = 129 | FunctionType::get(Int8Ty, ArrayRef(addIvarTypeVector), false); 130 | M.getOrInsertFunction("class_addIvar", addIvarType); 131 | FunctionType *addPropType = 132 | FunctionType::get(Int8Ty, ArrayRef(addPropTypeVector), false); 133 | M.getOrInsertFunction("class_addProperty", addPropType); 134 | FunctionType *class_getName_Type = 135 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 136 | M.getOrInsertFunction("class_getName", class_getName_Type); 137 | FunctionType *objc_getMetaClass_Type = 138 | FunctionType::get(Int8PtrTy, {Int8PtrTy}, false); 139 | M.getOrInsertFunction("objc_getMetaClass", objc_getMetaClass_Type); 140 | return true; 141 | } 142 | void HandleObjC(Module &M) { 143 | // Iterate all CLASSREF uses and replace with objc_getClass() call 144 | // Strings are encrypted in other passes 145 | for (auto G = M.global_begin(); G != M.global_end(); G++) { 146 | GlobalVariable &GV = *G; 147 | if (GV.getName().str().find("OBJC_CLASSLIST_REFERENCES") == 0) { 148 | if (GV.hasInitializer()) { 149 | string className = GV.getInitializer()->getName(); 150 | className.replace(className.find("OBJC_CLASS_$_"), 151 | strlen("OBJC_CLASS_$_"), ""); 152 | for (auto U = GV.user_begin(); U != GV.user_end(); U++) { 153 | if (Instruction *I = dyn_cast(*U)) { 154 | IRBuilder<> builder(I); 155 | Function *objc_getClass_Func = 156 | cast(M.getFunction("objc_getClass")); 157 | Value *newClassName = 158 | builder.CreateGlobalStringPtr(StringRef(className)); 159 | CallInst *CI = 160 | builder.CreateCall(objc_getClass_Func, {newClassName}); 161 | // We need to bitcast it back to avoid IRVerifier 162 | Value *BCI = builder.CreateBitCast(CI, I->getType()); 163 | I->replaceAllUsesWith(BCI); 164 | I->eraseFromParent(); 165 | } 166 | } 167 | GV.removeDeadConstantUsers(); 168 | if (GV.getNumUses() == 0) { 169 | GV.dropAllReferences(); 170 | GV.eraseFromParent(); 171 | } 172 | } 173 | } 174 | // Selector Convert 175 | else if (GV.getName().str().find("OBJC_SELECTOR_REFERENCES") == 0) { 176 | if (GV.hasInitializer()) { 177 | ConstantExpr *CE = dyn_cast(GV.getInitializer()); 178 | Constant *C = CE->getOperand(0); 179 | GlobalVariable *SELNameGV = dyn_cast(C); 180 | ConstantDataArray *CDA = 181 | dyn_cast(SELNameGV->getInitializer()); 182 | StringRef SELName = CDA->getAsString(); // This is REAL Selector Name 183 | for (auto U = GV.user_begin(); U != GV.user_end(); U++) { 184 | if (Instruction *I = dyn_cast(*U)) { 185 | IRBuilder<> builder(I); 186 | Function *sel_registerName_Func = 187 | cast(M.getFunction("sel_registerName")); 188 | Value *newGlobalSELName = builder.CreateGlobalStringPtr(SELName); 189 | CallInst *CI = 190 | builder.CreateCall(sel_registerName_Func, {newGlobalSELName}); 191 | // We need to bitcast it back to avoid IRVerifier 192 | Value *BCI = builder.CreateBitCast(CI, I->getType()); 193 | I->replaceAllUsesWith(BCI); 194 | I->eraseFromParent(); 195 | } 196 | } 197 | GV.removeDeadConstantUsers(); 198 | if (GV.getNumUses() == 0) { 199 | GV.dropAllReferences(); 200 | GV.eraseFromParent(); 201 | } 202 | } 203 | } 204 | } 205 | } 206 | virtual bool runOnFunction(Function &F) override { 207 | // Construct Function Prototypes 208 | if (toObfuscate(flag, &F, "fco") == false) { 209 | return false; 210 | } 211 | Triple Tri(F.getParent()->getTargetTriple()); 212 | if (!Tri.isAndroid() && !Tri.isOSDarwin()) { 213 | errs() << "Unsupported Target Triple:"<< F.getParent()->getTargetTriple() << "\n"; 214 | return false; 215 | } 216 | errs() << "Running FunctionCallObfuscate On " << F.getName() << "\n"; 217 | Module *M = F.getParent(); 218 | FixFunctionConstantExpr(&F); 219 | HandleObjC(*M); 220 | Type *Int32Ty = Type::getInt32Ty(M->getContext()); 221 | Type *Int8PtrTy = Type::getInt8PtrTy(M->getContext()); 222 | // ObjC Runtime Declarations 223 | FunctionType *dlopen_type = FunctionType::get( 224 | Int8PtrTy, {Int8PtrTy, Int32Ty}, 225 | false); // int has a length of 32 on both 32/64bit platform 226 | FunctionType *dlsym_type = 227 | FunctionType::get(Int8PtrTy, {Int8PtrTy, Int8PtrTy}, false); 228 | Function *dlopen_decl = 229 | cast(M->getOrInsertFunction("dlopen", dlopen_type)); 230 | Function *dlsym_decl = 231 | cast(M->getOrInsertFunction("dlsym", dlsym_type)); 232 | // Begin Iteration 233 | for (BasicBlock &BB : F) { 234 | for (auto I = BB.getFirstInsertionPt(), end = BB.end(); I != end; ++I) { 235 | Instruction &Inst = *I; 236 | if (isa(&Inst) || isa(&Inst)) { 237 | CallSite CS(&Inst); 238 | Function *calledFunction = CS.getCalledFunction(); 239 | if (calledFunction == NULL) { 240 | /* 241 | Note: 242 | For Indirect Calls: 243 | CalledFunction is NULL and calledValue is usually a bitcasted 244 | function pointer. We'll need to strip out the hiccups and obtain 245 | the called Function* from there 246 | */ 247 | calledFunction = 248 | dyn_cast(CS.getCalledValue()->stripPointerCasts()); 249 | } 250 | // Simple Extracting Failed 251 | // Use our own implementation 252 | if (calledFunction == NULL) { 253 | DEBUG_WITH_TYPE( 254 | "opt", errs() 255 | << "Failed To Extract Function From Indirect Call: " 256 | << *CS.getCalledValue() << "\n"); 257 | continue; 258 | } 259 | // It's only safe to restrict our modification to external symbols 260 | // Otherwise stripped binary will crash 261 | if (!calledFunction->empty() || 262 | calledFunction->getName().equals("dlsym") || 263 | calledFunction->getName().equals("dlopen") || 264 | calledFunction->isIntrinsic()) { 265 | continue; 266 | } 267 | // errs()<<"Searching For:"<getName()<<" In 268 | // Configuration\n"; 269 | if (this->Configuration.find(calledFunction->getName().str()) != 270 | this->Configuration.end()) { 271 | string sname = this->Configuration[calledFunction->getName().str()] 272 | .get(); 273 | StringRef calledFunctionName = StringRef(sname); 274 | BasicBlock *EntryBlock = CS->getParent(); 275 | IRBuilder<> IRB(EntryBlock, EntryBlock->getFirstInsertionPt()); 276 | vector dlopenargs; 277 | dlopenargs.push_back(Constant::getNullValue(Int8PtrTy)); 278 | if (Tri.isOSDarwin()) { 279 | dlopen_flag=DARWIN_FLAG; 280 | } else if (Tri.isAndroid()) { 281 | if (Tri.isArch64Bit()) { 282 | dlopen_flag=ANDROID64_FLAG; 283 | } else { 284 | dlopen_flag=ANDROID32_FLAG; 285 | } 286 | 287 | } else { 288 | errs() << "[FunctionCallObfuscate]Unsupported Target Triple:" 289 | << F.getParent()->getTargetTriple() << "\n"; 290 | errs()<<"[FunctionCallObfuscate]Applying Default Signature:"<(dlopenargs)); 295 | // Create dlsym call 296 | vector args; 297 | args.push_back(Handle); 298 | args.push_back(IRB.CreateGlobalStringPtr(calledFunctionName)); 299 | Value *fp = IRB.CreateCall(dlsym_decl, ArrayRef(args)); 300 | Value *bitCastedFunction = 301 | IRB.CreateBitCast(fp, CS.getCalledValue()->getType()); 302 | CS.setCalledFunction(bitCastedFunction); 303 | } 304 | } 305 | } 306 | } 307 | return true; 308 | } 309 | }; 310 | FunctionPass *createFunctionCallObfuscatePass() { 311 | return new FunctionCallObfuscate(); 312 | } 313 | FunctionPass *createFunctionCallObfuscatePass(bool flag) { 314 | return new FunctionCallObfuscate(flag); 315 | } 316 | } // namespace llvm 317 | char FunctionCallObfuscate::ID = 0; 318 | INITIALIZE_PASS(FunctionCallObfuscate, "fcoobf", 319 | "Enable Function CallSite Obfuscation.", true, true) 320 | -------------------------------------------------------------------------------- /FunctionWrapper.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/IR/CallSite.h" 4 | #include "llvm/IR/Constants.h" 5 | #include "llvm/IR/IRBuilder.h" 6 | #include "llvm/IR/InstIterator.h" 7 | #include "llvm/IR/Instructions.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/IR/Value.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | using namespace llvm; 17 | using namespace std; 18 | static cl::opt 19 | ProbRate("fw_prob", 20 | cl::desc("Choose the probability [%] For Each CallSite To Be " 21 | "Obfuscated By FunctionWrapper"), 22 | cl::value_desc("Probability Rate"), cl::init(30), cl::Optional); 23 | static cl::opt ObfTimes( 24 | "fw_times", 25 | cl::desc( 26 | "Choose how many time the FunctionWrapper pass loop on a CallSite"), 27 | cl::value_desc("Number of Times"), cl::init(2), cl::Optional); 28 | namespace llvm { 29 | struct FunctionWrapper : public ModulePass { 30 | static char ID; 31 | bool flag; 32 | FunctionWrapper() : ModulePass(ID) { this->flag = true; } 33 | FunctionWrapper(bool flag) : ModulePass(ID) { this->flag = flag; } 34 | StringRef getPassName() const override { 35 | return StringRef("FunctionWrapper"); 36 | } 37 | bool runOnModule(Module &M) override { 38 | vector callsites; 39 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 40 | Function &F = *iter; 41 | if (toObfuscate(flag, &F, "fw")) { 42 | errs() << "Running FunctionWrapper On " << F.getName() << "\n"; 43 | for (inst_iterator fi = inst_begin(&F); fi != inst_end(&F); fi++) { 44 | Instruction *Inst = &*fi; 45 | if (isa(Inst) || isa(Inst)) { 46 | if ((int)llvm::cryptoutils->get_range(100) <= ProbRate) { 47 | callsites.push_back(new CallSite(Inst)); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | for (CallSite *CS : callsites) { 54 | for (int i = 0; i < ObfTimes && CS != nullptr; i++) { 55 | CS = HandleCallSite(CS); 56 | } 57 | } 58 | return true; 59 | } // End of runOnModule 60 | CallSite *HandleCallSite(CallSite *CS) { 61 | Value *calledFunction = CS->getCalledFunction(); 62 | if (calledFunction == nullptr) { 63 | calledFunction = CS->getCalledValue()->stripPointerCasts(); 64 | } 65 | // Filter out IndirectCalls that depends on the context 66 | // Otherwise It'll be blantantly troublesome since you can't reference an 67 | // Instruction outside its BB Too much trouble for a hobby project 68 | // To be precise, we only keep CS that refers to a non-intrinsic function 69 | // either directly or through casting 70 | if (calledFunction == nullptr || 71 | (!isa(calledFunction) && 72 | !isa(calledFunction)) || 73 | CS->getIntrinsicID() != Intrinsic::ID::not_intrinsic) { 74 | return nullptr; 75 | } 76 | if (Function *tmp = dyn_cast(calledFunction)) { 77 | if (tmp->getName().startswith("clang.")) { 78 | // Clang Intrinsic 79 | return nullptr; 80 | } 81 | for(auto argiter = tmp->arg_begin(); argiter!= tmp->arg_end(); ++argiter) { 82 | Argument& arg=*(argiter); 83 | if(arg.hasByValAttr()){ 84 | // Arguments with byval attribute yields issues without proper handling. 85 | // The "proper" method to handle this is to revisit and patch attribute stealing code. 86 | // Technically readonly attr probably should also get filtered out here. 87 | 88 | // Nah too much work. This would do for open-source version since private already 89 | // this pass with more advanced solutions 90 | return nullptr; 91 | } 92 | } 93 | } 94 | // Create a new function which in turn calls the actual function 95 | vector types; 96 | for (unsigned i = 0; i < CS->getNumArgOperands(); i++) { 97 | types.push_back(CS->getArgOperand(i)->getType()); 98 | } 99 | FunctionType *ft = 100 | FunctionType::get(CS->getType(), ArrayRef(types), false); 101 | Function *func = 102 | Function::Create(ft, GlobalValue::LinkageTypes::InternalLinkage, 103 | "HikariFunctionWrapper", CS->getParent()->getModule()); 104 | //Trolling was all fun and shit so old implementation forced this symbol to exist in all objects 105 | appendToCompilerUsed(*func->getParent(), {func}); 106 | BasicBlock *BB = BasicBlock::Create(func->getContext(), "", func); 107 | IRBuilder<> IRB(BB); 108 | vector params; 109 | for (auto arg = func->arg_begin(); arg != func->arg_end(); arg++) { 110 | params.push_back(arg); 111 | } 112 | Value *retval = IRB.CreateCall(ConstantExpr::getBitCast(cast(calledFunction),CS->getCalledValue()->getType()), ArrayRef(params)); 113 | if (ft->getReturnType()->isVoidTy()) { 114 | IRB.CreateRetVoid(); 115 | } else { 116 | IRB.CreateRet(retval); 117 | } 118 | CS->setCalledFunction(func); 119 | CS->mutateFunctionType(ft); 120 | Instruction *Inst = CS->getInstruction(); 121 | delete CS; 122 | return new CallSite(Inst); 123 | } 124 | }; 125 | ModulePass *createFunctionWrapperPass() { return new FunctionWrapper(); } 126 | ModulePass *createFunctionWrapperPass(bool flag) { 127 | return new FunctionWrapper(flag); 128 | } 129 | } // namespace llvm 130 | 131 | char FunctionWrapper::ID = 0; 132 | INITIALIZE_PASS(FunctionWrapper, "funcwra", "Enable FunctionWrapper.", true, 133 | true) 134 | -------------------------------------------------------------------------------- /IndirectBranch.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/IR/Constants.h" 4 | #include "llvm/IR/IRBuilder.h" 5 | #include "llvm/IR/InstIterator.h" 6 | #include "llvm/IR/Instructions.h" 7 | #include "llvm/IR/Module.h" 8 | #include "llvm/IR/Value.h" 9 | #include "llvm/Pass.h" 10 | #include "llvm/Support/CommandLine.h" 11 | #include "llvm/Support/raw_ostream.h" 12 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 13 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 14 | using namespace llvm; 15 | using namespace std; 16 | namespace llvm { 17 | struct IndirectBranch : public FunctionPass { 18 | static char ID; 19 | bool flag; 20 | bool initialized; 21 | map indexmap; 22 | IndirectBranch() : FunctionPass(ID) { 23 | this->flag = true; 24 | this->initialized = false; 25 | } 26 | IndirectBranch(bool flag) : FunctionPass(ID) { 27 | this->flag = flag; 28 | this->initialized = false; 29 | } 30 | StringRef getPassName() const override { return StringRef("IndirectBranch"); } 31 | bool initialize(Module &M) { 32 | vector BBs; 33 | unsigned long long i = 0; 34 | for (auto F = M.begin(); F != M.end(); F++) { 35 | for (auto BB = F->begin(); BB != F->end(); BB++) { 36 | BasicBlock *BBPtr = &*BB; 37 | if (BBPtr != &(BBPtr->getParent()->getEntryBlock())) { 38 | indexmap[BBPtr] = i++; 39 | BBs.push_back(BlockAddress::get(BBPtr)); 40 | } 41 | } 42 | } 43 | ArrayType *AT = 44 | ArrayType::get(Type::getInt8PtrTy(M.getContext()), BBs.size()); 45 | Constant *BlockAddressArray = 46 | ConstantArray::get(AT, ArrayRef(BBs)); 47 | GlobalVariable *Table = new GlobalVariable( 48 | M, AT, false, GlobalValue::LinkageTypes::InternalLinkage, 49 | BlockAddressArray, "IndirectBranchingGlobalTable"); 50 | appendToCompilerUsed(M, {Table}); 51 | return true; 52 | } 53 | bool runOnFunction(Function &Func) override { 54 | if (!toObfuscate(flag, &Func, "indibr")) { 55 | return false; 56 | } 57 | if (this->initialized == false) { 58 | initialize(*Func.getParent()); 59 | this->initialized = true; 60 | } 61 | errs() << "Running IndirectBranch On " << Func.getName() << "\n"; 62 | vector BIs; 63 | for (inst_iterator I = inst_begin(Func); I != inst_end(Func); I++) { 64 | Instruction *Inst = &(*I); 65 | if (BranchInst *BI = dyn_cast(Inst)) { 66 | BIs.push_back(BI); 67 | } 68 | } // Finish collecting branching conditions 69 | Value *zero = 70 | ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), 0); 71 | for (BranchInst *BI : BIs) { 72 | IRBuilder<> IRB(BI); 73 | vector BBs; 74 | // We use the condition's evaluation result to generate the GEP 75 | // instruction False evaluates to 0 while true evaluates to 1. So here 76 | // we insert the false block first 77 | if (BI->isConditional()) { 78 | BBs.push_back(BI->getSuccessor(1)); 79 | } 80 | BBs.push_back(BI->getSuccessor(0)); 81 | ArrayType *AT = ArrayType::get( 82 | Type::getInt8PtrTy(Func.getParent()->getContext()), BBs.size()); 83 | vector BlockAddresses; 84 | for (unsigned i = 0; i < BBs.size(); i++) { 85 | BlockAddresses.push_back(BlockAddress::get(BBs[i])); 86 | } 87 | GlobalVariable *LoadFrom = NULL; 88 | 89 | if (BI->isConditional() || 90 | indexmap.find(BI->getSuccessor(0)) == indexmap.end()) { 91 | // Create a new GV 92 | Constant *BlockAddressArray = 93 | ConstantArray::get(AT, ArrayRef(BlockAddresses)); 94 | LoadFrom = new GlobalVariable( 95 | *Func.getParent(), AT, false, 96 | GlobalValue::LinkageTypes::PrivateLinkage, BlockAddressArray, 97 | "HikariConditionalLocalIndirectBranchingTable"); 98 | appendToCompilerUsed(*Func.getParent(), {LoadFrom}); 99 | } else { 100 | LoadFrom = Func.getParent()->getGlobalVariable( 101 | "IndirectBranchingGlobalTable", true); 102 | } 103 | Value *index = NULL; 104 | if (BI->isConditional()) { 105 | Value *condition = BI->getCondition(); 106 | index = IRB.CreateZExt( 107 | condition, Type::getInt32Ty(Func.getParent()->getContext())); 108 | } else { 109 | index = 110 | ConstantInt::get(Type::getInt32Ty(Func.getParent()->getContext()), 111 | indexmap[BI->getSuccessor(0)]); 112 | } 113 | Value *GEP = IRB.CreateGEP(LoadFrom, {zero, index}); 114 | LoadInst *LI = IRB.CreateLoad(GEP, "IndirectBranchingTargetAddress"); 115 | IndirectBrInst *indirBr = IndirectBrInst::Create(LI, BBs.size()); 116 | for (BasicBlock *BB : BBs) { 117 | indirBr->addDestination(BB); 118 | } 119 | ReplaceInstWithInst(BI, indirBr); 120 | } 121 | return true; 122 | } 123 | virtual bool doFinalization(Module &M) override { 124 | indexmap.clear(); 125 | initialized = false; 126 | return false; 127 | } 128 | }; 129 | } // namespace llvm 130 | FunctionPass *llvm::createIndirectBranchPass() { return new IndirectBranch(); } 131 | FunctionPass *llvm::createIndirectBranchPass(bool flag) { 132 | return new IndirectBranch(flag); 133 | } 134 | char IndirectBranch::ID = 0; 135 | INITIALIZE_PASS(IndirectBranch, "indibran", "IndirectBranching", true, true) 136 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Obfuscation.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | /* 4 | Hikari 's own "Pass Scheduler". 5 | Because currently there is no way to add dependency to transform passes 6 | Ref : http://lists.llvm.org/pipermail/llvm-dev/2011-February/038109.html 7 | */ 8 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 9 | #include 10 | using namespace llvm; 11 | using namespace std; 12 | // Begin Obfuscator Options 13 | static cl::opt AesSeed("aesSeed", cl::init(0x1337), 14 | cl::desc("seed for the PRNG")); 15 | static cl::opt EnableAntiClassDump("enable-acdobf", cl::init(false), 16 | cl::NotHidden, 17 | cl::desc("Enable AntiClassDump.")); 18 | static cl::opt 19 | EnableBogusControlFlow("enable-bcfobf", cl::init(false), cl::NotHidden, 20 | cl::desc("Enable BogusControlFlow.")); 21 | static cl::opt EnableFlattening("enable-cffobf", cl::init(false), 22 | cl::NotHidden, 23 | cl::desc("Enable Flattening.")); 24 | static cl::opt 25 | EnableBasicBlockSplit("enable-splitobf", cl::init(false), cl::NotHidden, 26 | cl::desc("Enable BasicBlockSpliting.")); 27 | static cl::opt 28 | EnableSubstitution("enable-subobf", cl::init(false), cl::NotHidden, 29 | cl::desc("Enable Instruction Substitution.")); 30 | static cl::opt EnableAllObfuscation("enable-allobf", cl::init(false), 31 | cl::NotHidden, 32 | cl::desc("Enable All Obfuscation.")); 33 | static cl::opt EnableFunctionCallObfuscate( 34 | "enable-fco", cl::init(false), cl::NotHidden, 35 | cl::desc("Enable Function CallSite Obfuscation.")); 36 | static cl::opt 37 | EnableStringEncryption("enable-strcry", cl::init(false), cl::NotHidden, 38 | cl::desc("Enable Function CallSite Obfuscation.")); 39 | static cl::opt 40 | EnableIndirectBranching("enable-indibran", cl::init(false), cl::NotHidden, 41 | cl::desc("Enable Indirect Branching.")); 42 | static cl::opt 43 | EnableFunctionWrapper("enable-funcwra", cl::init(false), cl::NotHidden, 44 | cl::desc("Enable Function Wrapper.")); 45 | // End Obfuscator Options 46 | 47 | static void LoadEnv() { 48 | if (getenv("SPLITOBF")) { 49 | EnableBasicBlockSplit = true; 50 | } 51 | if (getenv("SUBOBF")) { 52 | EnableSubstitution = true; 53 | } 54 | if (getenv("ALLOBF")) { 55 | EnableAllObfuscation = true; 56 | } 57 | if (getenv("FCO")) { 58 | EnableFunctionCallObfuscate = true; 59 | } 60 | if (getenv("STRCRY")) { 61 | EnableStringEncryption = true; 62 | } 63 | if (getenv("INDIBRAN")) { 64 | EnableIndirectBranching = true; 65 | } 66 | if (getenv("FUNCWRA")) { 67 | EnableFunctionWrapper = true;//Broken 68 | } 69 | if (getenv("BCFOBF")) { 70 | EnableBogusControlFlow = true; 71 | } 72 | if (getenv("ACDOBF")) { 73 | EnableAntiClassDump = true; 74 | } 75 | if (getenv("CFFOBF")) { 76 | EnableFlattening = true; 77 | } 78 | } 79 | namespace llvm { 80 | struct Obfuscation : public ModulePass { 81 | static char ID; 82 | Obfuscation() : ModulePass(ID) {} 83 | StringRef getPassName() const override { 84 | return StringRef("HikariObfuscationScheduler"); 85 | } 86 | bool runOnModule(Module &M) override { 87 | // Initial ACD Pass 88 | if (EnableAllObfuscation || EnableAntiClassDump) { 89 | ModulePass *P = createAntiClassDumpPass(); 90 | P->doInitialization(M); 91 | P->runOnModule(M); 92 | delete P; 93 | } 94 | // Now do FCO 95 | FunctionPass *FP = createFunctionCallObfuscatePass( 96 | EnableAllObfuscation || EnableFunctionCallObfuscate); 97 | FP->doInitialization(M); 98 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 99 | Function &F = *iter; 100 | if (!F.isDeclaration()) { 101 | FP->runOnFunction(F); 102 | } 103 | } 104 | delete FP; 105 | // Now Encrypt Strings 106 | ModulePass *MP = createStringEncryptionPass(EnableAllObfuscation || 107 | EnableStringEncryption); 108 | MP->runOnModule(M); 109 | delete MP; 110 | /* 111 | // Placing FW here does provide the most obfuscation however the compile 112 | time 113 | // and product size would be literally unbearable for any large project 114 | // Move it to post run 115 | if (EnableAllObfuscation || EnableFunctionWrapper) { 116 | ModulePass *P = createFunctionWrapperPass(); 117 | P->runOnModule(M); 118 | delete P; 119 | }*/ 120 | // Now perform Function-Level Obfuscation 121 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 122 | Function &F = *iter; 123 | if (!F.isDeclaration()) { 124 | FunctionPass *P = NULL; 125 | P = createSplitBasicBlockPass(EnableAllObfuscation || 126 | EnableBasicBlockSplit); 127 | P->runOnFunction(F); 128 | delete P; 129 | P = createBogusControlFlowPass(EnableAllObfuscation || 130 | EnableBogusControlFlow); 131 | P->runOnFunction(F); 132 | delete P; 133 | P = createFlatteningPass(EnableAllObfuscation || EnableFlattening); 134 | P->runOnFunction(F); 135 | delete P; 136 | P = createSubstitutionPass(EnableAllObfuscation || EnableSubstitution); 137 | P->runOnFunction(F); 138 | delete P; 139 | } 140 | } 141 | errs() << "Doing Post-Run Cleanup\n"; 142 | FunctionPass *P = createIndirectBranchPass(EnableAllObfuscation || 143 | EnableIndirectBranching); 144 | vector funcs; 145 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 146 | funcs.push_back(&*iter); 147 | } 148 | for (Function *F : funcs) { 149 | P->runOnFunction(*F); 150 | } 151 | delete P; 152 | MP = createFunctionWrapperPass(EnableAllObfuscation || 153 | EnableFunctionWrapper); 154 | MP->runOnModule(M); 155 | delete MP; 156 | // Cleanup Flags 157 | vector toDelete; 158 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 159 | Function &F = *iter; 160 | if (F.isDeclaration() && F.hasName() && 161 | F.getName().contains("hikari_")) { 162 | for (User *U : F.users()) { 163 | if (Instruction *Inst = dyn_cast(U)) { 164 | Inst->eraseFromParent(); 165 | } 166 | } 167 | toDelete.push_back(&F); 168 | } 169 | } 170 | for (Function *F : toDelete) { 171 | F->eraseFromParent(); 172 | } 173 | errs() << "Hikari Out\n"; 174 | return true; 175 | } // End runOnModule 176 | }; 177 | ModulePass *createObfuscationPass() { 178 | LoadEnv(); 179 | if (AesSeed!=0x1337) { 180 | cryptoutils->prng_seed(AesSeed); 181 | } 182 | else{ 183 | cryptoutils->prng_seed(); 184 | } 185 | cout<<"Initializing Hikari Core with Revision ID:"< SplitNum("split_num", cl::init(2), 16 | cl::desc("Split time each BB")); 17 | 18 | namespace { 19 | struct SplitBasicBlock : public FunctionPass { 20 | static char ID; // Pass identification, replacement for typeid 21 | bool flag; 22 | SplitBasicBlock() : FunctionPass(ID) { this->flag = true; } 23 | SplitBasicBlock(bool flag) : FunctionPass(ID) { this->flag = flag; } 24 | 25 | bool runOnFunction(Function &F); 26 | void split(Function *f); 27 | 28 | bool containsPHI(BasicBlock *b); 29 | void shuffle(std::vector &vec); 30 | }; 31 | } // namespace 32 | 33 | char SplitBasicBlock::ID = 0; 34 | INITIALIZE_PASS(SplitBasicBlock, "splitobf", "Enable BasicBlockSpliting.", true, 35 | true) 36 | FunctionPass *llvm::createSplitBasicBlockPass() { 37 | return new SplitBasicBlock(); 38 | } 39 | FunctionPass *llvm::createSplitBasicBlockPass(bool flag) { 40 | return new SplitBasicBlock(flag); 41 | } 42 | 43 | bool SplitBasicBlock::runOnFunction(Function &F) { 44 | // Check if the number of applications is correct 45 | if (!((SplitNum > 1) && (SplitNum <= 10))) { 46 | errs() << "Split application basic block percentage\ 47 | -split_num=x must be 1 < x <= 10"; 48 | return false; 49 | } 50 | 51 | Function *tmp = &F; 52 | 53 | // Do we obfuscate 54 | if (toObfuscate(flag, tmp, "split")) { 55 | errs() << "Running BasicBlockSplit On " << tmp->getName() << "\n"; 56 | split(tmp); 57 | ++Split; 58 | } 59 | 60 | return false; 61 | } 62 | 63 | void SplitBasicBlock::split(Function *f) { 64 | std::vector origBB; 65 | int splitN = SplitNum; 66 | 67 | // Save all basic blocks 68 | for (Function::iterator I = f->begin(), IE = f->end(); I != IE; ++I) { 69 | origBB.push_back(&*I); 70 | } 71 | 72 | for (std::vector::iterator I = origBB.begin(), 73 | IE = origBB.end(); 74 | I != IE; ++I) { 75 | BasicBlock *curr = *I; 76 | 77 | // No need to split a 1 inst bb 78 | // Or ones containing a PHI node 79 | if (curr->size() < 2 || containsPHI(curr)) { 80 | continue; 81 | } 82 | 83 | // Check splitN and current BB size 84 | if ((size_t)splitN > curr->size()) { 85 | splitN = curr->size() - 1; 86 | } 87 | 88 | // Generate splits point 89 | std::vector test; 90 | for (unsigned i = 1; i < curr->size(); ++i) { 91 | test.push_back(i); 92 | } 93 | 94 | // Shuffle 95 | if (test.size() != 1) { 96 | shuffle(test); 97 | std::sort(test.begin(), test.begin() + splitN); 98 | } 99 | 100 | // Split 101 | BasicBlock::iterator it = curr->begin(); 102 | BasicBlock *toSplit = curr; 103 | int last = 0; 104 | for (int i = 0; i < splitN; ++i) { 105 | for (int j = 0; j < test[i] - last; ++j) { 106 | ++it; 107 | } 108 | last = test[i]; 109 | if (toSplit->size() < 2) 110 | continue; 111 | toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split"); 112 | } 113 | 114 | ++Split; 115 | } 116 | } 117 | 118 | bool SplitBasicBlock::containsPHI(BasicBlock *b) { 119 | for (BasicBlock::iterator I = b->begin(), IE = b->end(); I != IE; ++I) { 120 | if (isa(I)) { 121 | return true; 122 | } 123 | } 124 | return false; 125 | } 126 | 127 | void SplitBasicBlock::shuffle(std::vector &vec) { 128 | int n = vec.size(); 129 | for (int i = n - 1; i > 0; --i) { 130 | std::swap(vec[i], vec[cryptoutils->get_uint32_t() % (i + 1)]); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /StringEncryption.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/Transforms/Obfuscation/StringEncryption.h" 4 | #include "llvm/IR/Constants.h" 5 | #include "llvm/IR/IRBuilder.h" 6 | #include "llvm/IR/Instructions.h" 7 | #include "llvm/IR/LegacyPassManager.h" 8 | #include "llvm/IR/Module.h" 9 | #include "llvm/IR/Value.h" 10 | #include "llvm/Pass.h" 11 | #include "llvm/Support/CommandLine.h" 12 | #include "llvm/Support/TargetSelect.h" 13 | #include "llvm/Support/raw_ostream.h" 14 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 15 | #include "llvm/Transforms/Obfuscation/CryptoUtils.h" 16 | #include "llvm/Transforms/Obfuscation/Obfuscation.h" 17 | #include "llvm/Transforms/Obfuscation/Utils.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using namespace llvm; 24 | using namespace std; 25 | namespace llvm { 26 | struct StringEncryption : public ModulePass { 27 | static char ID; 28 | map 29 | encstatus; 30 | bool flag; 31 | StringEncryption() : ModulePass(ID) { this->flag = true; } 32 | StringEncryption(bool flag) : ModulePass(ID) { this->flag = flag; } 33 | StringRef getPassName() const override { 34 | return StringRef("StringEncryption"); 35 | } 36 | bool runOnModule(Module &M) override { 37 | // in runOnModule. We simple iterate function list and dispatch functions 38 | // to handlers 39 | for (Module::iterator iter = M.begin(); iter != M.end(); iter++) { 40 | Function *F = &(*iter); 41 | 42 | if (toObfuscate(flag, F, "strenc")) { 43 | errs() << "Running StringEncryption On " << F->getName() << "\n"; 44 | Constant *S = ConstantInt::get(Type::getInt32Ty(M.getContext()), 0); 45 | GlobalVariable *GV = new GlobalVariable( 46 | M, S->getType(), false, GlobalValue::LinkageTypes::PrivateLinkage, 47 | S, ""); 48 | encstatus[F] = GV; 49 | HandleFunction(F); 50 | } 51 | } 52 | return true; 53 | } // End runOnModule 54 | void HandleFunction(Function *Func) { 55 | FixFunctionConstantExpr(Func); 56 | set Globals; 57 | set Users; 58 | for (BasicBlock &BB : *Func) { 59 | for (Instruction &I : BB) { 60 | for (Value *Op : I.operands()) { 61 | if (GlobalVariable *G = dyn_cast(Op->stripPointerCasts())) { 62 | if(User* U=dyn_cast(Op)){ 63 | Users.insert(U); 64 | } 65 | Users.insert(&I); 66 | Globals.insert(G); 67 | } 68 | } 69 | } 70 | } 71 | set rawStrings; 72 | set objCStrings; 73 | map> GV2Keys; 74 | map> old2new; 75 | for (GlobalVariable *GV : Globals) { 76 | if (GV->hasInitializer() && 77 | GV->getSection() != StringRef("llvm.metadata") && 78 | GV->getSection().find(StringRef("__objc")) == string::npos && 79 | GV->getName().find("OBJC") == string::npos) { 80 | if (GV->getInitializer()->getType() == 81 | Func->getParent()->getTypeByName("struct.__NSConstantString_tag")) { 82 | objCStrings.insert(GV); 83 | rawStrings.insert( 84 | cast(cast(GV->getInitializer()) 85 | ->getOperand(2) 86 | ->stripPointerCasts())); 87 | 88 | } else if (isa(GV->getInitializer())) { 89 | rawStrings.insert(GV); 90 | }else if(isa(GV->getInitializer())){ 91 | ConstantArray* CA=cast(GV->getInitializer()); 92 | for(unsigned i=0;igetNumOperands();i++){ 93 | Value* op=CA->getOperand(i)->stripPointerCasts(); 94 | if(GlobalVariable* GV=dyn_cast(op)){ 95 | Globals.insert(GV); 96 | } 97 | } 98 | 99 | } 100 | } 101 | } 102 | for (GlobalVariable *GV : rawStrings) { 103 | if (GV->getInitializer()->isZeroValue() || 104 | GV->getInitializer()->isNullValue()) { 105 | continue; 106 | } 107 | ConstantDataSequential *CDS = 108 | cast(GV->getInitializer()); 109 | Type *memberType = CDS->getElementType(); 110 | // Ignore non-IntegerType 111 | if (!isa(memberType)) { 112 | continue; 113 | } 114 | IntegerType *intType = cast(memberType); 115 | Constant *KeyConst = NULL; 116 | Constant *EncryptedConst = NULL; 117 | Constant *DummyConst = NULL; 118 | if (intType == Type::getInt8Ty(GV->getParent()->getContext())) { 119 | vector keys; 120 | vector encry; 121 | vector dummy; 122 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 123 | uint8_t K = cryptoutils->get_uint8_t(); 124 | uint64_t V = CDS->getElementAsInteger(i); 125 | keys.push_back(K); 126 | encry.push_back(K ^ V); 127 | dummy.push_back(rand()); 128 | } 129 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 130 | ArrayRef(keys)); 131 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 132 | ArrayRef(encry)); 133 | DummyConst = ConstantDataArray::get(GV->getParent()->getContext(), 134 | ArrayRef(dummy)); 135 | 136 | } else if (intType == Type::getInt16Ty(GV->getParent()->getContext())) { 137 | vector keys; 138 | vector encry; 139 | vector dummy; 140 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 141 | uint16_t K = cryptoutils->get_uint16_t(); 142 | uint64_t V = CDS->getElementAsInteger(i); 143 | keys.push_back(K); 144 | encry.push_back(K ^ V); 145 | dummy.push_back(rand()); 146 | } 147 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 148 | ArrayRef(keys)); 149 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 150 | ArrayRef(encry)); 151 | DummyConst = ConstantDataArray::get(GV->getParent()->getContext(), 152 | ArrayRef(dummy)); 153 | } else if (intType == Type::getInt32Ty(GV->getParent()->getContext())) { 154 | vector keys; 155 | vector encry; 156 | vector dummy; 157 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 158 | uint32_t K = cryptoutils->get_uint32_t(); 159 | uint64_t V = CDS->getElementAsInteger(i); 160 | keys.push_back(K); 161 | encry.push_back(K ^ V); 162 | dummy.push_back(rand()); 163 | } 164 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 165 | ArrayRef(keys)); 166 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 167 | ArrayRef(encry)); 168 | DummyConst = ConstantDataArray::get(GV->getParent()->getContext(), 169 | ArrayRef(dummy)); 170 | } else if (intType == Type::getInt64Ty(GV->getParent()->getContext())) { 171 | vector keys; 172 | vector encry; 173 | vector dummy; 174 | for (unsigned i = 0; i < CDS->getNumElements(); i++) { 175 | uint64_t K = cryptoutils->get_uint64_t(); 176 | uint64_t V = CDS->getElementAsInteger(i); 177 | keys.push_back(K); 178 | encry.push_back(K ^ V); 179 | dummy.push_back(rand()); 180 | } 181 | KeyConst = ConstantDataArray::get(GV->getParent()->getContext(), 182 | ArrayRef(keys)); 183 | EncryptedConst = ConstantDataArray::get(GV->getParent()->getContext(), 184 | ArrayRef(encry)); 185 | DummyConst = ConstantDataArray::get(GV->getParent()->getContext(), 186 | ArrayRef(dummy)); 187 | } else { 188 | errs() << "Unsupported CDS Type\n"; 189 | abort(); 190 | } 191 | // Prepare new rawGV 192 | GlobalVariable *EncryptedRawGV = new GlobalVariable( 193 | *(GV->getParent()), EncryptedConst->getType(), false, 194 | GV->getLinkage(), EncryptedConst, "EncryptedString", nullptr, 195 | GV->getThreadLocalMode(), GV->getType()->getAddressSpace()); 196 | GlobalVariable *DecryptSpaceGV = new GlobalVariable( 197 | *(GV->getParent()), DummyConst->getType(), false, 198 | GV->getLinkage(), DummyConst, "DecryptSpace", nullptr, 199 | GV->getThreadLocalMode(), GV->getType()->getAddressSpace()); 200 | old2new[GV] = make_pair(EncryptedRawGV, DecryptSpaceGV); 201 | GV2Keys[DecryptSpaceGV] = make_pair(KeyConst, EncryptedRawGV); 202 | } 203 | // Now prepare ObjC new GV 204 | for (GlobalVariable *GV : objCStrings) { 205 | ConstantStruct *CS = cast(GV->getInitializer()); 206 | GlobalVariable *oldrawString = cast(CS->getOperand(2)->stripPointerCasts()); 207 | if (old2new.find(oldrawString) == old2new.end()) { // Filter out zero initializers 208 | continue; 209 | } 210 | GlobalVariable *EncryptedOCGV = ObjectivCString(GV, "EncryptedStringObjC", oldrawString, old2new[oldrawString].first, CS); 211 | GlobalVariable *DecryptSpaceOCGV = ObjectivCString(GV, "DecryptSpaceObjC", oldrawString, old2new[oldrawString].second, CS); 212 | old2new[GV] = make_pair(EncryptedOCGV, DecryptSpaceOCGV); 213 | } // End prepare ObjC new GV 214 | if(old2new.empty() || GV2Keys.empty()) 215 | return; 216 | // Replace Uses 217 | for (User *U : Users) { 218 | for (map>::iterator iter = 219 | old2new.begin(); 220 | iter != old2new.end(); ++iter) { 221 | U->replaceUsesOfWith(iter->first, iter->second.second); 222 | iter->first->removeDeadConstantUsers(); 223 | } 224 | } // End Replace Uses 225 | // CleanUp Old ObjC GVs 226 | for (GlobalVariable *GV : objCStrings) { 227 | if (GV->getNumUses() == 0) { 228 | GV->dropAllReferences(); 229 | old2new.erase(GV); 230 | GV->eraseFromParent(); 231 | } 232 | } 233 | // CleanUp Old Raw GVs 234 | for (map>::iterator iter = 235 | old2new.begin(); 236 | iter != old2new.end(); ++iter) { 237 | GlobalVariable *toDelete = iter->first; 238 | toDelete->removeDeadConstantUsers(); 239 | if (toDelete->getNumUses() == 0) { 240 | toDelete->dropAllReferences(); 241 | toDelete->eraseFromParent(); 242 | } 243 | } 244 | GlobalVariable *StatusGV = encstatus[Func]; 245 | /* 246 | - Split Original EntryPoint BB into A and C. 247 | - Create new BB as Decryption BB between A and C. Adjust the terminators 248 | into: A (Alloca a new array containing all) 249 | | 250 | B(If not decrypted) 251 | | 252 | C 253 | */ 254 | BasicBlock *A = &(Func->getEntryBlock()); 255 | BasicBlock *C = A->splitBasicBlock(A->getFirstNonPHIOrDbgOrLifetime()); 256 | C->setName("PrecedingBlock"); 257 | BasicBlock *B = 258 | BasicBlock::Create(Func->getContext(), "StringDecryptionBB", Func, C); 259 | // Change A's terminator to jump to B 260 | // We'll add new terminator to jump C later 261 | BranchInst *newBr = BranchInst::Create(B); 262 | ReplaceInstWithInst(A->getTerminator(), newBr); 263 | IRBuilder<> IRB(A->getFirstNonPHIOrDbgOrLifetime()); 264 | // Insert DecryptionCode 265 | HandleDecryptionBlock(B, C, GV2Keys); 266 | // Add atomic load checking status in A 267 | LoadInst *LI = IRB.CreateLoad(StatusGV, "LoadEncryptionStatus"); 268 | LI->setAtomic(AtomicOrdering::Acquire); // Will be released at the start of 269 | // C 270 | LI->setAlignment(4); 271 | Value *condition = IRB.CreateICmpEQ( 272 | LI, ConstantInt::get(Type::getInt32Ty(Func->getContext()), 0)); 273 | A->getTerminator()->eraseFromParent(); 274 | BranchInst::Create(B, C, condition, A); 275 | // Add StoreInst atomically in C start 276 | // No matter control flow is coming from A or B, the GVs must be decrypted 277 | IRBuilder<> IRBC(C->getFirstNonPHIOrDbgOrLifetime()); 278 | StoreInst *SI = IRBC.CreateStore( 279 | ConstantInt::get(Type::getInt32Ty(Func->getContext()), 1), StatusGV); 280 | SI->setAlignment(4); 281 | SI->setAtomic(AtomicOrdering::Release); // Release the lock acquired in LI 282 | 283 | } // End of HandleFunction 284 | 285 | GlobalVariable *ObjectivCString(GlobalVariable *GV, string name, GlobalVariable *oldrawString, GlobalVariable *newString, ConstantStruct *CS) { 286 | Value *zero = ConstantInt::get(Type::getInt32Ty(GV->getContext()), 0); 287 | vector vals; 288 | vals.push_back(CS->getOperand(0)); 289 | vals.push_back(CS->getOperand(1)); 290 | Constant *GEPed = ConstantExpr::getInBoundsGetElementPtr(nullptr, newString, {zero, zero}); 291 | if (GEPed->getType() == CS->getOperand(2)->getType()) { 292 | vals.push_back(GEPed); 293 | } else { 294 | Constant *BitCasted = ConstantExpr::getBitCast(newString, CS->getOperand(2)->getType()); 295 | vals.push_back(BitCasted); 296 | } 297 | vals.push_back(CS->getOperand(3)); 298 | Constant *newCS = ConstantStruct::get(CS->getType(), ArrayRef(vals)); 299 | return new GlobalVariable( 300 | *(GV->getParent()), newCS->getType(), false, GV->getLinkage(), newCS, 301 | name.c_str(), nullptr, GV->getThreadLocalMode(), 302 | GV->getType()->getAddressSpace()); 303 | } 304 | 305 | void HandleDecryptionBlock(BasicBlock *B, BasicBlock *C, 306 | map> &GV2Keys) { 307 | IRBuilder<> IRB(B); 308 | Value *zero = ConstantInt::get(Type::getInt32Ty(B->getContext()), 0); 309 | for (map>::iterator iter = GV2Keys.begin(); 310 | iter != GV2Keys.end(); ++iter) { 311 | ConstantDataArray *CastedCDA = cast(iter->second.first); 312 | // Prevent optimization of encrypted data 313 | appendToCompilerUsed(*iter->second.second->getParent(), 314 | {iter->second.second}); 315 | // Element-By-Element XOR so the fucking verifier won't complain 316 | // Also, this hides keys 317 | for (unsigned i = 0; i < CastedCDA->getType()->getNumElements(); i++) { 318 | Value *offset = ConstantInt::get(Type::getInt32Ty(B->getContext()), i); 319 | Value *EncryptedGEP = IRB.CreateGEP(iter->second.second, {zero, offset}); 320 | Value *DecryptedGEP = IRB.CreateGEP(iter->first, {zero, offset}); 321 | LoadInst *LI = IRB.CreateLoad(EncryptedGEP, "EncryptedChar"); 322 | Value *XORed = IRB.CreateXor(LI, CastedCDA->getElementAsConstant(i)); 323 | IRB.CreateStore(XORed, DecryptedGEP); 324 | } 325 | } 326 | IRB.CreateBr(C); 327 | } // End of HandleDecryptionBlock 328 | bool doFinalization(Module &M) override { 329 | encstatus.clear(); 330 | return false; 331 | } 332 | }; 333 | ModulePass *createStringEncryptionPass() { return new StringEncryption(); } 334 | ModulePass *createStringEncryptionPass(bool flag) { 335 | return new StringEncryption(flag); 336 | } 337 | } // namespace llvm 338 | 339 | char StringEncryption::ID = 0; 340 | INITIALIZE_PASS(StringEncryption, "strcry", "Enable String Encryption", true, 341 | true) 342 | -------------------------------------------------------------------------------- /Substitution.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/Transforms/Obfuscation/Substitution.h" 4 | #include "llvm/IR/Intrinsics.h" 5 | #include "llvm/IR/LLVMContext.h" 6 | #include "llvm/Support/raw_ostream.h" 7 | #include "llvm/Transforms/Obfuscation/Utils.h" 8 | 9 | #define DEBUG_TYPE "substitution" 10 | 11 | #define NUMBER_ADD_SUBST 4 12 | #define NUMBER_SUB_SUBST 3 13 | #define NUMBER_AND_SUBST 2 14 | #define NUMBER_OR_SUBST 2 15 | #define NUMBER_XOR_SUBST 2 16 | 17 | static cl::opt 18 | ObfTimes("sub_loop", 19 | cl::desc("Choose how many time the -sub pass loops on a function"), 20 | cl::value_desc("number of times"), cl::init(1), cl::Optional); 21 | static cl::opt 22 | ObfProbRate("sub_prob", 23 | cl::desc("Choose the probability [%] each basic blocks will be " 24 | "obfuscated by the InstructioSubstitution pass"), 25 | cl::value_desc("probability rate"), cl::init(50), cl::Optional); 26 | 27 | // Stats 28 | STATISTIC(Add, "Add substitued"); 29 | STATISTIC(Sub, "Sub substitued"); 30 | // STATISTIC(Mul, "Mul substitued"); 31 | // STATISTIC(Div, "Div substitued"); 32 | // STATISTIC(Rem, "Rem substitued"); 33 | // STATISTIC(Shi, "Shift substitued"); 34 | STATISTIC(And, "And substitued"); 35 | STATISTIC(Or, "Or substitued"); 36 | STATISTIC(Xor, "Xor substitued"); 37 | 38 | namespace { 39 | 40 | struct Substitution : public FunctionPass { 41 | static char ID; // Pass identification, replacement for typeid 42 | void (Substitution::*funcAdd[NUMBER_ADD_SUBST])(BinaryOperator *bo); 43 | void (Substitution::*funcSub[NUMBER_SUB_SUBST])(BinaryOperator *bo); 44 | void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo); 45 | void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo); 46 | void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo); 47 | bool flag; 48 | Substitution(bool flag) : Substitution() { this->flag = flag; } 49 | Substitution() : FunctionPass(ID) { 50 | this->flag = true; 51 | funcAdd[0] = &Substitution::addNeg; 52 | funcAdd[1] = &Substitution::addDoubleNeg; 53 | funcAdd[2] = &Substitution::addRand; 54 | funcAdd[3] = &Substitution::addRand2; 55 | 56 | funcSub[0] = &Substitution::subNeg; 57 | funcSub[1] = &Substitution::subRand; 58 | funcSub[2] = &Substitution::subRand2; 59 | 60 | funcAnd[0] = &Substitution::andSubstitution; 61 | funcAnd[1] = &Substitution::andSubstitutionRand; 62 | 63 | funcOr[0] = &Substitution::orSubstitution; 64 | funcOr[1] = &Substitution::orSubstitutionRand; 65 | 66 | funcXor[0] = &Substitution::xorSubstitution; 67 | funcXor[1] = &Substitution::xorSubstitutionRand; 68 | } 69 | 70 | bool runOnFunction(Function &F); 71 | bool substitute(Function *f); 72 | 73 | void addNeg(BinaryOperator *bo); 74 | void addDoubleNeg(BinaryOperator *bo); 75 | void addRand(BinaryOperator *bo); 76 | void addRand2(BinaryOperator *bo); 77 | 78 | void subNeg(BinaryOperator *bo); 79 | void subRand(BinaryOperator *bo); 80 | void subRand2(BinaryOperator *bo); 81 | 82 | void andSubstitution(BinaryOperator *bo); 83 | void andSubstitutionRand(BinaryOperator *bo); 84 | 85 | void orSubstitution(BinaryOperator *bo); 86 | void orSubstitutionRand(BinaryOperator *bo); 87 | 88 | void xorSubstitution(BinaryOperator *bo); 89 | void xorSubstitutionRand(BinaryOperator *bo); 90 | }; 91 | } // namespace 92 | 93 | char Substitution::ID = 0; 94 | INITIALIZE_PASS(Substitution, "subobf", "Enable Instruction Substitution.", 95 | true, true) 96 | FunctionPass *llvm::createSubstitutionPass() { return new Substitution(); } 97 | FunctionPass *llvm::createSubstitutionPass(bool flag) { 98 | return new Substitution(flag); 99 | } 100 | bool Substitution::runOnFunction(Function &F) { 101 | // Check if the percentage is correct 102 | if (ObfTimes <= 0) { 103 | errs() << "Substitution application number -sub_loop=x must be x > 0"; 104 | return false; 105 | } 106 | if (ObfProbRate > 100) { 107 | errs() << "InstructionSubstitution application instruction percentage " 108 | "-sub_prob=x must be 0 < x <= 100"; 109 | return false; 110 | } 111 | 112 | Function *tmp = &F; 113 | // Do we obfuscate 114 | if (toObfuscate(flag, tmp, "sub")) { 115 | errs() << "Running Instruction Substitution On " << F.getName() << "\n"; 116 | substitute(tmp); 117 | return true; 118 | } 119 | 120 | return false; 121 | } 122 | 123 | bool Substitution::substitute(Function *f) { 124 | Function *tmp = f; 125 | 126 | // Loop for the number of time we run the pass on the function 127 | int times = ObfTimes; 128 | do { 129 | for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) { 130 | for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { 131 | if (inst->isBinaryOp() && cryptoutils->get_range(100) <= ObfProbRate) { 132 | switch (inst->getOpcode()) { 133 | case BinaryOperator::Add: 134 | // case BinaryOperator::FAdd: 135 | // Substitute with random add operation 136 | (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])( 137 | cast(inst)); 138 | ++Add; 139 | break; 140 | case BinaryOperator::Sub: 141 | // case BinaryOperator::FSub: 142 | // Substitute with random sub operation 143 | (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])( 144 | cast(inst)); 145 | ++Sub; 146 | break; 147 | case BinaryOperator::Mul: 148 | case BinaryOperator::FMul: 149 | //++Mul; 150 | break; 151 | case BinaryOperator::UDiv: 152 | case BinaryOperator::SDiv: 153 | case BinaryOperator::FDiv: 154 | //++Div; 155 | break; 156 | case BinaryOperator::URem: 157 | case BinaryOperator::SRem: 158 | case BinaryOperator::FRem: 159 | //++Rem; 160 | break; 161 | case Instruction::Shl: 162 | //++Shi; 163 | break; 164 | case Instruction::LShr: 165 | //++Shi; 166 | break; 167 | case Instruction::AShr: 168 | //++Shi; 169 | break; 170 | case Instruction::And: 171 | (this->*funcAnd[llvm::cryptoutils->get_range(2)])( 172 | cast(inst)); 173 | ++And; 174 | break; 175 | case Instruction::Or: 176 | (this->*funcOr[llvm::cryptoutils->get_range(2)])( 177 | cast(inst)); 178 | ++Or; 179 | break; 180 | case Instruction::Xor: 181 | (this->*funcXor[llvm::cryptoutils->get_range(2)])( 182 | cast(inst)); 183 | ++Xor; 184 | break; 185 | default: 186 | break; 187 | } // End switch 188 | } // End isBinaryOp 189 | } // End for basickblock 190 | } // End for Function 191 | } while (--times > 0); // for times 192 | return false; 193 | } 194 | 195 | // Implementation of a = b - (-c) 196 | void Substitution::addNeg(BinaryOperator *bo) { 197 | BinaryOperator *op = NULL; 198 | 199 | // Create sub 200 | if (bo->getOpcode() == Instruction::Add) { 201 | op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 202 | op = 203 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo); 204 | 205 | // Check signed wrap 206 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 207 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 208 | 209 | bo->replaceAllUsesWith(op); 210 | } 211 | } 212 | 213 | // Implementation of a = -(-b + (-c)) 214 | void Substitution::addDoubleNeg(BinaryOperator *bo) { 215 | BinaryOperator *op, *op2 = NULL; 216 | 217 | if (bo->getOpcode() == Instruction::Add) { 218 | op = BinaryOperator::CreateNeg(bo->getOperand(0), "", bo); 219 | op2 = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 220 | op = BinaryOperator::Create(Instruction::Add, op, op2, "", bo); 221 | op = BinaryOperator::CreateNeg(op, "", bo); 222 | 223 | // Check signed wrap 224 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 225 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 226 | } 227 | else { 228 | op = BinaryOperator::CreateFNeg(bo->getOperand(0), "", bo); 229 | op2 = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo); 230 | op = BinaryOperator::Create(Instruction::FAdd, op, op2, "", bo); 231 | op = BinaryOperator::CreateFNeg(op, "", bo); 232 | } 233 | bo->replaceAllUsesWith(op); 234 | 235 | } 236 | 237 | // Implementation of r = rand (); a = b + r; a = a + c; a = a - r 238 | void Substitution::addRand(BinaryOperator *bo) { 239 | BinaryOperator *op = NULL; 240 | 241 | if (bo->getOpcode() == Instruction::Add) { 242 | Type *ty = bo->getType(); 243 | ConstantInt *co = 244 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 245 | op = 246 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo); 247 | op = 248 | BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo); 249 | op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo); 250 | 251 | // Check signed wrap 252 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 253 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 254 | 255 | bo->replaceAllUsesWith(op); 256 | } 257 | /* else { 258 | Type *ty = bo->getType(); 259 | ConstantFP *co = 260 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 261 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 262 | op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo); 263 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 264 | } */ 265 | } 266 | 267 | // Implementation of r = rand (); a = b - r; a = a + b; a = a + r 268 | void Substitution::addRand2(BinaryOperator *bo) { 269 | BinaryOperator *op = NULL; 270 | 271 | if (bo->getOpcode() == Instruction::Add) { 272 | Type *ty = bo->getType(); 273 | ConstantInt *co = 274 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 275 | op = 276 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo); 277 | op = 278 | BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo); 279 | op = BinaryOperator::Create(Instruction::Add, op, co, "", bo); 280 | 281 | // Check signed wrap 282 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 283 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 284 | 285 | bo->replaceAllUsesWith(op); 286 | } 287 | /* else { 288 | Type *ty = bo->getType(); 289 | ConstantFP *co = 290 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 291 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 292 | op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo); 293 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 294 | } */ 295 | } 296 | 297 | // Implementation of a = b + (-c) 298 | void Substitution::subNeg(BinaryOperator *bo) { 299 | BinaryOperator *op = NULL; 300 | 301 | if (bo->getOpcode() == Instruction::Sub) { 302 | op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); 303 | op = 304 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo); 305 | 306 | // Check signed wrap 307 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 308 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 309 | } 310 | else { 311 | op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo); 312 | op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op, "", 313 | bo); 314 | } 315 | bo->replaceAllUsesWith(op); 316 | } 317 | 318 | // Implementation of r = rand (); a = b + r; a = a - c; a = a - r 319 | void Substitution::subRand(BinaryOperator *bo) { 320 | BinaryOperator *op = NULL; 321 | 322 | if (bo->getOpcode() == Instruction::Sub) { 323 | Type *ty = bo->getType(); 324 | ConstantInt *co = 325 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 326 | op = 327 | BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo); 328 | op = 329 | BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo); 330 | op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo); 331 | 332 | // Check signed wrap 333 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 334 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 335 | 336 | bo->replaceAllUsesWith(op); 337 | } 338 | /* else { 339 | Type *ty = bo->getType(); 340 | ConstantFP *co = 341 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 342 | op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo); 343 | op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo); 344 | op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo); 345 | } */ 346 | } 347 | 348 | // Implementation of r = rand (); a = b - r; a = a - c; a = a + r 349 | void Substitution::subRand2(BinaryOperator *bo) { 350 | BinaryOperator *op = NULL; 351 | 352 | if (bo->getOpcode() == Instruction::Sub) { 353 | Type *ty = bo->getType(); 354 | ConstantInt *co = 355 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 356 | op = 357 | BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo); 358 | op = 359 | BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo); 360 | op = BinaryOperator::Create(Instruction::Add, op, co, "", bo); 361 | 362 | // Check signed wrap 363 | // op->setHasNoSignedWrap(bo->hasNoSignedWrap()); 364 | // op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); 365 | 366 | bo->replaceAllUsesWith(op); 367 | } 368 | /* else { 369 | Type *ty = bo->getType(); 370 | ConstantFP *co = 371 | (ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t()); 372 | op = BinaryOperator::Create(Instruction::FSub,bo->getOperand(0),co,"",bo); 373 | op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo); 374 | op = BinaryOperator::Create(Instruction::FAdd,op,co,"",bo); 375 | } */ 376 | } 377 | 378 | // Implementation of a = b & c => a = (b^~c)& b 379 | void Substitution::andSubstitution(BinaryOperator *bo) { 380 | BinaryOperator *op = NULL; 381 | 382 | // Create NOT on second operand => ~c 383 | op = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 384 | 385 | // Create XOR => (b^~c) 386 | BinaryOperator *op1 = 387 | BinaryOperator::Create(Instruction::Xor, bo->getOperand(0), op, "", bo); 388 | 389 | // Create AND => (b^~c) & b 390 | op = BinaryOperator::Create(Instruction::And, op1, bo->getOperand(0), "", bo); 391 | bo->replaceAllUsesWith(op); 392 | } 393 | 394 | // Implementation of a = a && b <=> !(!a | !b) && (r | !r) 395 | void Substitution::andSubstitutionRand(BinaryOperator *bo) { 396 | // Copy of the BinaryOperator type to create the random number with the 397 | // same type of the operands 398 | Type *ty = bo->getType(); 399 | 400 | // r (Random number) 401 | ConstantInt *co = 402 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 403 | 404 | // !a 405 | BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 406 | 407 | // !b 408 | BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 409 | 410 | // !r 411 | BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo); 412 | 413 | // (!a | !b) 414 | BinaryOperator *opa = 415 | BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 416 | 417 | // (r | !r) 418 | opr = BinaryOperator::Create(Instruction::Or, co, opr, "", bo); 419 | 420 | // !(!a | !b) 421 | op = BinaryOperator::CreateNot(opa, "", bo); 422 | 423 | // !(!a | !b) && (r | !r) 424 | op = BinaryOperator::Create(Instruction::And, op, opr, "", bo); 425 | 426 | // We replace all the old AND operators with the new one transformed 427 | bo->replaceAllUsesWith(op); 428 | } 429 | 430 | // Implementation of a = b | c => a = (b & c) | (b ^ c) 431 | void Substitution::orSubstitutionRand(BinaryOperator *bo) { 432 | 433 | Type *ty = bo->getType(); 434 | ConstantInt *co = 435 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 436 | 437 | // !a 438 | BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 439 | 440 | // !b 441 | BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 442 | 443 | // !r 444 | BinaryOperator *op2 = BinaryOperator::CreateNot(co, "", bo); 445 | 446 | // !a && r 447 | BinaryOperator *op3 = 448 | BinaryOperator::Create(Instruction::And, op, co, "", bo); 449 | 450 | // a && !r 451 | BinaryOperator *op4 = 452 | BinaryOperator::Create(Instruction::And, bo->getOperand(0), op2, "", bo); 453 | 454 | // !b && r 455 | BinaryOperator *op5 = 456 | BinaryOperator::Create(Instruction::And, op1, co, "", bo); 457 | 458 | // b && !r 459 | BinaryOperator *op6 = 460 | BinaryOperator::Create(Instruction::And, bo->getOperand(1), op2, "", bo); 461 | 462 | // (!a && r) || (a && !r) 463 | op3 = BinaryOperator::Create(Instruction::Or, op3, op4, "", bo); 464 | 465 | // (!b && r) ||(b && !r) 466 | op4 = BinaryOperator::Create(Instruction::Or, op5, op6, "", bo); 467 | 468 | // (!a && r) || (a && !r) ^ (!b && r) ||(b && !r) 469 | op5 = BinaryOperator::Create(Instruction::Xor, op3, op4, "", bo); 470 | 471 | // !a || !b 472 | op3 = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 473 | 474 | // !(!a || !b) 475 | op3 = BinaryOperator::CreateNot(op3, "", bo); 476 | 477 | // r || !r 478 | op4 = BinaryOperator::Create(Instruction::Or, co, op2, "", bo); 479 | 480 | // !(!a || !b) && (r || !r) 481 | op4 = BinaryOperator::Create(Instruction::And, op3, op4, "", bo); 482 | 483 | // [(!a && r) || (a && !r) ^ (!b && r) ||(b && !r) ] || [!(!a || !b) && (r || 484 | // !r)] 485 | op = BinaryOperator::Create(Instruction::Or, op5, op4, "", bo); 486 | bo->replaceAllUsesWith(op); 487 | } 488 | 489 | void Substitution::orSubstitution(BinaryOperator *bo) { 490 | BinaryOperator *op = NULL; 491 | 492 | // Creating first operand (b & c) 493 | op = BinaryOperator::Create(Instruction::And, bo->getOperand(0), 494 | bo->getOperand(1), "", bo); 495 | 496 | // Creating second operand (b ^ c) 497 | BinaryOperator *op1 = BinaryOperator::Create( 498 | Instruction::Xor, bo->getOperand(0), bo->getOperand(1), "", bo); 499 | 500 | // final op 501 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 502 | bo->replaceAllUsesWith(op); 503 | } 504 | 505 | // Implementation of a = a ~ b => a = (!a && b) || (a && !b) 506 | void Substitution::xorSubstitution(BinaryOperator *bo) { 507 | BinaryOperator *op = NULL; 508 | 509 | // Create NOT on first operand 510 | op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); // !a 511 | 512 | // Create AND 513 | op = BinaryOperator::Create(Instruction::And, bo->getOperand(1), op, "", 514 | bo); // !a && b 515 | 516 | // Create NOT on second operand 517 | BinaryOperator *op1 = 518 | BinaryOperator::CreateNot(bo->getOperand(1), "", bo); // !b 519 | 520 | // Create AND 521 | op1 = BinaryOperator::Create(Instruction::And, bo->getOperand(0), op1, "", 522 | bo); // a && !b 523 | 524 | // Create OR 525 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", 526 | bo); // (!a && b) || (a && !b) 527 | bo->replaceAllUsesWith(op); 528 | } 529 | 530 | // implementation of a = a ^ b <=> (a ^ r) ^ (b ^ r) <=> (!a && r || a && !r) ^ 531 | // (!b && r || b && !r) 532 | // note : r is a random number 533 | void Substitution::xorSubstitutionRand(BinaryOperator *bo) { 534 | BinaryOperator *op = NULL; 535 | 536 | Type *ty = bo->getType(); 537 | ConstantInt *co = 538 | (ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t()); 539 | 540 | // !a 541 | op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); 542 | 543 | // !a && r 544 | op = BinaryOperator::Create(Instruction::And, co, op, "", bo); 545 | 546 | // !r 547 | BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo); 548 | 549 | // a && !r 550 | BinaryOperator *op1 = 551 | BinaryOperator::Create(Instruction::And, bo->getOperand(0), opr, "", bo); 552 | 553 | // !b 554 | BinaryOperator *op2 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo); 555 | 556 | // !b && r 557 | op2 = BinaryOperator::Create(Instruction::And, op2, co, "", bo); 558 | 559 | // b && !r 560 | BinaryOperator *op3 = 561 | BinaryOperator::Create(Instruction::And, bo->getOperand(1), opr, "", bo); 562 | 563 | // (!a && r) || (a && !r) 564 | op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo); 565 | 566 | // (!b && r) || (b && !r) 567 | op1 = BinaryOperator::Create(Instruction::Or, op2, op3, "", bo); 568 | 569 | // (!a && r) || (a && !r) ^ (!b && r) || (b && !r) 570 | op = BinaryOperator::Create(Instruction::Xor, op, op1, "", bo); 571 | bo->replaceAllUsesWith(op); 572 | } 573 | -------------------------------------------------------------------------------- /Utils.cpp: -------------------------------------------------------------------------------- 1 | // For open-source license, please refer to [License](https://github.com/HikariObfuscator/Hikari/wiki/License). 2 | //===----------------------------------------------------------------------===// 3 | #include "llvm/Transforms/Obfuscation/Utils.h" 4 | #include "llvm/IR/IRBuilder.h" 5 | #include "llvm/IR/InstIterator.h" 6 | #include "llvm/IR/Module.h" 7 | #include "llvm/Support/raw_ostream.h" 8 | #include "llvm/IR/IRBuilder.h" 9 | #include "llvm/IR/NoFolder.h" 10 | using namespace llvm; 11 | using namespace std; 12 | // Shamefully borrowed from ../Scalar/RegToMem.cpp :( 13 | bool valueEscapes(Instruction *Inst) { 14 | BasicBlock *BB = Inst->getParent(); 15 | for (Value::use_iterator UI = Inst->use_begin(), E = Inst->use_end(); UI != E; 16 | ++UI) { 17 | Instruction *I = cast(*UI); 18 | if (I->getParent() != BB || isa(I)) { 19 | return true; 20 | } 21 | } 22 | return false; 23 | } 24 | void appendToAnnotations(Module &M, ConstantStruct *Data) { 25 | // Type for the annotation array 26 | // { i8*, i8*, i8*, i32 } 27 | GlobalVariable *AnnotationGV = M.getGlobalVariable("llvm.global.annotations"); 28 | Type *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); 29 | Type *Int32Ty = Type::getInt32Ty(M.getContext()); 30 | if (AnnotationGV == nullptr) { 31 | ArrayType *AT = ArrayType::get(Data->getType(), 1); 32 | ConstantArray *CA = cast(ConstantArray::get(AT, {Data})); 33 | GlobalVariable *newGV = new GlobalVariable(M, CA->getType(), false, 34 | GlobalValue::AppendingLinkage, 35 | CA, "llvm.global.annotations"); 36 | newGV->setSection("llvm.metadata"); 37 | return; 38 | } else { 39 | StructType *ST = StructType::get( 40 | M.getContext(), {Int8PtrTy, Int8PtrTy, Int8PtrTy, Int32Ty}); 41 | vector exists; 42 | for (unsigned i = 0; 43 | i < cast(AnnotationGV->getInitializer()->getType()) 44 | ->getNumElements(); 45 | i++) { 46 | exists.push_back(AnnotationGV->getInitializer()->getAggregateElement(i)); 47 | } 48 | exists.push_back(Data); 49 | ArrayType *AT = ArrayType::get(ST, exists.size()); 50 | ConstantArray *CA = cast( 51 | ConstantArray::get(AT, ArrayRef(exists))); 52 | GlobalVariable *newGV = new GlobalVariable(M, CA->getType(), false, 53 | GlobalValue::AppendingLinkage, 54 | CA, "llvm.global.annotations"); 55 | newGV->setSection("llvm.metadata"); 56 | return; 57 | } 58 | } 59 | void FixFunctionConstantExpr(Function *Func) { 60 | // Replace ConstantExpr with equal instructions 61 | // Otherwise replacing on Constant will crash the compiler 62 | for (BasicBlock &BB : *Func) { 63 | FixBasicBlockConstantExpr(&BB); 64 | } 65 | } 66 | void FixBasicBlockConstantExpr(BasicBlock *BB) { 67 | // Replace ConstantExpr with equal instructions 68 | // Otherwise replacing on Constant will crash the compiler 69 | // Things to note: 70 | // - Phis must be placed at BB start so CEs must be placed prior to current BB 71 | assert(!BB->empty()&&"BasicBlock is empty!"); 72 | assert((BB->getParent()!=NULL)&&"BasicBlock must be in a Function!"); 73 | Instruction* FunctionInsertPt=&*(BB->getParent()->getEntryBlock().getFirstInsertionPt()); 74 | //Instruction* LocalBBInsertPt=&*(BB.getFirstInsertionPt()); 75 | 76 | for (Instruction &I : *BB) { 77 | if(isa(I)||isa(I)){ 78 | continue; 79 | } 80 | for(unsigned i=0;i(I.getOperand(i))){ 82 | Instruction* InsertPt=&I; 83 | IRBuilder IRB(InsertPt); 84 | if(isa(I)){ 85 | IRB.SetInsertPoint(FunctionInsertPt); 86 | } 87 | Instruction *Inst = IRB.Insert(C->getAsInstruction()); 88 | I.setOperand(i,Inst); 89 | } 90 | } 91 | } 92 | } 93 | 94 | 95 | map BuildAnnotateMap(Module &M) { 96 | map VAMap; 97 | GlobalVariable *glob = M.getGlobalVariable("llvm.global.annotations"); 98 | if (glob != nullptr && glob->hasInitializer()) { 99 | ConstantArray *CDA = cast(glob->getInitializer()); 100 | for (Value *op : CDA->operands()) { 101 | ConstantStruct *anStruct = cast(op); 102 | /* 103 | Structure: [Value,Annotation,SourceFilePath,LineNumber] 104 | Usually wrapped inside GEP/BitCast 105 | We only care about Value and Annotation Here 106 | */ 107 | GlobalValue *Value = 108 | cast(anStruct->getOperand(0)->getOperand(0)); 109 | GlobalVariable *Annotation = 110 | cast(anStruct->getOperand(1)->getOperand(0)); 111 | if (Annotation->hasInitializer()) { 112 | VAMap[Value] = 113 | cast(Annotation->getInitializer()) 114 | ->getAsCString(); 115 | } 116 | } 117 | } 118 | return VAMap; 119 | } 120 | 121 | void fixStack(Function *f) { 122 | // Try to remove phi node and demote reg to stack 123 | std::vector tmpPhi; 124 | std::vector tmpReg; 125 | BasicBlock *bbEntry = &*f->begin(); 126 | 127 | do { 128 | tmpPhi.clear(); 129 | tmpReg.clear(); 130 | 131 | for (Function::iterator i = f->begin(); i != f->end(); ++i) { 132 | 133 | for (BasicBlock::iterator j = i->begin(); j != i->end(); ++j) { 134 | 135 | if (isa(j)) { 136 | PHINode *phi = cast(j); 137 | tmpPhi.push_back(phi); 138 | continue; 139 | } 140 | if (!(isa(j) && j->getParent() == bbEntry) && 141 | (valueEscapes(&*j) || j->isUsedOutsideOfBlock(&*i))) { 142 | tmpReg.push_back(&*j); 143 | continue; 144 | } 145 | } 146 | } 147 | for (unsigned int i = 0; i != tmpReg.size(); ++i) { 148 | DemoteRegToStack(*tmpReg.at(i), f->begin()->getTerminator()); 149 | } 150 | 151 | for (unsigned int i = 0; i != tmpPhi.size(); ++i) { 152 | DemotePHIToStack(tmpPhi.at(i), f->begin()->getTerminator()); 153 | } 154 | 155 | } while (tmpReg.size() != 0 || tmpPhi.size() != 0); 156 | } 157 | 158 | std::string readAnnotate(Function *f) { 159 | std::string annotation = ""; 160 | 161 | // Get annotation variable 162 | GlobalVariable *glob = 163 | f->getParent()->getGlobalVariable("llvm.global.annotations"); 164 | 165 | if (glob != NULL) { 166 | // Get the array 167 | if (ConstantArray *ca = dyn_cast(glob->getInitializer())) { 168 | for (unsigned i = 0; i < ca->getNumOperands(); ++i) { 169 | // Get the struct 170 | if (ConstantStruct *structAn = 171 | dyn_cast(ca->getOperand(i))) { 172 | if (ConstantExpr *expr = 173 | dyn_cast(structAn->getOperand(0))) { 174 | // If it's a bitcast we can check if the annotation is concerning 175 | // the current function 176 | if (expr->getOpcode() == Instruction::BitCast && 177 | expr->getOperand(0) == f) { 178 | ConstantExpr *note = cast(structAn->getOperand(1)); 179 | // If it's a GetElementPtr, that means we found the variable 180 | // containing the annotations 181 | if (note->getOpcode() == Instruction::GetElementPtr) { 182 | if (GlobalVariable *annoteStr = 183 | dyn_cast(note->getOperand(0))) { 184 | if (ConstantDataSequential *data = 185 | dyn_cast( 186 | annoteStr->getInitializer())) { 187 | if (data->isString()) { 188 | annotation += data->getAsString().lower() + " "; 189 | } 190 | } 191 | } 192 | } 193 | } 194 | } 195 | } 196 | } 197 | } 198 | } 199 | return annotation; 200 | } 201 | 202 | // Unlike O-LLVM which uses __attribute__ that is not supported by the ObjC CFE. 203 | // We use a dummy call here and remove the call later 204 | // Very dumb and definitely slower than the function attribute method 205 | // Merely a hack 206 | bool readFlag(Function *f, std::string attribute) { 207 | for (inst_iterator I = inst_begin(f); I != inst_end(f); I++) { 208 | Instruction *Inst = &*I; 209 | if (CallInst *CI = dyn_cast(Inst)) { 210 | if (CI->getCalledFunction() != nullptr && 211 | CI->getCalledFunction()->getName().contains("hikari_" + attribute)) { 212 | CI->eraseFromParent(); 213 | return true; 214 | } 215 | } 216 | } 217 | return false; 218 | } 219 | bool toObfuscate(bool flag, Function *f, std::string attribute) { 220 | 221 | // Check if declaration 222 | if (f->isDeclaration()) { 223 | return false; 224 | } 225 | // Check external linkage 226 | if (f->hasAvailableExternallyLinkage() != 0) { 227 | return false; 228 | } 229 | std::string attr = attribute; 230 | std::string attrNo = "no" + attr; 231 | // We have to check the nofla flag first 232 | // Because .find("fla") is true for a string like "fla" or 233 | // "nofla" 234 | if (readAnnotate(f).find(attrNo) != std::string::npos || 235 | readFlag(f, attrNo)) { 236 | return false; 237 | } 238 | if (readAnnotate(f).find(attr) != std::string::npos || readFlag(f, attr)) { 239 | return true; 240 | } 241 | if (flag == true) { 242 | return true; 243 | } 244 | return false; 245 | } 246 | --------------------------------------------------------------------------------