From b6030409d96b3c0bfecc8db54b018f4cf96f5aa5 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sun, 9 Mar 2014 20:29:49 +0100 Subject: [PATCH 01/11] 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 | 2 + .../Obfuscation/XorStringEncryption.cpp | 68 +++++++++ .../Obfuscation/XorStringEncryption.h | 41 ++++++ 7 files changed, 296 insertions(+) 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 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/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 0ca297c1d366..f4343d0e83ca 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 + AbsractStringEncryptionPass.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..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 fe547b21edbbe62dc80d711adcc2800a24e2b699 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:25:16 +0200 Subject: [PATCH 02/11] 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 dfb7f56a31a984c3c9d8b8dd21e174a81459d56a Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:26:37 +0200 Subject: [PATCH 03/11] 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 7197a91d10bba8cece1f51645eb9b21b8ce70e75 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 10:37:25 +0200 Subject: [PATCH 04/11] 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 f4343d0e83ca..6284be9dbfdd 100644 --- a/lib/Transforms/Obfuscation/CMakeLists.txt +++ b/lib/Transforms/Obfuscation/CMakeLists.txt @@ -5,7 +5,7 @@ add_llvm_library(LLVMObfuscation Substitution.cpp SubstitutionFunction.cpp BogusControlFlow.cpp - AbsractStringEncryptionPass.cpp + AbstractStringEncryptionPass.cpp XorStringEncryption.cpp ) From cadce142568c78a2747d917eae4af4d8a21ebc10 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Wed, 16 Jul 2014 23:54:46 +0200 Subject: [PATCH 05/11] 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 f37115f3aeeca43fcb0702878fdb53c7d34b25f4 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Fri, 28 Nov 2014 08:38:28 +0100 Subject: [PATCH 06/11] 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 1ed8190033473b787fe668f8f7f3f7875d4dad66 Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sat, 29 Nov 2014 14:44:19 +0100 Subject: [PATCH 07/11] fix clang crash when using -O3 optimization with string encryption pass --- lib/Transforms/Utils/GlobalStatus.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) 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; From bd0482c8c2776563fc7ca4d633433ad9beabad5f Mon Sep 17 00:00:00 2001 From: "christophe.duvernois" Date: Sun, 30 Nov 2014 12:06:41 +0100 Subject: [PATCH 08/11] 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 69d3dac26a0cd04e68f6be956ce1ebfd1ccd0504 Mon Sep 17 00:00:00 2001 From: Christophe Duvernois Date: Tue, 13 Jan 2015 14:41:37 +0100 Subject: [PATCH 09/11] string encryption pass : handle more cases --- .../AbstractStringEncryptionPass.cpp | 751 +++++++++++++----- .../AbstractStringEncryptionPass.h | 29 +- 2 files changed, 590 insertions(+), 190 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index c380d59955e8..8f58d47676f2 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "llvm/Pass.h" #include "llvm/IR/Module.h" @@ -8,210 +9,592 @@ #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) { - +AbstractStringEncryptionPass::AbstractStringEncryptionPass(char ID) : ModulePass(ID), encryptedStringCounter(0) { + } bool AbstractStringEncryptionPass::runOnModule(Module &M) { - bool changed = false; - - uint64_t encryptedStringCounter = 0; - - StringMapGlobalVars.clear(); - std::vector StringGlobalVars; - std::vector StringGlobalVarsToDelete; - - //----------------- - //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(); - if(c){ - 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); - //std::string encryptedString = 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); - //need to remove clear text global - StringGlobalVarsToDelete.push_back(GV); - 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 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; - } + 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()){ + StringGlobalVars.push_back(I); + }else{ + if(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) { + //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){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + 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){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + 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){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + 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){ + errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), GV); + if(it != StringGlobalVars.end()){ + StringGlobalVars.erase(it); + } + } + } + } + } + } + } + + // I don't know how to handle this case : + // int main(){ + // const char *test[] = { "item0", "item1", "item2", "item3", "item4"}; + // printf("%s\n", test[3]); + // return 0; + // } + // do not encrypt those strings ... + // @TODO : find a way to handle this case and remove this code + 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) { + if(llvm::MemCpyInst* memcpyInst = dyn_cast(inst)){ + if (llvm::ConstantExpr *constExpr = llvm::dyn_cast(memcpyInst->getArgOperand(1))){ + if(llvm::CastInst* castInst = dyn_cast(constExpr->getAsInstruction())){ + if (GlobalVariable* global = dyn_cast(castInst->getOperand(0))) { + if (ConstantArray* array = dyn_cast(global->getInitializer())) { + for(unsigned int i = 0; i < array->getNumOperands(); i++){ + if(ConstantExpr* ce = dyn_cast(array->getOperand(i))){ + if(GetElementPtrInst *gep = dyn_cast(ce->getAsInstruction())){ + if(GlobalVariable* gv = dyn_cast(gep->getPointerOperand())){ + if(dyn_cast(gv->getInitializer())){ + errs() << "WARNING : " << getGlobalStringValue(gv) << " won't be ecnrypted (char** encryption not fully supported!)!\n"; + std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), gv); + if(it != StringGlobalVars.end()){ + 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; - } - } - } - } - - //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; + 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){ + // handle load i8* getelementptr inbounds ([X x i8]* @string, i32 0, i64 x), align 1 + ConstantExpr *constExpr = dyn_cast(ptrOp); + if(constExpr != 0){ + GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); + if (gepInst != 0) { + //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, it->second, size, Load); + std::vector idxlist; + idxlist.push_back(gepInst->getOperand(gepInst->getNumOperands() - 1)); + GetElementPtrInst* newGep = GetElementPtrInst::Create(decryptedStr, ArrayRef(idxlist), "", Load); + LoadInst* newload = new LoadInst(newGep, "", false, 8, Load); + //replace current load with the decryption code + Load->replaceAllUsesWith(newload); + InstructionToDel.push_back(Load); + }else{ + // handle load i8** getelementptr inbounds ([X x i8*]* @string_array, i32 0, i64 x), align 8 + if (GlobalVariable* global = dyn_cast(gepInst->getPointerOperand())) { + if (ConstantArray* array = dyn_cast(global->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){ + StringRef gepOpName = gepElementFromArray->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, Load); + std::vector idxlist; + idxlist.push_back(gepElementFromArray->getOperand(gepElementFromArray->getNumOperands() - 1)); + GetElementPtrInst* newGep = GetElementPtrInst::Create(decryptedStr, ArrayRef(idxlist), "", Load); + //replace current load with the decryption code + Load->replaceAllUsesWith(newGep); + InstructionToDel.push_back(Load); + } + } + } + } + } + } + } + } + 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* 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); - } - } + 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::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); - } - } + 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 index e758701982d4..2f71600b43c0 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.h @@ -10,16 +10,20 @@ namespace llvm { class GlobalVariable; class Module; class LoadInst; + class StoreInst; class CallInst; class InvokeInst; + class ReturnInst; + class GetElementPtrInst; + class Instruction; } namespace llvm { - class AbstractStringEncryptionPass : public llvm::ModulePass { + class AbstractStringEncryptionPass : public ModulePass { public: AbstractStringEncryptionPass(char ID); - virtual bool runOnModule(llvm::Module &M); + virtual bool runOnModule(Module &M); protected: /** encryption method @@ -33,15 +37,28 @@ namespace llvm { * \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) = 0; + virtual Value* stringDecryption(Module &M, Value* EncryptedString, const uint64_t Size, Instruction* Parent) = 0; 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); + 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; }; } From 7c5444f8d9deceb9db32c4f36d93a9f466a986b9 Mon Sep 17 00:00:00 2001 From: Christophe Duvernois Date: Wed, 14 Jan 2015 15:32:34 +0100 Subject: [PATCH 10/11] string encryptiion clean up, skip const char** constant string, they are not encrypted --- .../AbstractStringEncryptionPass.cpp | 148 +++++------------- 1 file changed, 41 insertions(+), 107 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index 8f58d47676f2..e49901d2927d 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -39,15 +39,11 @@ bool AbstractStringEncryptionPass::runOnModule(Module &M) { if(c){ ConstantDataSequential *cds = dyn_cast(c); if(cds){ - if(cds->isString()){ + if(cds->isString() || cds->isCString()){ StringGlobalVars.push_back(I); }else{ - if(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"; - } + //not a string skip it + //errs() << "WARNING : Can't get string value from " << GV->getName() << " SKIP ENCRYPTION!\n"; } } } @@ -101,6 +97,38 @@ std::string AbstractStringEncryptionPass::getGlobalStringValue(GlobalVariable* G } 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) + continue; + + 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); + } + } + } + } + continue; + } + } + //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 ... @@ -116,7 +144,7 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve Value* retval = ret->getReturnValue(); if(retval == 0) continue; - + //check if the return value is a load instruction LoadInst* loadInst = dyn_cast(retval); if(loadInst){ @@ -136,9 +164,9 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve // handle load i8* getelementptr inbounds ([X x i8]* @string, i32 0, i64 x), align 1 ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); if(cds){ - errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; 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{ @@ -153,9 +181,9 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve if(GV){ ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); if(cds){ - errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; 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); } } @@ -186,9 +214,9 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve if(GV){ ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); if(cds){ - errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; 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); } } @@ -210,9 +238,9 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve if(GV){ ConstantDataSequential *cds = dyn_cast(GV->getInitializer()); if(cds){ - errs() << "WARNING : " << getGlobalStringValue(GV) << " cant't be ecnrypted (const char* directly used in return instruction)!\n"; 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); } } @@ -221,47 +249,6 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve } } } - - // I don't know how to handle this case : - // int main(){ - // const char *test[] = { "item0", "item1", "item2", "item3", "item4"}; - // printf("%s\n", test[3]); - // return 0; - // } - // do not encrypt those strings ... - // @TODO : find a way to handle this case and remove this code - 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) { - if(llvm::MemCpyInst* memcpyInst = dyn_cast(inst)){ - if (llvm::ConstantExpr *constExpr = llvm::dyn_cast(memcpyInst->getArgOperand(1))){ - if(llvm::CastInst* castInst = dyn_cast(constExpr->getAsInstruction())){ - if (GlobalVariable* global = dyn_cast(castInst->getOperand(0))) { - if (ConstantArray* array = dyn_cast(global->getInitializer())) { - for(unsigned int i = 0; i < array->getNumOperands(); i++){ - if(ConstantExpr* ce = dyn_cast(array->getOperand(i))){ - if(GetElementPtrInst *gep = dyn_cast(ce->getAsInstruction())){ - if(GlobalVariable* gv = dyn_cast(gep->getPointerOperand())){ - if(dyn_cast(gv->getInitializer())){ - errs() << "WARNING : " << getGlobalStringValue(gv) << " won't be ecnrypted (char** encryption not fully supported!)!\n"; - std::vector::iterator it = std::find(StringGlobalVars.begin(), StringGlobalVars.end(), gv); - if(it != StringGlobalVars.end()){ - StringGlobalVars.erase(it); - } - } - } - } - } - } - } - } - } - } - } - - } - } - } } bool AbstractStringEncryptionPass::encryptString(Module &M, std::vector& StringGlobalVars, std::vector& StringGlobalVarsToDelete) { @@ -376,61 +363,8 @@ 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){ - // handle load i8* getelementptr inbounds ([X x i8]* @string, i32 0, i64 x), align 1 - ConstantExpr *constExpr = dyn_cast(ptrOp); - if(constExpr != 0){ - GetElementPtrInst* gepInst = dyn_cast(constExpr->getAsInstruction()); - if (gepInst != 0) { - //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, it->second, size, Load); - std::vector idxlist; - idxlist.push_back(gepInst->getOperand(gepInst->getNumOperands() - 1)); - GetElementPtrInst* newGep = GetElementPtrInst::Create(decryptedStr, ArrayRef(idxlist), "", Load); - LoadInst* newload = new LoadInst(newGep, "", false, 8, Load); - //replace current load with the decryption code - Load->replaceAllUsesWith(newload); - InstructionToDel.push_back(Load); - }else{ - // handle load i8** getelementptr inbounds ([X x i8*]* @string_array, i32 0, i64 x), align 8 - if (GlobalVariable* global = dyn_cast(gepInst->getPointerOperand())) { - if (ConstantArray* array = dyn_cast(global->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){ - StringRef gepOpName = gepElementFromArray->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, Load); - std::vector idxlist; - idxlist.push_back(gepElementFromArray->getOperand(gepElementFromArray->getNumOperands() - 1)); - GetElementPtrInst* newGep = GetElementPtrInst::Create(decryptedStr, ArrayRef(idxlist), "", Load); - //replace current load with the decryption code - Load->replaceAllUsesWith(newGep); - InstructionToDel.push_back(Load); - } - } - } - } - } - } - } - } + if (GV == 0) return; - } //check if loaded pointer is constant Constant* c = GV->getInitializer(); From 982a50e8826b5bc24ee0bf3e2da77c96abbe674e Mon Sep 17 00:00:00 2001 From: Christophe Duvernois Date: Tue, 20 Jan 2015 17:31:28 +0100 Subject: [PATCH 11/11] struct { char* x = "str"; } encryption is not supported --- .../AbstractStringEncryptionPass.cpp | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp index e49901d2927d..5d5840bf1eb4 100644 --- a/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp +++ b/lib/Transforms/Obfuscation/AbstractStringEncryptionPass.cpp @@ -108,24 +108,45 @@ void AbstractStringEncryptionPass::checkStringsCanBeEncrypted(Module &M, std::ve if(array){ for(unsigned int i = 0; i < array->getNumOperands(); i++){ ConstantExpr* ce = dyn_cast(array->getOperand(i)); - if(ce == 0) - continue; - - GetElementPtrInst *gepElementFromArray = dyn_cast(ce->getAsInstruction()); - if(gepElementFromArray == 0) - continue; + 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); + 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); + } } } } } - continue; } }