diff --git a/include/llvm/Transforms/Obfuscation/StringEncryption.h b/include/llvm/Transforms/Obfuscation/StringEncryption.h new file mode 100644 index 000000000000..52b0a0fa40ad --- /dev/null +++ b/include/llvm/Transforms/Obfuscation/StringEncryption.h @@ -0,0 +1,13 @@ +#ifndef __STRING_ENCRYPTION_H__ +#define __STRING_ENCRYPTION_H__ + +// LLVM include +#include "llvm/Pass.h" + +using namespace llvm; + +namespace llvm { + Pass* createXorStringEncryption(); +} + +#endif diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index 217a991c87f2..aa640f59c2da 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -28,6 +28,7 @@ #include "llvm/Transforms/Obfuscation/Substitution.h" #include "llvm/Transforms/Obfuscation/Flattening.h" #include "llvm/Transforms/Obfuscation/BogusControlFlow.h" +#include "llvm/Transforms/Obfuscation/StringEncryption.h" #include "llvm/PrngAESCtr.h" @@ -73,6 +74,9 @@ BogusControlFlow("bcf",cl::init(false),cl::desc("Enable bogus control flow")); static cl::opt Substitution("sub",cl::init(false),cl::desc("Enable instruction substitutions")); +static cl::opt +StringEncryption("xse",cl::init(false),cl::desc("Enable string encryptions")); + static cl::opt AesSeed("aesSeed",cl::init(""),cl::desc("seed for the AES-CTR PRNG")); @@ -188,9 +192,13 @@ void PassManagerBuilder::populateModulePassManager(PassManagerBase &MPM) { // Substitution if(Substitution) MPM.add(createSubstitution()); + if(StringEncryption) MPM.add(createXorStringEncryption()); + return; } + if(StringEncryption) MPM.add(createXorStringEncryption()); + // Add LibraryInfo if we have some. if (LibraryInfo) MPM.add(new TargetLibraryInfo(*LibraryInfo)); diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp new file mode 100644 index 000000000000..5d5840bf1eb4 --- /dev/null +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -0,0 +1,555 @@ +#include +#include +#include +#include +#include "llvm/Pass.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Path.h" + +#include "AbstractStringEncryptionPass.h" + +using namespace llvm; + +AbstractStringEncryptionPass::AbstractStringEncryptionPass(char ID) : ModulePass(ID), encryptedStringCounter(0) { + +} + +bool AbstractStringEncryptionPass::runOnModule(Module &M) { + bool changed = false; + + StringMapGlobalVars.clear(); + std::vector StringGlobalVars; + std::vector StringGlobalVarsToDelete; + + //----------------- + //get list of strings + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { + GlobalVariable* GV = I; + if(GV->isConstant()){ + Constant* c = GV->getInitializer(); + if(c){ + ConstantDataSequential *cds = dyn_cast(c); + if(cds){ + if(cds->isString() || cds->isCString()){ + StringGlobalVars.push_back(I); + }else{ + //not a string skip it + //errs() << "WARNING : Can't get string value from " << GV->getName() << " SKIP ENCRYPTION!\n"; + } + } + } + } + } + + + //----------------- + //remove all strings that cannot be encrypted + checkStringsCanBeEncrypted(M, StringGlobalVars); + + //----------------- + //encrypt strings + changed = encryptString(M, StringGlobalVars, StringGlobalVarsToDelete); + if(changed == false) + return changed; + + //---------------------------------------------- + //insert decryption code where string is used + insertDecryptionCode(M); + + + //remove all clear text global variable + for(std::vector::iterator it = StringGlobalVarsToDelete.begin(); it != StringGlobalVarsToDelete.end(); ++it){ + GlobalVariable* GV = *it; + GV->eraseFromParent(); + } + //remove all dead instructions + for(std::vector::iterator it = InstructionToDel.begin(); it != InstructionToDel.end(); ++it){ + Instruction* inst = *it; + inst->eraseFromParent(); + } + + //M.dump(); + return changed; +} + +std::string AbstractStringEncryptionPass::getGlobalStringValue(GlobalVariable* GV) { + std::string str = ""; + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + if(cds){ + if(cds->isString()){ + str = cds->getAsString(); + }else{ + if(cds->isCString ()){ + str = cds->getAsCString(); + } + } + } + return str; +} + +void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::vector& StringGlobalVars) { + // @todo do not encrypt const char** not supported too many case too handle for now ... + // just detect const char** + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { + GlobalVariable* GV = I; + if(!GV->hasInitializer()) + continue; + + ConstantArray* array = dyn_cast(GV->getInitializer()); + if(array){ + for(unsigned int i = 0; i < array->getNumOperands(); i++){ + ConstantExpr* ce = dyn_cast(array->getOperand(i)); + if(ce == 0){ + ConstantStruct* cs = dyn_cast(array->getOperand(i)); + if(cs == 0) + continue; + + for(unsigned int j = 0; j < cs->getNumOperands(); j++){ + ConstantExpr* structelement = dyn_cast(cs->getOperand(j)); + if(structelement == 0) + continue; + GetElementPtrInst *gepElementFromStruct = dyn_cast(structelement->getAsInstruction()); + if(gepElementFromStruct == 0) + continue; + + if(GlobalVariable* gv = dyn_cast(gepElementFromStruct->getPointerOperand())){ + if(dyn_cast(gv->getInitializer())){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), gv); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(gv) << " won't be ecnrypted (struct { char* x = \"str\"; } encryption is not supported!) - conversion from string literal to 'char *' is deprecated!\n"; + StringGlobalVars.erase(it); + } + } + } + } + }else{ + GetElementPtrInst *gepElementFromArray = dyn_cast(ce->getAsInstruction()); + if(gepElementFromArray == 0) + continue; + + if(GlobalVariable* gv = dyn_cast(gepElementFromArray->getPointerOperand())){ + if(dyn_cast(gv->getInitializer())){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), gv); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(gv) << " won't be ecnrypted (char** encryption is not supported!)!\n"; + StringGlobalVars.erase(it); + } + } + } + } + } + } + } + + //do not encrypt string that are directly in return instruction + // example : const char* fun(){ return "clear-text"; } + // this can't be encrypted since we have to do some allocation to decrypt the string ... + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + for (Function::iterator bb = I->begin(), e = I->end(); bb != e; ++bb) { + for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { + //check every return instruction + ReturnInst *ret = dyn_cast(inst); + if (ret == 0) + continue; + + //get the return value + Value* retval = ret->getReturnValue(); + if(retval == 0) + continue; + + //check if the return value is a load instruction + LoadInst* loadInst = dyn_cast(retval); + if(loadInst){ + Value* ptrOp = loadInst->getPointerOperand(); + GlobalVariable *GV = dyn_cast(ptrOp); + if (GV == 0){ + ConstantExpr *constExpr = dyn_cast(ptrOp); + if(constExpr == 0) + continue; + + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if (gepInst == 0) + continue; + + GlobalVariable* GV = dyn_cast(gepInst->getPointerOperand()); + if(GV){ + // handle load i8* getelementptr inbounds ([X x i8]* @string, i32 0, i64 x), align 1 + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + if(cds){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + StringGlobalVars.erase(it); + } + }else{ + // handle load i8** getelementptr inbounds ([X x i8*]* @string_array, i32 0, i64 x), align 8 + if (ConstantArray* array = dyn_cast(GV->getInitializer())) { + Constant* c = array->getAggregateElement(dyn_cast(gepInst->getOperand(2))->getZExtValue()); + ConstantExpr* ce = dyn_cast(c); + if(ce){ + GetElementPtrInst *gepElementFromArray = dyn_cast(ce->getAsInstruction()); + if(gepElementFromArray){ + GlobalVariable* GV = dyn_cast(gepElementFromArray->getPointerOperand()); + if(GV){ + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + if(cds){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + StringGlobalVars.erase(it); + } + } + } + } + } + } + } + } + continue; + }else{ + //check if loaded pointer is constant + Constant* c = GV->getInitializer(); + if(c == 0) + continue; + + ConstantExpr *constExpr = dyn_cast(c); + if(constExpr == 0) + continue; + + if (constExpr->getOpcode() == Instruction::GetElementPtr){ + //get GEP instruction + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + continue; + + GlobalVariable* GV = dyn_cast(gepInst->getPointerOperand()); + if(GV){ + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + if(cds){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + StringGlobalVars.erase(it); + } + } + } + } + } + }else{ + //instruction is not a load, check for global variable... + ConstantExpr *constExpr = dyn_cast(retval); + if (constExpr == 0) + continue; + if (constExpr->getOpcode() != Instruction::GetElementPtr) + continue; + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + continue; + + GlobalVariable* GV = dyn_cast(gepInst->getPointerOperand()); + if(GV){ + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + if(cds){ + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + StringGlobalVars.erase(it); + } + } + } + } + } + } + } +} + +bool AbstractStringEncryptionPass::encryptString(Module &M, std::vector& StringGlobalVars, std::vector& StringGlobalVarsToDelete) { + bool changed = false; + for(std::vector::iterator it = StringGlobalVars.begin(); it != StringGlobalVars.end(); ++it){ + GlobalVariable* GV = *it; + //get clear text string + std::string clearstr = getGlobalStringValue(GV); + + GlobalVariable::LinkageTypes lt = GV->getLinkage(); + switch(lt){ + default: + //not supported + //errs() << "WARNING : " << GV->getName() << "use unsupported linkage type (" << lt << ") SKIP ENCRYPTION!\n"; + //GV->dump(); + break; + case GlobalVariable::ExternalLinkage: + case GlobalVariable::InternalLinkage: + case GlobalVariable::PrivateLinkage: + //linkage supported + + //encrypt current string + std::string encryptedString = stringEncryption(clearstr); + + //create new global string with the encrypted string + //@todo check if name does not exist in module + std::ostringstream oss; + oss << ".encstr" << encryptedStringCounter << "_" << sys::Process::GetRandomNumber(); + encryptedStringCounter++; + Constant *cryptedStr = ConstantDataArray::getString(M.getContext(), encryptedString, true); + GlobalVariable* gCryptedStr = new GlobalVariable(M, cryptedStr->getType(), true, GV->getLinkage(), cryptedStr, oss.str()); + StringMapGlobalVars[oss.str()] = gCryptedStr; + //replace use of clear string with encrypted string + GV->replaceAllUsesWith(gCryptedStr); + //remove clear text global + StringGlobalVarsToDelete.push_back(GV); + changed = true; + break; + } + } + return changed; +} + +void AbstractStringEncryptionPass::insertDecryptionCode(Module &M){ + //iterate every instruction of the module and get the list of every gep instruction + std::vector geps; + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + for (Function::iterator bb = I->begin(), e = I->end(); bb != e; ++bb) { + for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { + //check if instruction is a get element pointer + GetElementPtrInst* gepInst = dyn_cast(inst); + if (gepInst != 0) { + //store it for later, decoding string with other instruction may add other gep + geps.push_back(gepInst); + continue; + } + } + } + } + + //iterate every instruction of the module and insert decryption code + //each time an encrypted string is used. + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + for (Function::iterator bb = I->begin(), e = I->end(); bb != e; ++bb) { + for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { + //check if instruction is call + CallInst *call = dyn_cast(inst); + if (call != 0) { + handleCall(M, call); + continue; + } + + //check if instruction is load + LoadInst *load = dyn_cast(inst); + if(load != 0){ + handleLoad(M, load); + continue; + } + + //check if instruction is invoke + InvokeInst *invoke = dyn_cast(inst); + if(invoke != 0){ + handleInvoke(M, invoke); + continue; + } + + //check if instruction is getelementptr + ReturnInst *ret = dyn_cast(inst); + if (ret != 0) { + handleReturn(M, ret); + continue; + } + + //check if instruction is store + StoreInst *store = dyn_cast(inst); + if (store != 0) { + handleStore(M, store); + continue; + } + } + } + } + + //handle original gep instruction + for(std::vector::iterator it = geps.begin(); it != geps.end(); ++it){ + GetElementPtrInst* gep = *it; + handleGEP(M, gep); + } +} + +void AbstractStringEncryptionPass::handleLoad(Module &M, LoadInst* Load) { + //check if loaded pointer is global + Value* ptrOp = Load->getPointerOperand(); + GlobalVariable *GV = dyn_cast(ptrOp); + if (GV == 0) + return; + + //check if loaded pointer is constant + Constant* c = GV->getInitializer(); + if(c == 0) + return; + + ConstantExpr *constExpr = dyn_cast(c); + if(constExpr == 0) + return; + + if (constExpr->getOpcode() == Instruction::GetElementPtr){ + //get GEP instruction + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + return; + + //check if the string is encrypted + StringRef gepOpName = gepInst->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + LoadInst* newload = new LoadInst(Load->getPointerOperand(), "", false, 8, Load); + Value* decryptedStr = stringDecryption(M, newload, size, Load); + //replace current load with the decryption code + Load->replaceAllUsesWith(decryptedStr); + InstructionToDel.push_back(Load); + } + } +} + +void AbstractStringEncryptionPass::handleStore(Module &M, StoreInst* Store) { + //check if loaded pointer is global + Value* vOp = Store->getValueOperand(); + ConstantExpr *constExpr = dyn_cast(vOp); + if(constExpr == 0) + return; + + if (constExpr->getOpcode() == Instruction::GetElementPtr){ + //get GEP instruction + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + return; + + //check if the string is encrypted + StringRef gepOpName = gepInst->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + Value* decryptedStr = stringDecryption(M, gepInst->getPointerOperand(), size, Store); + //replace current store with the decryption code + new StoreInst(decryptedStr, Store->getPointerOperand(), false, 8, Store); + InstructionToDel.push_back(Store); + } + } +} + +void AbstractStringEncryptionPass::handleCall(llvm::Module &M, llvm::CallInst* Call) { + for(unsigned i = 0; i < Call->getNumArgOperands(); i++){ + llvm::ConstantExpr *constExpr = llvm::dyn_cast(Call->getArgOperand(i)); + //not a constant expr + if (constExpr == 0) + continue; + + //not a gep + if (constExpr->getOpcode() != llvm::Instruction::GetElementPtr) + continue; + + llvm::GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + continue; + + //load encrypted string + StringRef gepOpName = gepInst->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + llvm::Value* decryptedStr = stringDecryption(M, it->second, size, Call); + Call->setArgOperand(i, decryptedStr); + } + } +} + +void AbstractStringEncryptionPass::handleInvoke(llvm::Module &M, llvm::InvokeInst* Invoke){ + for(unsigned i = 0; i < Invoke->getNumArgOperands(); i++){ + llvm::ConstantExpr *constExpr = llvm::dyn_cast(Invoke->getArgOperand(i)); + //not a constant expr + if (constExpr == 0) + continue; + //not a gep + if (constExpr->getOpcode() != llvm::Instruction::GetElementPtr) + continue; + + llvm::GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + continue; + + //load encrypted string + StringRef gepOpName = gepInst->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + llvm::Value* decryptedStr = stringDecryption(M, it->second, size, Invoke); + Invoke->setArgOperand(i, decryptedStr); + } + } +} + +void AbstractStringEncryptionPass::handleReturn(Module &M, ReturnInst* ret){ + Value* retval = ret->getReturnValue(); + if(retval == 0) + return; + + ConstantExpr *constExpr = dyn_cast(retval); + if (constExpr == 0) + return; + //not a gep + if (constExpr->getOpcode() != Instruction::GetElementPtr) + return; + + llvm::GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if(gepInst == 0) + return; + + //load encrypted string + StringRef gepOpName = gepInst->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + Value* decryptedStr = stringDecryption(M, it->second, size, ret); + ReturnInst::Create(M.getContext(), decryptedStr, ret); + InstructionToDel.push_back(ret); + } +} + +void AbstractStringEncryptionPass::handleGEP(Module &M, GetElementPtrInst* Gep) { + //load encrypted string + StringRef gepOpName = Gep->getPointerOperand()->getName(); + std::map::iterator it = StringMapGlobalVars.find(gepOpName.str()); + if(it != StringMapGlobalVars.end()){ + //get size of string + ConstantDataSequential *cds = dyn_cast(it->second->getInitializer()); + uint64_t size = cds->getNumElements(); + //generate IR to decrypt string + llvm::Value* decryptedStr = stringDecryption(M, it->second, size, Gep); + std::vector idxlist; + idxlist.push_back(Gep->getOperand(Gep->getNumOperands() - 1)); + GetElementPtrInst* newGep = GetElementPtrInst::Create(decryptedStr, ArrayRef(idxlist), "", Gep); + Gep->replaceAllUsesWith(newGep); + InstructionToDel.push_back(Gep); + return; + } +} diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h new file mode 100644 index 000000000000..2f71600b43c0 --- /dev/null +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h @@ -0,0 +1,65 @@ +#ifndef __ABSTRACT_STRING_ENCRYPTION_PASS_H__ +#define __ABSTRACT_STRING_ENCRYPTION_PASS_H__ + +#include +#include +#include + +namespace llvm { + class Value; + class GlobalVariable; + class Module; + class LoadInst; + class StoreInst; + class CallInst; + class InvokeInst; + class ReturnInst; + class GetElementPtrInst; + class Instruction; +} + +namespace llvm { + class AbstractStringEncryptionPass : public ModulePass { + public: + AbstractStringEncryptionPass(char ID); + + virtual bool runOnModule(Module &M); + + protected: + /** encryption method + * \param ClearString string to encrypt + * \return encrypted string */ + virtual std::string stringEncryption(const std::string& ClearString) = 0; + /** Decryption method, called every time a encrypted string is used. + * Should generate the llvm IR to decrypt the string + * \param M module + * \param EncryptedString encrypted string value + * \param Size size of encrypted string + * \param Parent parent instruction + * \return value that will replace the load to the encrypted string */ + virtual Value* stringDecryption(Module &M, Value* EncryptedString, const uint64_t Size, Instruction* Parent) = 0; + + private: + void handleLoad(Module &M, LoadInst* Load); + void handleStore(Module &M, StoreInst* store); + void handleCall(Module &M, CallInst* Call); + void handleInvoke(Module &M, InvokeInst* Invoke); + void handleReturn(Module &M, ReturnInst* Ret); + void handleGEP(Module &M, GetElementPtrInst* Gep); + + void checkStringsCanBeEncrypted(Module &M, std::vector& StringGlobalVars); + + bool encryptString(Module &M, std::vector& StringGlobalVars, std::vector& StringGlobalVarsToDelete); + void insertDecryptionCode(Module &M); + + std::string getGlobalStringValue(GlobalVariable* GV); + + private: + std::map StringMapGlobalVars; + std::vector InstructionToDel; + + uint64_t encryptedStringCounter; + }; +} + +#endif diff --git a/lib/Transforms/Obfuscation/CMakeLists.txt b/lib/Transforms/Obfuscation/CMakeLists.txt index 0ca297c1d366..6284be9dbfdd 100644 --- a/lib/Transforms/Obfuscation/CMakeLists.txt +++ b/lib/Transforms/Obfuscation/CMakeLists.txt @@ -5,6 +5,8 @@ add_llvm_library(LLVMObfuscation Substitution.cpp SubstitutionFunction.cpp BogusControlFlow.cpp + AbstractStringEncryptionPass.cpp + XorStringEncryption.cpp ) add_dependencies(LLVMObfuscation intrinsics_gen) diff --git a/lib/Transforms/Obfuscation/XorStringEncryption.cpp b/lib/Transforms/Obfuscation/XorStringEncryption.cpp new file mode 100644 index 000000000000..40a5e30ab959 --- /dev/null +++ b/lib/Transforms/Obfuscation/XorStringEncryption.cpp @@ -0,0 +1,75 @@ +#include +#include "llvm/Pass.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/Transforms/Obfuscation/StringEncryption.h" +#include "XorStringEncryption.h" + +#define DEBUG_TYPE "xorstringencryption" + +using namespace llvm; + +XorStringEncryption::XorStringEncryption(uint32_t KeySize) : AbstractStringEncryptionPass(ID){ + _key = generateRandomKey(KeySize); +} + +XorStringEncryption::XorStringEncryption(const std::string& Key) : AbstractStringEncryptionPass(ID){ + _key = Key; +} + +std::string XorStringEncryption::generateRandomKey(uint32_t Size){ + std::string allowedChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-#'?!"; + std::string key; + for(uint32_t i = 0; i < Size; i++){ + int n = rand() % allowedChar.size(); + key += allowedChar[n]; + } + //errs() << key << "\n"; + return key; +} + +std::string XorStringEncryption::stringEncryption(const std::string& str_) { + std::string encstr = str_; + for(uint32_t i = 0; i < encstr.size(); i++){ + encstr[i] ^= _key[i%_key.size()]; + } + return encstr; +} + +llvm::Value* XorStringEncryption::stringDecryption(llvm::Module &M, llvm::Value* encryptedString, const uint64_t Size, llvm::Instruction* parent) { + //allocate a new string + AllocaInst* alloca = new AllocaInst(IntegerType::getInt8Ty(M.getContext()), ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), Size), "", parent); + + for(uint64_t i = 0; i < Size; i++){ + std::vector idxlist; + idxlist.push_back(ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), i)); + GetElementPtrInst* destPtr = GetElementPtrInst::CreateInBounds(alloca, ArrayRef(idxlist), "", parent); + + if(not dyn_cast(encryptedString)){ + idxlist.clear(); + idxlist.push_back(ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), 0)); + idxlist.push_back(ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), i)); + //convert [NB x i8]* to i8 *... + //%cast = getelementptr [NB x i8]* @.str, i64 0, i64 i + } + + GetElementPtrInst* srcPtr = GetElementPtrInst::Create(encryptedString, ArrayRef(idxlist), "", parent); + LoadInst* srcload = new LoadInst(srcPtr, "", false, 8, parent); + + BinaryOperator* clearChar = BinaryOperator::CreateXor(srcload, ConstantInt::get(IntegerType::getInt8Ty(M.getContext()), _key[i%_key.size()]), "", parent); + new StoreInst(clearChar, destPtr, false, 8, parent); + } + return alloca; +} + +char XorStringEncryption::ID = 0; +static RegisterPass X("xorscrypt", "Xor String Encryption Pass"); + +Pass *llvm::createXorStringEncryption() { + return new XorStringEncryption(); +} diff --git a/lib/Transforms/Obfuscation/XorStringEncryption.h b/lib/Transforms/Obfuscation/XorStringEncryption.h new file mode 100644 index 000000000000..0a78c9457937 --- /dev/null +++ b/lib/Transforms/Obfuscation/XorStringEncryption.h @@ -0,0 +1,43 @@ +#ifndef __XOR_STRING_ENCRYPTION_H__ +#define __XOR_STRING_ENCRYPTION_H__ + +#include +#include "AbstractStringEncryptionPass.h" + +namespace llvm { + class Module; + class LoadInst; +} + +namespace llvm { + class XorStringEncryption : public AbstractStringEncryptionPass { + public: + static char ID; + + XorStringEncryption(uint32_t KeySize = 80); + XorStringEncryption(const std::string& Key); + + protected: + /** encryption method + * \param ClearString string to encrypt + * \return encrypted string */ + virtual std::string stringEncryption(const std::string& ClearString); + /** Decryption method, called every time a encrypted string is used. + * Should generate the llvm IR to decrypt the string + * \param M module + * \param EncryptedString encrypted string value + * \param Size size of encrypted string + * \param Parent parent instruction + * \return value that will replace the load to the encrypted string */ + virtual llvm::Value* stringDecryption(llvm::Module &M, llvm::Value* EncryptedString, const uint64_t Size, llvm::Instruction* Parent); + + private: + /** generate random key */ + std::string generateRandomKey(uint32_t Size); + + private: + std::string _key; + }; +} + +#endif diff --git a/lib/Transforms/Utils/GlobalStatus.cpp b/lib/Transforms/Utils/GlobalStatus.cpp index 5f0a563ceec0..bf73dc56f586 100644 --- a/lib/Transforms/Utils/GlobalStatus.cpp +++ b/lib/Transforms/Utils/GlobalStatus.cpp @@ -62,11 +62,13 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS, return true; } else if (const Instruction *I = dyn_cast(U)) { if (!GS.HasMultipleAccessingFunctions) { - const Function *F = I->getParent()->getParent(); - if (GS.AccessingFunction == 0) - GS.AccessingFunction = F; - else if (GS.AccessingFunction != F) - GS.HasMultipleAccessingFunctions = true; + if(I->getParent()){ + const Function *F = I->getParent()->getParent(); + if (GS.AccessingFunction == 0) + GS.AccessingFunction = F; + else if (GS.AccessingFunction != F) + GS.HasMultipleAccessingFunctions = true; + } } if (const LoadInst *LI = dyn_cast(I)) { GS.IsLoaded = true;