简介

在上一个教学中,学习了如何写一个LLVM Pass示例来进行控制流平坦化,这篇文章,来学习如何二利用LLVM实现字符串的加密。

案例

需要加密的对象

这是一个经典的c语言样例,目的是输出字符串:hello world

#include 

int main(){
    printf("hello world\n");
    return 0;
}

加密pass编写

下面是完整的pass代码:
代码的目的是:让字符串在编译的过程中进行异或加密,并且在运行的过程中动态解密。

#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Constants.h"

using namespace llvm;

namespace{
    struct mypass : public PassInfoMixin{
        const uint8_t KEY = 0x42;

        Function *createDecryptFunc(Module *M){
            LLVMContext &Ctx = M->getContext();
            std::vector paramTypes = { PointerType::getUnqual(Ctx), Type::getInt32Ty(Ctx) };
            FunctionType *funcType = FunctionType::get(Type::getVoidTy(Ctx),paramTypes,false);

            Function *Func = Function::Create(funcType, GlobalValue::InternalLinkage, "my_decrypt_func", M);

            Argument *ArgData = Func->getArg(0);
            Argument *ArgLen  = Func->getArg(1);

            BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Func);
            BasicBlock *LoopCheckBB = BasicBlock::Create(Ctx, "loop_check", Func);
            BasicBlock *LoopBodyBB  = BasicBlock::Create(Ctx, "loop_body", Func);
            BasicBlock *ExitBB      = BasicBlock::Create(Ctx, "exit", Func);

            IRBuilder<> builder(EntryBB);
            builder.CreateBr(LoopCheckBB);
            builder.SetInsertPoint(LoopCheckBB);

            PHINode *LoopVar = builder.CreatePHI(Type::getInt32Ty(Ctx), 2, "i");
            LoopVar->addIncoming(builder.getInt32(0), EntryBB); 

            Value *Cond = builder.CreateICmpSLT(LoopVar, ArgLen, "cond");
            builder.CreateCondBr(Cond, LoopBodyBB, ExitBB);

            builder.SetInsertPoint(LoopBodyBB);

            Value *Ptr = builder.CreateInBoundsGEP(builder.getInt8Ty(), ArgData, LoopVar);
            Value *ByteVal = builder.CreateLoad(builder.getInt8Ty(), Ptr);
            Value *XorVal = builder.CreateXor(ByteVal, builder.getInt8(KEY));
            builder.CreateStore(XorVal, Ptr);

            Value *NextVar = builder.CreateAdd(LoopVar, builder.getInt32(1));
            LoopVar->addIncoming(NextVar, LoopBodyBB);

            builder.CreateBr(LoopCheckBB);
            builder.SetInsertPoint(ExitBB);
            builder.CreateRetVoid();

            return Func;
        }
        PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM){
            errs() << "Running On-Demand String Encryption Pass...\n";
            std::vector EncryptedGlobals;
            for(GlobalVariable &GV : M.globals()){
                if (!GV.hasInitializer() || !GV.isConstant() || GV.getName().contains("llvm.")) continue;

                Constant *Init = GV.getInitializer();
                ConstantDataArray* DataArray = dyn_cast(Init);

                if(DataArray && DataArray->isString()){
                    StringRef OriginalString = DataArray->getAsString();

                    if(OriginalString.size() < 2) continue;

                    errs() << "Encrypting string: " << OriginalString << "\n";
                    std::string EncryptedStr = OriginalString.str();
                    for(int i = 0; i < EncryptedStr.size(); i++){
                        EncryptedStr[i] ^= KEY;
                    }

                    Constant *NewInit = ConstantDataArray::getString(M.getContext(), EncryptedStr, false);
                    GV.setInitializer(NewInit);
                    GV.setConstant(false);
                    
                    EncryptedGlobals.push_back(&GV);
                }
            }

            if(EncryptedGlobals.empty()) return PreservedAnalyses::all();

            Function *DecryptFunc = createDecryptFunc(&M);

            for(GlobalVariable *GV : EncryptedGlobals){
                std::vector user;
                for(User *U: GV->users()){
                    Instruction* ins = dyn_cast(U);
                    if(ins->getFunction() == DecryptFunc) continue;
                    user.push_back(ins);
                }
                
                for(Instruction *ins : user){
                    IRBuilder<> builder(ins);
                    ConstantDataArray* DataArray = dyn_cast(GV->getInitializer());
                    int len = DataArray->getNumElements();
                    builder.CreateCall(DecryptFunc, {GV, builder.getInt32(len)});
                }
            }
            return PreservedAnalyses::none();
        }
    };
}

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo(){
    return{
        LLVM_PLUGIN_API_VERSION,
        "mypass",
        "v0.1",
        [](PassBuilder &PB){
            PB.registerPipelineParsingCallback(
                [](StringRef Name, ModulePassManager &MPM, ArrayRef){
                    if(Name == "mypass"){
                        MPM.addPass(mypass());
                        return true;
                    }
                    return false;
                }
            );
        }
    };
}

代码解释

看到上面的pass代码,我们会感到头晕目眩,没关系,下面我们一步步拆解。
上面的代码分主要分为两部分:

  1. 构建异或的解密函数(createDecryptFunc
  2. 加密字符串,并且将上面构建的解密函数插入代码。

CMakeLists.txt

编译可以直接用下面的cmake配置文件,编译过程在之前文章详细讲解

cmake_minimum_required(VERSION 4.1.1)
project(mypass) 

set(LLVM_DIR "D:/LLVM/llvm-project/build/lib/cmake/llvm")
find_package(LLVM REQUIRED CONFIG)
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
include(AddLLVM)
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(mypass MODULE mypass.cpp)
set_target_properties(mypass PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) 
target_link_libraries(mypass LLVMCore LLVMSupport)     
target_compile_options(mypass PRIVATE /utf-8)#用中文

使用效果展示

编译并执行

图片中可以看出,可以正常运行
命令运行

反编译查看区别

原始test.exe

字符串加密

加密test_opt.exe

原始

根据上面的图片,可以看到,上面使用的pass,成功将HelloWorld加密了。

如果❤喜欢❤本系列教程,就点个关注吧,后续不定期更新~


原文地址: https://www.cveoy.top/t/topic/qFXx 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录