Giter VIP home page Giter VIP logo

llvm-string-obfuscator's Introduction

LLVM String Obfuscator

Hide all your precious strings without touching a single line of your source code, powered by LLVM bytecode manipulation.

Accompanying post: https://medium.com/@polarply/build-your-first-llvm-obfuscator-80d16583392b

image

How-To

  1. Install llvm sudo apt install llvm

  2. Build the StringObfuscator library:

mkdir build
cd build
cmake ..
make
  1. Generate LLVM bytecode from your binary and run the StringObfuscator pass on it:
clang -emit-llvm hello.c -c -o hello.bc
opt -load-pass-plugin=./build/StringObfuscator/libLLVMStringObfuscator.so -passes="string-obfuscator-pass" < hello.bc -o out.bc
llc out.bc -o out.s
clang -static out.s -o out

For Rust:

rustc hello.rs --emit=llvm-bc -o hellor.bc
opt -load-pass-plugin=./build/StringObfuscator/libLLVMStringObfuscator.so -passes="string-obfuscator-pass" < ./examples/hellor.bc -o out.bc
llc out.bc -o out.s
ruststd=$(basename $(ls /usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd*.so) | sed 's/lib//g' | sed 's/\.so//g')
clang out.s -L/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib -l$ruststd -o out
  1. Leave a like :)

llvm-string-obfuscator's People

Contributors

tsarpaul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

llvm-string-obfuscator's Issues

Example hello.c program doesn't work

Decode stub checks for null byte before decoding to determine the end of a string. If compiler puts two strings together in the string table without any padding between them, a string will get decoded multiple times.

I ran into this issue with the given hello.c program. 'hello world %d' and '%s' were placed together without any space between. Since the encoded null byte 0x01 wasn't decoded, the decoder bled into the '%s' string and decoded it with the 'hello world %d' string, and then decoded it again afterwards. This caused printf to receive '$r' instead of '%s' and failed to print how much I love bananas.

Easy fix: change the cmp in decode stub to check for 0x01 instead of 0x00 to end string.

Unable to make project

Hi, I am trying to make this project but encounter the following errors:

[ 50%] Building CXX object StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/StringObfuscator.o
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp: In function ‘llvm::Function* {anonymous}::createDecodeStubFunc(llvm::Module&, std::vector<{anonymous}::GlobalString*>&, llvm::Function*)’:
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:31:2: error: ‘FunctionCallee’ was not declared in this scope
FunctionCallee DecodeStubCallee = M.getOrInsertFunction("decode_stub",
^~~~~~~~~~~~~~
/llvm/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:33:44: error: ‘DecodeStubCallee’ was not declared in this scope
Function DecodeStubFunc = cast(DecodeStubCallee.getCallee());
^~~~~~~~~~~~~~~~
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:33:44: note: suggested alternative: ‘DecodeStubFunc’
Function DecodeStubFunc = cast(DecodeStubCallee.getCallee());
^~~~~~~~~~~~~~~~
DecodeStubFunc
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:47:78: error: no matching function for call to ‘llvm::IRBuilder<>::CreateStructGEP(llvm::GlobalVariable
&, unsigned int&)’
auto String = Builder.CreateStructGEP(GlobString->Glob, GlobString->index);
^
In file included from /llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:7:0:
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1365:10: note: candidate: llvm::Value
llvm::IRBuilder<T, Inserter>::CreateStructGEP(llvm::Type
, llvm::Value*, unsigned int, const llvm::Twine&) [with T = llvm::ConstantFolder; Inserter = llvm::IRBuilderDefaultInserter]
Value CreateStructGEP(Type Ty, Value Ptr, unsigned Idx,
^~~~~~~~~~~~~~~
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1365:10: note: candidate expects 4 arguments, 2 provided
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:49:43: error: no matching function for call to ‘llvm::IRBuilder<>::CreateCall(llvm::Function
&, )’
Builder.CreateCall(DecodeFunc, {StrPtr});
^
In file included from /llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:7:0:
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1663:13: note: candidate: llvm::CallInst
llvm::IRBuilder<T, Inserter>::CreateCall(llvm::Value
, llvm::ArrayRefllvm::Value*, const llvm::Twine&, llvm::MDNode*) [with T = llvm::ConstantFolder; Inserter = llvm::IRBuilderDefaultInserter]
CallInst CreateCall(Value Callee, ArrayRef<Value > Args = None,
^~~~~~~~~~
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1663:13: note: no known conversion for argument 2 from ‘’ to ‘llvm::ArrayRefllvm::Value*’
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1670:13: note: candidate: llvm::CallInst
llvm::IRBuilder<T, Inserter>::CreateCall(llvm::FunctionType
, llvm::Value
, llvm::ArrayRefllvm::Value*, const llvm::Twine&, llvm::MDNode*) [with T = llvm::ConstantFolder; Inserter = llvm::IRBuilderDefaultInserter]
CallInst CreateCall(FunctionType FTy, Value Callee,
^~~~~~~~~~
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1670:13: note: candidate expects 5 arguments, 2 provided
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1679:13: note: candidate: llvm::CallInst
llvm::IRBuilder<T, Inserter>::CreateCall(llvm::Value
, llvm::ArrayRefllvm::Value*, llvm::ArrayRef<llvm::OperandBundleDefTllvm::Value* >, const llvm::Twine&, llvm::MDNode
) [with T = llvm::ConstantFolder; Inserter = llvm::IRBuilderDefaultInserter]
CallInst CreateCall(Value Callee, ArrayRef<Value > Args,
^~~~~~~~~~
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1679:13: note: candidate expects 5 arguments, 2 provided
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1688:13: note: candidate: llvm::CallInst
llvm::IRBuilder<T, Inserter>::CreateCall(llvm::Function
, llvm::ArrayRefllvm::Value*, const llvm::Twine&, llvm::MDNode
) [with T = llvm::ConstantFolder; Inserter = llvm::IRBuilderDefaultInserter]
CallInst *CreateCall(Function *Callee, ArrayRef<Value > Args,
^~~~~~~~~~
/usr/lib/llvm-6.0/include/llvm/IR/IRBuilder.h:1688:13: note: no known conversion for argument 2 from ‘’ to ‘llvm::ArrayRefllvm::Value*’
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp: In function ‘llvm::Function
{anonymous}::createDecodeFunc(llvm::Module&)’:
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:61:2: error: ‘FunctionCallee’ was not declared in this scope
FunctionCallee DecodeFuncCallee = M.getOrInsertFunction("decode",
^~~~~~~~~~~~~~
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:64:40: error: ‘DecodeFuncCallee’ was not declared in this scope
Function *DecodeFunc = cast(DecodeFuncCallee.getCallee());
^~~~~~~~~~~~~~~~
/llvm-string-obfuscator/StringObfuscator/StringObfuscator.cpp:64:40: note: suggested alternative: ‘DecodeFunc’
Function *DecodeFunc = cast(DecodeFuncCallee.getCallee());
^~~~~~~~~~~~~~~~
DecodeFunc
StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/build.make:62: recipe for target 'StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/StringObfuscator.o' failed
make[2]: *** [StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/StringObfuscator.o] Error 1
CMakeFiles/Makefile2:117: recipe for target 'StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/all' failed
make[1]: *** [StringObfuscator/CMakeFiles/LLVMStringObfuscator.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

Can advise? Thanks!

licenses issue

Hello, we quoted and modified your code to implement a Rust code obfuscator, and will open source our project, but your code project did not add authorized licenses, would you add license file to your project? licenses such as https://opensource.org/licenses/MIT or other licenses, thanks.

cargo build

Hi, this is not really an issue. Could you advise on how to run the llvm-string-obfuscator with cargo build? Many thanks!

There is a problem with this decode function.

Limited the decode data length

char *EncodeString(const char *Data, unsigned int lenght)
{
    char *NewData = (char *)malloc(lenght);
    for (unsigned int i = 0; i < lenght; i++) {
        NewData[i] = Data[i] + 1;
    }

    return NewData;
}

void decode(char *Data, unsigned int lenght)
{
    if (Data) {        
        for (unsigned int i = 0; i < lenght; i++) {
            Data[i] -= 1;
        }
    }
}
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local void @decode(i8* %Data, i32 %lenght) #1 {
entry:
  %lenght.addr = alloca i32, align 4
  %Data.addr = alloca i8*, align 8
  %i = alloca i32, align 4
  store i32 %lenght, i32* %lenght.addr, align 4
  store i8* %Data, i8** %Data.addr, align 8
  %0 = load i8*, i8** %Data.addr, align 8
  %tobool = icmp ne i8* %0, null
  br i1 %tobool, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  store i32 0, i32* %i, align 4
  br label %for.cond

for.cond:                                         ; preds = %for.inc, %if.then
  %1 = load i32, i32* %i, align 4
  %2 = load i32, i32* %lenght.addr, align 4
  %cmp = icmp ult i32 %1, %2
  br i1 %cmp, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %3 = load i8*, i8** %Data.addr, align 8
  %4 = load i32, i32* %i, align 4
  %idxprom = zext i32 %4 to i64
  %arrayidx = getelementptr inbounds i8, i8* %3, i64 %idxprom
  %5 = load i8, i8* %arrayidx, align 1
  %conv = sext i8 %5 to i32
  %sub = sub nsw i32 %conv, 1
  %conv1 = trunc i32 %sub to i8
  store i8 %conv1, i8* %arrayidx, align 1
  br label %for.inc

for.inc:                                          ; preds = %for.body
  %6 = load i32, i32* %i, align 4
  %inc = add i32 %6, 1
  store i32 %inc, i32* %i, align 4
  br label %for.cond

for.end:                                          ; preds = %for.cond
  br label %if.end

if.end:                                           ; preds = %for.end, %entry
  ret void
}
Function *createDecodeFunc(Module &M)
{
    auto &Ctx = M.getContext();

    // Add Decode function
    FunctionType *fn_type = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt8PtrTy(Ctx), Type::getInt32Ty(Ctx)}, false);
    FunctionCallee DecodeFuncCallee = M.getOrInsertFunction("decode", fn_type);
    Function *DecodeFunc = cast<Function>(DecodeFuncCallee.getCallee());
    DecodeFunc->setCallingConv(CallingConv::C);

    // Name DecodeFunc arguments
    Function::arg_iterator Args = DecodeFunc->arg_begin();
    Value *Data = Args++;
    Data->setName("Data");
    Value *lenght = Args++;
    lenght->setName("lenght");

    // Create blocks 
    BasicBlock *BEntry = BasicBlock::Create(Ctx, "entry", DecodeFunc);
    BasicBlock *BIfThen = BasicBlock::Create(Ctx, "if.then", DecodeFunc);
    BasicBlock *BIfEnd = BasicBlock::Create(Ctx, "if.end", DecodeFunc);
    BasicBlock *BForCond = BasicBlock::Create(Ctx, "for.cond", DecodeFunc);
    BasicBlock *BForBody = BasicBlock::Create(Ctx, "for.body", DecodeFunc);
    BasicBlock *BForInc = BasicBlock::Create(Ctx, "for.inc", DecodeFunc);
    BasicBlock *BForEnd = BasicBlock::Create(Ctx, "for.end", DecodeFunc);

    //// Entry block
    IRBuilder<> B1(BEntry);
    auto lenght_addr = B1.CreateAlloca(B1.getInt32Ty(), nullptr, "lenght.addr");
    auto Data_addr = B1.CreateAlloca(B1.getInt8PtrTy(), nullptr, "Data.addr");
    auto i = B1.CreateAlloca(B1.getInt32Ty(), nullptr, "i");

    B1.CreateStore(lenght, lenght_addr);
    B1.CreateStore(Data, Data_addr);

    auto var0 = B1.CreateLoad(Data_addr);
    auto tobool = B1.CreateICmpNE(var0, Constant::getNullValue(Type::getInt8PtrTy(Ctx)), "tobool");
    B1.CreateCondBr(tobool, BIfThen, BIfEnd);

    // if.then block
    IRBuilder<> B2(BIfThen);
    B2.CreateStore(B2.getInt32(0), i);
    B2.CreateBr(BForCond);

    // for.cond block
    IRBuilder<> B3(BForCond);
    auto var1 = B3.CreateLoad(i);
    auto var2 = B3.CreateLoad(lenght_addr);
    auto cmp = B3.CreateICmpULT(var1, var2, "cmp");
    B3.CreateCondBr(cmp, BForBody, BForEnd);

    // for.body block
    IRBuilder<> B4(BForBody);
    auto var3 = B4.CreateLoad(Data_addr);
    auto var4 = B4.CreateLoad(i);
    auto idxprom = B4.CreateZExt(var4, B4.getInt64Ty(), "idxprom");
    auto arrayidx = B4.CreateInBoundsGEP(B4.getInt8Ty(), var3, idxprom, "arrayidx");

    auto var5 = B4.CreateLoad(arrayidx);
    auto conv = B4.CreateSExt(var5, B4.getInt32Ty(), "conv");
    auto sub = B4.CreateSub(conv, B4.getInt32(1), "sub", false, true);
    auto conv1 = B4.CreateTrunc(sub, B4.getInt8Ty(), "conv1");
    B4.CreateStore(conv1, arrayidx);
    B4.CreateBr(BForInc);

    // for.inc block
    IRBuilder<> B5(BForInc);
    auto var6 = B5.CreateLoad(i);
    auto inc = B5.CreateAdd(var6, B5.getInt32(1), "inc");
    B5.CreateStore(inc, i);
    B5.CreateBr(BForCond);

    // for.end block
    IRBuilder<> B6(BForEnd);
    B6.CreateBr(BIfEnd);

    // End block
    IRBuilder<> B7(BIfEnd);
    B7.CreateRetVoid();

    return DecodeFunc;
}
Function *createDecodeStubFunc(Module &M, vector<GlobalString *> &GlobalStrings, Function *DecodeFunc)
{
    auto &Ctx = M.getContext();
    // Add DecodeStub function
    FunctionCallee DecodeStubCallee = M.getOrInsertFunction("decode_stub", Type::getVoidTy(Ctx));
    Function *DecodeStubFunc = cast<Function>(DecodeStubCallee.getCallee());
    DecodeStubFunc->setCallingConv(CallingConv::C);

    // Create entry block
    BasicBlock *BB = BasicBlock::Create(Ctx, "entry", DecodeStubFunc);
    IRBuilder<> Builder(BB);

    // Add calls to decode every encoded global
    for (GlobalString *GlobString : GlobalStrings) {
        if (GlobString->type == GlobString->SIMPLE_STRING_TYPE) {
            Constant *Zero = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
            Value *Idx[] = {Zero, Zero};
            auto StrPtr = Builder.CreateInBoundsGEP(GlobString->Glob->getValueType(), GlobString->Glob, Idx);

            // Extract raw string
            auto CDA = dyn_cast<ConstantDataArray>(GlobString->Glob->getInitializer());
            StringRef StrVal = CDA->getAsString();
            size_t Size = StrVal.size();

            Builder.CreateCall(DecodeFunc, {StrPtr, ConstantInt::get(Builder.getInt32Ty(), Size)});
        }
        else if (GlobString->type == GlobString->STRUCT_STRING_TYPE) {
            auto StrPtr = Builder.CreateStructGEP(GlobString->Glob, GlobString->index);

            // Extract raw string
            auto CDA = dyn_cast<ConstantDataArray>(GlobString->Glob->getInitializer()->getOperand(GlobString->index));
            StringRef StrVal = CDA->getAsString();
            size_t Size = StrVal.size();

            Builder.CreateCall(DecodeFunc, {StrPtr, ConstantInt::get(Builder.getInt32Ty(), Size)});
        }
    }

    Builder.CreateRetVoid();

    // log IR info
    std::string str;
    raw_string_ostream OS(str);
    DecodeStubFunc->print(OS);
    errs() << str;

    return DecodeStubFunc;
}
void createDecodeStubBlock(Module &M, Function *DecodeStubFunc)
{
    Function *F = M.getFunction("main");
    auto &Ctx = F->getContext();
    BasicBlock &EntryBlock = F->getEntryBlock();

    auto Inst = EntryBlock.begin();
    // // Create new block
    // BasicBlock *NewBB = BasicBlock::Create(Ctx, "DecodeStub", EntryBlock.getParent(), &EntryBlock);
    // IRBuilder<> Builder(NewBB);
    // 
    // // Call stub func instruction
    // Builder.CreateCall(DecodeStubFunc);
    // // Jump to original entry block
    // Builder.CreateBr(&EntryBlock);

    IRBuilder<> Builder(&*Inst);
    Builder.CreateCall(DecodeStubFunc);
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.