From 1b26bd11de9410cdcdaf775e979edd37fc5f2483 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sun, 9 Mar 2014 20:29:49 +0100 Subject: [PATCH 1/9] add simple string xor encryption pass --- .../Transforms/Obfuscation/StringEncryption.h | 13 ++ lib/Transforms/IPO/PassManagerBuilder.cpp | 8 ++ .../AbsractStringEncryptionPass.cpp | 130 ++++++++++++++++++ .../AbstractStringEncryptionPass.h | 34 +++++ lib/Transforms/Obfuscation/CMakeLists.txt | 4 +- .../Obfuscation/XorStringEncryption.cpp | 68 +++++++++ .../Obfuscation/XorStringEncryption.h | 41 ++++++ 7 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 include/llvm/Transforms/Obfuscation/StringEncryption.h create mode 100644 lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp create mode 100644 lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h create mode 100644 lib/Transforms/Obfuscation/XorStringEncryption.cpp create mode 100644 lib/Transforms/Obfuscation/XorStringEncryption.h 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 00eddb04bb97..a2b6d0920f4d 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -25,6 +25,7 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Vectorize.h" +#include "llvm/Transforms/Obfuscation/StringEncryption.h" #include "llvm/Transforms/Obfuscation/BogusControlFlow.h" #include "llvm/Transforms/Obfuscation/Flattening.h" @@ -75,6 +76,9 @@ static cl::opt Substitution("sub", cl::init(false), static cl::opt AesSeed("aesSeed", cl::init(""), cl::desc("seed for the AES-CTR PRNG")); +static cl::opt +StringEncryption("xse",cl::init(false),cl::desc("Enable string encryptions")); + static cl::opt Split("spli", cl::init(false), cl::desc("Enable basic block splitting")); @@ -178,9 +182,13 @@ void PassManagerBuilder::populateModulePassManager(PassManagerBase &MPM) { MPM.add(createSubstitution(Substitution)); addExtensionsToPM(EP_EnabledOnOptLevel0, MPM); + 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/AbsractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp new file mode 100644 index 000000000000..24b212f862a4 --- /dev/null +++ b/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp @@ -0,0 +1,130 @@ +#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/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Support/raw_ostream.h" + +#include "AbstractStringEncryptionPass.h" + +using namespace llvm; + +AbstractStringEncryptionPass::AbstractStringEncryptionPass(char ID) : ModulePass(ID) { + +} + +bool AbstractStringEncryptionPass::runOnModule(Module &M) { + bool changed = false; + + uint64_t encryptedStringCounter = 0; + + std::vector StringGlobalVars; + std::map StringMapGlobalVars; + + //----------------- + //get 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(); + ConstantDataSequential *cds = dyn_cast(c); + if(cds){ + StringGlobalVars.push_back(I); + } + } + } + + //----------------- + //encrypt strings + for(std::vector::iterator it = StringGlobalVars.begin(); it != StringGlobalVars.end(); ++it){ + GlobalVariable* GV = *it; + ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); + std::string clearstr = ""; + if(cds->isString()){ + clearstr = cds->getAsString(); + }else{ + if(cds->isCString ()){ + clearstr = cds->getAsCString(); + }else{ + errs() << "Can't get string value from " << GV->getName() << " SKIP ENCRYPTION!\n"; + continue; + } + } + + //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; + encryptedStringCounter++; + Constant *cryptedStr = ConstantDataArray::getString(M.getContext(), encryptedString, true); + GlobalVariable* gCryptedStr = new GlobalVariable(M, cryptedStr->getType(), true, GlobalValue::ExternalLinkage, cryptedStr, oss.str()); + StringMapGlobalVars[oss.str()] = gCryptedStr; + + //replace use of clear string with encrypted string + //note : the globaldce pass must be called after this pass to clean up all the unused clear string. + GV->replaceAllUsesWith(gCryptedStr); + + changed = true; + } + + //---------------------------------------------- + //insert decryption code where string is used + + //iterate every instruction of the module + 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 load + LoadInst *load = dyn_cast(inst); + if(load == 0) + continue; + + //check if loaded pointer is global + Value* ptrOp = load->getPointerOperand(); + GlobalVariable *GV = dyn_cast(ptrOp); + if (GV == 0) + continue; + + //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; + + //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, load, size); + //replace current load with the decryption code + load->replaceAllUsesWith(decryptedStr); + //note : the dce pass must be called after this pass to clean up all the useless load to clear string. + } + } + } + } + } + + M.dump(); + return changed; +} diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h new file mode 100644 index 000000000000..613c3a708d08 --- /dev/null +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h @@ -0,0 +1,34 @@ +#ifndef __ABSTRACT_STRING_ENCRYPTION_PASS_H__ +#define __ABSTRACT_STRING_ENCRYPTION_PASS_H__ + +#include +#include + +namespace llvm { + class Value; + class Module; + class LoadInst; +} + +namespace llvm { + class AbstractStringEncryptionPass : public llvm::ModulePass { + public: + AbstractStringEncryptionPass(char ID); + + virtual bool runOnModule(llvm::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 LoadEncryptedString load instruction (load pointer to the encrypted string) + * \return value that will replace the load to the encrypted string */ + virtual llvm::Value* stringDecryption(llvm::Module &M, llvm::LoadInst* LoadEncryptedString, const uint64_t Size) = 0; + }; +} + +#endif diff --git a/lib/Transforms/Obfuscation/CMakeLists.txt b/lib/Transforms/Obfuscation/CMakeLists.txt index 2336b3019b78..b90d7967ff00 100644 --- a/lib/Transforms/Obfuscation/CMakeLists.txt +++ b/lib/Transforms/Obfuscation/CMakeLists.txt @@ -2,8 +2,8 @@ add_llvm_library(LLVMObfuscation CryptoUtils.cpp Substitution.cpp BogusControlFlow.cpp - Utils.cpp - SplitBasicBlocks.cpp + AbsractStringEncryptionPass.cpp + XorStringEncryption.cpp Flattening.cpp ) diff --git a/lib/Transforms/Obfuscation/XorStringEncryption.cpp b/lib/Transforms/Obfuscation/XorStringEncryption.cpp new file mode 100644 index 000000000000..5862e24459bb --- /dev/null +++ b/lib/Transforms/Obfuscation/XorStringEncryption.cpp @@ -0,0 +1,68 @@ +#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/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(Module &M, llvm::LoadInst* LoadEncryptedString, const uint64_t Size) { + //create a load to the + LoadInst* newload = new LoadInst(((LoadInst*)LoadEncryptedString)->getPointerOperand(), "", false, 8, LoadEncryptedString); + //allocate a new string + AllocaInst* alloca = new AllocaInst(IntegerType::getInt8Ty(M.getContext()), ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), Size), "", LoadEncryptedString); + + for(uint64_t i = 0; i < Size; i++){ + std::vector idxlist; + idxlist.push_back(ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), i)); + GetElementPtrInst* srcPtr = GetElementPtrInst::Create(newload, ArrayRef(idxlist), "", LoadEncryptedString); + GetElementPtrInst* destPtr = GetElementPtrInst::Create(alloca, ArrayRef(idxlist), "", LoadEncryptedString); + LoadInst* srcload = new LoadInst(srcPtr, "", false, 8, LoadEncryptedString); + BinaryOperator* clearChar = BinaryOperator::CreateXor(srcload, ConstantInt::get(IntegerType::getInt8Ty(M.getContext()), _key[i%_key.size()]), "", LoadEncryptedString); + new StoreInst(clearChar, destPtr, false, 8, LoadEncryptedString); + } + 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..85ff2944d6d3 --- /dev/null +++ b/lib/Transforms/Obfuscation/XorStringEncryption.h @@ -0,0 +1,41 @@ +#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 LoadEncryptedString load instruction (load pointer to the encrypted string) + * \return value that will replace the load to the encrypted string */ + virtual llvm::Value* stringDecryption(llvm::Module &M, llvm::LoadInst* LoadEncryptedString, const uint64_t Size); + + private: + /** generate random key */ + std::string generateRandomKey(uint32_t Size); + + private: + std::string _key; + }; +} + +#endif From 61eb68c27f2838316280a9eb93bc47d7259fd6d3 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:25:16 +0200 Subject: [PATCH 2/9] string encryption pass : handle more cases --- .../AbsractStringEncryptionPass.cpp | 125 ++++++++++++------ .../AbstractStringEncryptionPass.h | 18 ++- .../Obfuscation/XorStringEncryption.cpp | 31 +++-- .../Obfuscation/XorStringEncryption.h | 6 +- 4 files changed, 123 insertions(+), 57 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp index 24b212f862a4..e13c17e6bc0b 100644 --- a/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include #include "llvm/Pass.h" #include "llvm/IR/Module.h" @@ -14,6 +15,8 @@ using namespace llvm; +//NOTE : the global dce pass must be called after this pass to clean up all the useless load to clear string... + AbstractStringEncryptionPass::AbstractStringEncryptionPass(char ID) : ModulePass(ID) { } @@ -23,8 +26,8 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { uint64_t encryptedStringCounter = 0; + StringMapGlobalVars.clear(); std::vector StringGlobalVars; - std::map StringMapGlobalVars; //----------------- //get strings @@ -58,6 +61,7 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { //encrypt current string std::string encryptedString = stringEncryption(clearstr); + //std::string encryptedString = clearstr; //create new global string with the encrypted string //@todo check if name does not exist in module @@ -69,7 +73,7 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { StringMapGlobalVars[oss.str()] = gCryptedStr; //replace use of clear string with encrypted string - //note : the globaldce pass must be called after this pass to clean up all the unused clear string. + //the globaldce pass should be called after this pass to clean up all the unused clear string. GV->replaceAllUsesWith(gCryptedStr); changed = true; @@ -82,49 +86,90 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { 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 load - LoadInst *load = dyn_cast(inst); - if(load == 0) - continue; - - //check if loaded pointer is global - Value* ptrOp = load->getPointerOperand(); - GlobalVariable *GV = dyn_cast(ptrOp); - if (GV == 0) + //check if instruction is call + CallInst *call = dyn_cast(inst); + if (call != 0) { + handleCall(M, call); continue; + } - //check if loaded pointer is constant - Constant* c = GV->getInitializer(); - if(c == 0) - continue; - ConstantExpr *constExpr = dyn_cast(c); - if(constExpr == 0) + //check if instruction is load + LoadInst *load = dyn_cast(inst); + if(load != 0){ + handleLoad(M, load); continue; - - if (constExpr->getOpcode() == Instruction::GetElementPtr){ - //get GEP instruction - GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); - if(gepInst == 0) - continue; - - //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, load, size); - //replace current load with the decryption code - load->replaceAllUsesWith(decryptedStr); - //note : the dce pass must be called after this pass to clean up all the useless load to clear string. - } } + } } } - - M.dump(); + //M.dump(); return changed; } + +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); + //note : the dce pass must be called after this pass to clean up all the useless load to clear string. + } + } +} + +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); + } + } +} diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h index 613c3a708d08..050223723687 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h @@ -2,12 +2,15 @@ #define __ABSTRACT_STRING_ENCRYPTION_PASS_H__ #include +#include #include namespace llvm { class Value; + class GlobalVariable; class Module; class LoadInst; + class CallInst; } namespace llvm { @@ -21,13 +24,22 @@ namespace llvm { /** encryption method * \param ClearString string to encrypt * \return encrypted string */ - virtual std::string stringEncryption(const std::string& ClearString) = 0; + 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 LoadEncryptedString load instruction (load pointer to the encrypted string) + * \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::LoadInst* LoadEncryptedString, const uint64_t Size) = 0; + virtual llvm::Value* stringDecryption(llvm::Module &M, llvm::Value* EncryptedString, const uint64_t Size, llvm::Instruction* Parent) = 0; + + private: + void handleLoad(llvm::Module &M, llvm::LoadInst* Load); + void handleCall(llvm::Module &M, llvm::CallInst* Call); + + private: + std::map StringMapGlobalVars; }; } diff --git a/lib/Transforms/Obfuscation/XorStringEncryption.cpp b/lib/Transforms/Obfuscation/XorStringEncryption.cpp index 5862e24459bb..40a5e30ab959 100644 --- a/lib/Transforms/Obfuscation/XorStringEncryption.cpp +++ b/lib/Transforms/Obfuscation/XorStringEncryption.cpp @@ -1,5 +1,4 @@ #include -#include #include "llvm/Pass.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" @@ -42,22 +41,30 @@ std::string XorStringEncryption::stringEncryption(const std::string& str_) { return encstr; } -llvm::Value* XorStringEncryption::stringDecryption(Module &M, llvm::LoadInst* LoadEncryptedString, const uint64_t Size) { - //create a load to the - LoadInst* newload = new LoadInst(((LoadInst*)LoadEncryptedString)->getPointerOperand(), "", false, 8, LoadEncryptedString); +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), "", LoadEncryptedString); + 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; + std::vector idxlist; idxlist.push_back(ConstantInt::get(IntegerType::getInt64Ty(M.getContext()), i)); - GetElementPtrInst* srcPtr = GetElementPtrInst::Create(newload, ArrayRef(idxlist), "", LoadEncryptedString); - GetElementPtrInst* destPtr = GetElementPtrInst::Create(alloca, ArrayRef(idxlist), "", LoadEncryptedString); - LoadInst* srcload = new LoadInst(srcPtr, "", false, 8, LoadEncryptedString); - BinaryOperator* clearChar = BinaryOperator::CreateXor(srcload, ConstantInt::get(IntegerType::getInt8Ty(M.getContext()), _key[i%_key.size()]), "", LoadEncryptedString); - new StoreInst(clearChar, destPtr, false, 8, LoadEncryptedString); + 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; + return alloca; } char XorStringEncryption::ID = 0; diff --git a/lib/Transforms/Obfuscation/XorStringEncryption.h b/lib/Transforms/Obfuscation/XorStringEncryption.h index 85ff2944d6d3..0a78c9457937 100644 --- a/lib/Transforms/Obfuscation/XorStringEncryption.h +++ b/lib/Transforms/Obfuscation/XorStringEncryption.h @@ -25,9 +25,11 @@ namespace llvm { /** Decryption method, called every time a encrypted string is used. * Should generate the llvm IR to decrypt the string * \param M module - * \param LoadEncryptedString load instruction (load pointer to the encrypted string) + * \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::LoadInst* LoadEncryptedString, const uint64_t Size); + virtual llvm::Value* stringDecryption(llvm::Module &M, llvm::Value* EncryptedString, const uint64_t Size, llvm::Instruction* Parent); private: /** generate random key */ From 5003e9daa3ed9470516cbf36c5b528d6905aba6c Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:26:37 +0200 Subject: [PATCH 3/9] fix filename AbstractStringEncryptionPass.cpp --- ...tStringEncryptionPass.cpp => AbstractStringEncryptionPass.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/Transforms/Obfuscation/{AbsractStringEncryptionPass.cpp => AbstractStringEncryptionPass.cpp} (100%) diff --git a/lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp similarity index 100% rename from lib/Transforms/Obfuscation/AbsractStringEncryptionPass.cpp rename to lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp From df02964ef74167790384c2de1261d6f1185b6f6e Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:37:25 +0200 Subject: [PATCH 4/9] fix cmake build --- lib/Transforms/Obfuscation/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Transforms/Obfuscation/CMakeLists.txt b/lib/Transforms/Obfuscation/CMakeLists.txt index b90d7967ff00..7cea2472268c 100644 --- a/lib/Transforms/Obfuscation/CMakeLists.txt +++ b/lib/Transforms/Obfuscation/CMakeLists.txt @@ -2,7 +2,7 @@ add_llvm_library(LLVMObfuscation CryptoUtils.cpp Substitution.cpp BogusControlFlow.cpp - AbsractStringEncryptionPass.cpp + AbstractStringEncryptionPass.cpp XorStringEncryption.cpp Flattening.cpp ) From ca8d93da1a43445339dc8c0692aeaf8afbe7604e Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 23:54:46 +0200 Subject: [PATCH 5/9] remove unused clear string global variable --- .../Obfuscation/AbstractStringEncryptionPass.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index e13c17e6bc0b..3f43446da3ff 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -15,8 +15,6 @@ using namespace llvm; -//NOTE : the global dce pass must be called after this pass to clean up all the useless load to clear string... - AbstractStringEncryptionPass::AbstractStringEncryptionPass(char ID) : ModulePass(ID) { } @@ -28,6 +26,7 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { StringMapGlobalVars.clear(); std::vector StringGlobalVars; + std::vector StringGlobalVarsToDelete; //----------------- //get strings @@ -73,9 +72,9 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { StringMapGlobalVars[oss.str()] = gCryptedStr; //replace use of clear string with encrypted string - //the globaldce pass should be called after this pass to clean up all the unused clear string. GV->replaceAllUsesWith(gCryptedStr); - + //need to remove clear text global + StringGlobalVarsToDelete.push_back(GV); changed = true; } @@ -103,6 +102,13 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { } } } + + //remove all clear text global variable + for(std::vector::iterator it = StringGlobalVarsToDelete.begin(); it != StringGlobalVarsToDelete.end(); ++it){ + GlobalVariable* GV = *it; + GV->eraseFromParent(); + } + //M.dump(); return changed; } @@ -140,7 +146,6 @@ void AbstractStringEncryptionPass::handleLoad(Module &M, LoadInst* Load) { Value* decryptedStr = stringDecryption(M, newload, size, Load); //replace current load with the decryption code Load->replaceAllUsesWith(decryptedStr); - //note : the dce pass must be called after this pass to clean up all the useless load to clear string. } } } From 49de48e05dd8cd9069dd8f3051689a209f9e4d11 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Fri, 28 Nov 2014 08:38:28 +0100 Subject: [PATCH 6/9] string encryption pass : handle more cases --- .../AbstractStringEncryptionPass.cpp | 46 +++++++++++++++++-- .../AbstractStringEncryptionPass.h | 2 + 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index 3f43446da3ff..ee02bdef54ad 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -34,9 +34,11 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { GlobalVariable* GV = I; if(GV->isConstant()){ Constant* c = GV->getInitializer(); - ConstantDataSequential *cds = dyn_cast(c); - if(cds){ - StringGlobalVars.push_back(I); + if(c){ + ConstantDataSequential *cds = dyn_cast(c); + if(cds){ + StringGlobalVars.push_back(I); + } } } } @@ -68,7 +70,7 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { oss << ".encstr" << encryptedStringCounter; encryptedStringCounter++; Constant *cryptedStr = ConstantDataArray::getString(M.getContext(), encryptedString, true); - GlobalVariable* gCryptedStr = new GlobalVariable(M, cryptedStr->getType(), true, GlobalValue::ExternalLinkage, cryptedStr, oss.str()); + 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 @@ -98,7 +100,13 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { handleLoad(M, load); continue; } - + + //check if instruction is invoke + InvokeInst *invoke = dyn_cast(inst); + if(invoke != 0){ + handleInvoke(M, invoke); + continue; + } } } } @@ -178,3 +186,31 @@ void AbstractStringEncryptionPass::handleCall(llvm::Module &M, llvm::CallInst* C } } } + +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); + } + } +} diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h index 050223723687..e758701982d4 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h @@ -11,6 +11,7 @@ namespace llvm { class Module; class LoadInst; class CallInst; + class InvokeInst; } namespace llvm { @@ -37,6 +38,7 @@ namespace llvm { private: void handleLoad(llvm::Module &M, llvm::LoadInst* Load); void handleCall(llvm::Module &M, llvm::CallInst* Call); + void handleInvoke(llvm::Module &M, llvm::InvokeInst* Invoke); private: std::map StringMapGlobalVars; From 6eaeaac9d42bfa776c3c2e0f1095596080210142 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sat, 29 Nov 2014 14:44:19 +0100 Subject: [PATCH 7/9] fix clang crash when using -O3 optimization with string encryption pass --- lib/Transforms/Utils/GlobalStatus.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/Transforms/Utils/GlobalStatus.cpp b/lib/Transforms/Utils/GlobalStatus.cpp index 12057e4b929c..6af013369e70 100644 --- a/lib/Transforms/Utils/GlobalStatus.cpp +++ b/lib/Transforms/Utils/GlobalStatus.cpp @@ -60,11 +60,13 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS, return true; } else if (const Instruction *I = dyn_cast(UR)) { if (!GS.HasMultipleAccessingFunctions) { - const Function *F = I->getParent()->getParent(); + if(I->getParent()){ + const Function *F = I->getParent()->getParent(); if (!GS.AccessingFunction) - GS.AccessingFunction = F; - else if (GS.AccessingFunction != F) - GS.HasMultipleAccessingFunctions = true; + GS.AccessingFunction = F; + else if (GS.AccessingFunction != F) + GS.HasMultipleAccessingFunctions = true; + } } if (const LoadInst *LI = dyn_cast(I)) { GS.IsLoaded = true; From d01248859a40934f184339c9604394d8a66470ed Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sun, 30 Nov 2014 12:06:41 +0100 Subject: [PATCH 8/9] string encryption : unique global variable name --- lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index ee02bdef54ad..c380d59955e8 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -10,6 +10,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Process.h" #include "AbstractStringEncryptionPass.h" @@ -67,7 +68,7 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { //create new global string with the encrypted string //@todo check if name does not exist in module std::ostringstream oss; - oss << ".encstr" << encryptedStringCounter; + 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()); From 5302a13f65efd16c961e967de995302be5d933c7 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sun, 30 Nov 2014 19:01:49 +0100 Subject: [PATCH 9/9] fix build --- lib/Transforms/Obfuscation/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/Obfuscation/CMakeLists.txt b/lib/Transforms/Obfuscation/CMakeLists.txt index 7cea2472268c..afd8dba1c0b8 100644 --- a/lib/Transforms/Obfuscation/CMakeLists.txt +++ b/lib/Transforms/Obfuscation/CMakeLists.txt @@ -2,9 +2,11 @@ add_llvm_library(LLVMObfuscation CryptoUtils.cpp Substitution.cpp BogusControlFlow.cpp + Utils.cpp + SplitBasicBlocks.cpp + Flattening.cpp AbstractStringEncryptionPass.cpp XorStringEncryption.cpp - Flattening.cpp ) add_dependencies(LLVMObfuscation intrinsics_gen)