llvm代码混淆学习(八)

写在前面
随便学学 llvm 代码混淆,顺便做个毕设,水几篇文章就当做做笔记
随机控制流原理分析
概述
随机控制流是虚假控制流的一种变体,随机控制流通过克隆基本块,以及添加随机跳转(随机跳转到两个功能相同的基本块中的一个)来混淆控制流。
与虚假控制流不同,随机控制流中不存在不可达基本块和不透明谓词,因此用于去除虚假控制流的手段(消除不透明谓词、符号执行获得不可达基本块后去除)失效。
随机控制流的控制流图与虚假控制流类似,都呈长条形。
混淆效果
随机的跳转和冗余的不可达基本块导致了大量的垃圾代码,严重干扰了攻击者的分析,并且 rdrand 指令可以干扰某些符号执行引擎(如 angr )的分析。

原理
随机控制流同样是以基本块为单位进行混淆的,每个基本块要经过分裂、克隆、构造随机跳转和构造虚假随机跳转四个操作。

随机控制流代码实现思路
实现步骤
第一步:基本块拆分
将基本块拆分成头部、中部、尾部三个基本块,同虚假控制流。

通过 getFirstNonPHI 函数获取第一个不是 PHINode 的指令,以该指令为界限进行分割,得到 entryBB 和 bodyBB。
以 bodyBB 的终结指令为界限进行分割,最终得到头部、中部和尾部三个基本块,也就是 entryBB, bodyBB 和 endBB,其中尾部只有终结指令。
// 第一步,拆分得到 entryBB,bodyBB,endBB// 其中所有的 PHI 指令都在 entryBB(如果有的话)// endBB 只包含一条终结指令BasicBlock *entryBB = BB;BasicBlock *bodyBB = entryBB->splitBasicBlock(entryBB--getFirstNonPHIOrDbgOrLifetime(), "bodyBB");BasicBlock *endBB = bodyBB->splitBasicBlock(bodyBB->getTerminator(), "endBB");第二步:基本块克隆
将中间的基本块进行克隆,这里可以选择对基本块进行变异,但不能改变基本块的功能。(与虚假控制流不同)

能不能沿用之前的 createCloneBasicBlock函数?
与虚假控制流不同,随机控制流在克隆时,还需要修复逃逸变量
BasicBlock *cloneBB = createCloneBasicBlock(bodyBB);在一个基本块中定义的变量,如果在另一个基本块中被引用,那么该变量称为逃逸变量:
image-20230227160357638
BasicBlock* llvm::createCloneBasicBlock(BasicBlock *BB){ // 克隆之前先修复所有逃逸变量 vector<Instruction*> origReg; BasicBlock &entryBB = BB->getParent()->getEntryBlock(); for(Instruction &I : *BB){ if(!(isa<AllocaInst>(&I) && I.getParent() == &entryBB) && I.isUsedOutsideOfBlock(BB)){ origReg.push_back(&I); } } for(Instruction *I : origReg){ DemoteRegToStack(*I, entryBB.getTerminator()); } // 创建一个映射表类型变量 ValueToValueMapTy VMap; BasicBlock *cloneBB = CloneBasicBlock(BB, VMap, "cloneBB", BB->getParent()); // 对克隆基本块的引用进行修复 for(Instruction &I : *cloneBB){ for(int i = 0;i < I.getNumOperands();i ++){ Value *V = MapValue(I.getOperand(i), VMap); // 如果映射出来不为空,(成功) if(V){ I.setOperand(i, V); } } } return cloneBB;}第三步:构造随机跳转
将生成随机数的指令插入到 entryBB,将生成的随机数命名为randVar,并在entryBB后插入基于randVar的随机跳转指令。

向entryBB中插入随机数的指令和随机跳转,使其能够随机跳转到bodyBB或者bodyBB的克隆块。
其中随机数指令可以使用 LLVM 的内置函数rdrand:
如果使用了内置函数
rdrand,在生成了.ll文件后,需要用llc工具静态编译生成二进制文件,此时需要添加-mattr=rdrnd的属性:llc -filetype=obj -mattr=+rdrnd IR/TestProgram_rcf.ll -o Bin/TestProgram_rcf.o否则会出现 LLVM ERROR: Cannot select: t74: i64,i32,ch = X86ISD::RDRAND t0 错误。
// 在 entryBB 后插入随机跳转,使其能够随机跳转到第 bodyBB 或其克隆基本块 cloneBBentryBB->getTerminator()->eraseFromParent();// 获取 rdrand 函数Function *rdrand = Intrinsic::getDeclaration(entryBB->getModule(), Intrinsic::x86_rdrand_32);// 新建 call 指令调用 rdrand 函数,返回结果是一个结构体,第一个成员是生成的随机数,第二个参数表示该函数是否调用成功CallInst *randVarStruct = CallInst::Create(rdrand->getFunctionType(), rdrand, "", entryBB);// 通过 rdrand 内置函数获取随机数Value *randVar = ExtractValueInst::Create(randVarStruct, 0, "", entryBB);insertRandomBranch(randVar, bodyBB, cloneBB, entryBB);Intrinsic::getDeclaration(id)方法:获取并且创建一个 LLVM 内置函数,这个 id 可以在 intrinsics.gen 中找到。这里调用 LLVM 内置的 rdrand 生成随机数的函数。
insertRandomBranch函数:
void RandomControlFlow::insertRandomBranch(Value *randVar, BasicBlock *ifTrue, BasicBlock *ifFalse, BasicBlock *insertAfter){ // 对随机数进行等价变换 Value *alteredRandVar = alterVal(randVar, insertAfter); // and 1 == % 2 Value *randMod2 = BinaryOperator::Create(Instruction::And, alteredRandVar, CONST_I32(1), "", insertAfter); ICmpInst *condition = new ICmpInst(*insertAfter, ICmpInst::ICMP_EQ, randMod2, CONST_I32(1)); // 跳转到不同基本块 BranchInst::Create(ifTrue, ifFalse, condition, insertAfter);}对随机变量的恒等变换:
Value* RandomControlFlow::alterVal(Value *startVar,BasicBlock *insertAfter){ uint32_t code = rand() % 3; Value *result; if(code == 0){ // x = x * (x + 1) - x^2 BinaryOperator *op1 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(1), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Mul, startVar, op1, "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Mul, startVar, startVar, "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Sub, op2, op3, "", insertAfter); result = op4; }else if(code == 1){ // x = 3 * x * (x - 2) - 3 * x^2 + 7 * x BinaryOperator *op1 = BinaryOperator::Create(Instruction::Mul, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(2), "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Mul, op1, op2, "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Mul, startVar, startVar, "", insertAfter); BinaryOperator *op5 = BinaryOperator::Create(Instruction::Mul, op4, CONST_I32(3), "", insertAfter); BinaryOperator *op6 = BinaryOperator::Create(Instruction::Mul, startVar, CONST_I32(7), "", insertAfter); BinaryOperator *op7 = BinaryOperator::Create(Instruction::Sub, op3, op5, "", insertAfter); BinaryOperator *op8 = BinaryOperator::Create(Instruction::Add, op6, op7, "", insertAfter); result = op8; }else if(code == 2){ // x = (x - 1) * (x + 3) - (x + 4) * (x - 3) - 9 BinaryOperator *op1 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(1), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(4), "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op5 = BinaryOperator::Create(Instruction::Mul, op1, op2, "", insertAfter); BinaryOperator *op6 = BinaryOperator::Create(Instruction::Mul, op3, op4, "", insertAfter); BinaryOperator *op7 = BinaryOperator::Create(Instruction::Sub, op5, op6, "", insertAfter); BinaryOperator *op8 = BinaryOperator::Create(Instruction::Sub, op7, CONST_I32(9), "", insertAfter); result = op8; } return result;}第四步:构造虚假随机跳转
在bodyBB和cloneBB后插入虚假随机跳转指令(实际上仍然会直接跳转到endBB):

// 添加 bodyBB 到 bodyBB.clone 的虚假随机跳转bodyBB->getTerminator()->eraseFromParent();insertRandomBranch(randVar, endBB, cloneBB, bodyBB);// 添加 bodyBB.clone 到 bodyBB 的虚假随机跳转cloneBB->getTerminator()->eraseFromParent();insertRandomBranch(randVar, bodyBB, endBB, cloneBB);随机控制流代码实现
RandomControlFlow.cpp
#include "llvm/IR/Function.h"#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h"#include "llvm/Support/CommandLine.h"#include "llvm/IR/Module.h"#include "llvm/IR/Instructions.h"#include "llvm/Transforms/Utils/Local.h"#include "llvm/IR/Intrinsics.h"#include "llvm/IR/IntrinsicsX86.h"#include "SplitBasicBlock.h"#include "Utils.h"#include <vector>#include <cstdlib>#include <ctime>using std::vector;using namespace llvm;
// 混淆次数,混淆次数越多混淆结果越复杂static cl::opt<int> obfuTimes("rcf_loop", cl::init(1), cl::desc("Obfuscate a function <bcf_loop> time(s)."));
namespace{ struct RandomControlFlow : public FunctionPass{ static char ID;
RandomControlFlow() : FunctionPass(ID){ srand(time(NULL)); }
bool runOnFunction(Function &F);
// 创建一组等效于 origVar 的指令 Value* alterVal(Value *origVar,BasicBlock *insertAfter);
void insertRandomBranch(Value *randVar, BasicBlock *ifTrue, BasicBlock *ifFalse, BasicBlock *insertAfter);
// 以基本块为单位进行随机控制流混淆 bool randcf(BasicBlock *BB);
};}
bool RandomControlFlow::runOnFunction(Function &F){ INIT_CONTEXT(F); FunctionPass *pass = createSplitBasicBlockPass(); pass->runOnFunction(F); for(int i = 0;i < obfuTimes;i ++){ vector<BasicBlock*> origBB; for(BasicBlock &BB : F){ origBB.push_back(&BB); } for(BasicBlock *BB : origBB){ randcf(BB); } } return true;}
void RandomControlFlow::insertRandomBranch(Value *randVar, BasicBlock *ifTrue, BasicBlock *ifFalse, BasicBlock *insertAfter){ // 对随机数进行等价变换 Value *alteredRandVar = alterVal(randVar, insertAfter); // and 1 == % 2 // Value *randMod2 = BinaryOperator::CreateURem(alteredRandVar, CONST_I32(2), "", insertAfter); Value *randMod2 = BinaryOperator::Create(Instruction::And, alteredRandVar, CONST_I32(1), "", insertAfter); ICmpInst *condition = new ICmpInst(*insertAfter, ICmpInst::ICMP_EQ, randMod2, CONST_I32(1)); // 跳转到不同基本块 BranchInst::Create(ifTrue, ifFalse, condition, insertAfter);}
bool RandomControlFlow::randcf(BasicBlock *BB){ // 拆分得到 entryBB, bodyBB, endBB // 其中所有的 PHI 指令都在 entryBB(如果有的话) // endBB 只包含一条终结指令 BasicBlock *entryBB = BB; BasicBlock *bodyBB = entryBB->splitBasicBlock(BB->getFirstNonPHIOrDbgOrLifetime(), "bodyBB"); BasicBlock *endBB = bodyBB->splitBasicBlock(bodyBB->getTerminator(), "endBB"); BasicBlock *cloneBB = createCloneBasicBlock(bodyBB);
// 在 entryBB 后插入随机跳转,使其能够随机跳转到第 bodyBB 或其克隆基本块 cloneBB entryBB->getTerminator()->eraseFromParent(); // 获取 rdrand 函数 Function *rdrand = Intrinsic::getDeclaration(entryBB->getModule(), Intrinsic::x86_rdrand_32); // 新建 call 指令调用 rdrand 函数,返回结果是一个结构体,第一个成员是生成的随机数,第二个参数表示该函数是否调用成功 CallInst *randVarStruct = CallInst::Create(rdrand->getFunctionType(), rdrand, "", entryBB); // 通过 rdrand 内置函数获取随机数 Value *randVar = ExtractValueInst::Create(randVarStruct, 0, "", entryBB); insertRandomBranch(randVar, bodyBB, cloneBB, entryBB);
// 添加 bodyBB 到 bodyBB.clone 的虚假随机跳转 bodyBB->getTerminator()->eraseFromParent(); insertRandomBranch(randVar, endBB, cloneBB, bodyBB); // 添加 bodyBB.clone 到 bodyBB 的虚假随机跳转 cloneBB->getTerminator()->eraseFromParent(); insertRandomBranch(randVar, bodyBB, endBB, cloneBB);
return true;}
Value* RandomControlFlow::alterVal(Value *startVar,BasicBlock *insertAfter){ uint32_t code = rand() % 3; Value *result; if(code == 0){ // x = x * (x + 1) - x^2 BinaryOperator *op1 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(1), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Mul, startVar, op1, "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Mul, startVar, startVar, "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Sub, op2, op3, "", insertAfter); result = op4; }else if(code == 1){ // x = 3 * x * (x - 2) - 3 * x^2 + 7 * x BinaryOperator *op1 = BinaryOperator::Create(Instruction::Mul, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(2), "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Mul, op1, op2, "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Mul, startVar, startVar, "", insertAfter); BinaryOperator *op5 = BinaryOperator::Create(Instruction::Mul, op4, CONST_I32(3), "", insertAfter); BinaryOperator *op6 = BinaryOperator::Create(Instruction::Mul, startVar, CONST_I32(7), "", insertAfter); BinaryOperator *op7 = BinaryOperator::Create(Instruction::Sub, op3, op5, "", insertAfter); BinaryOperator *op8 = BinaryOperator::Create(Instruction::Add, op6, op7, "", insertAfter); result = op8; }else if(code == 2){ // x = (x - 1) * (x + 3) - (x + 4) * (x - 3) - 9 BinaryOperator *op1 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(1), "", insertAfter); BinaryOperator *op2 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op3 = BinaryOperator::Create(Instruction::Add, startVar, CONST_I32(4), "", insertAfter); BinaryOperator *op4 = BinaryOperator::Create(Instruction::Sub, startVar, CONST_I32(3), "", insertAfter); BinaryOperator *op5 = BinaryOperator::Create(Instruction::Mul, op1, op2, "", insertAfter); BinaryOperator *op6 = BinaryOperator::Create(Instruction::Mul, op3, op4, "", insertAfter); BinaryOperator *op7 = BinaryOperator::Create(Instruction::Sub, op5, op6, "", insertAfter); BinaryOperator *op8 = BinaryOperator::Create(Instruction::Sub, op7, CONST_I32(9), "", insertAfter); result = op8; } return result;}
char RandomControlFlow::ID = 0;static RegisterPass<RandomControlFlow> X("rcf", "Add random control flow to each function.");Utils.cpp
#include "../include/Utils.h"#include <vector>#include "llvm/IR/Instructions.h"#include "llvm/Transforms/Utils/Local.h"#include "llvm/Transforms/Utils/ValueMapper.h"#include "llvm/Transforms/Utils/Cloning.h"
using std::vector;using namespace llvm;
LLVMContext *CONTEXT = nullptr;
void llvm::fixStack(Function &F) { vector<PHINode*> origPHI; vector<Instruction*> origReg; BasicBlock &entryBB = F.getEntryBlock(); for(BasicBlock &BB : F){ for(Instruction &I : BB){ if(PHINode *PN = dyn_cast<PHINode>(&I)){ origPHI.push_back(PN); }else if(!(isa<AllocaInst>(&I) && I.getParent() == &entryBB) && I.isUsedOutsideOfBlock(&BB)){ origReg.push_back(&I); } } } for(PHINode *PN : origPHI){ DemotePHIToStack(PN, entryBB.getTerminator()); } for(Instruction *I : origReg){ DemoteRegToStack(*I, entryBB.getTerminator()); }}
BasicBlock* llvm::createCloneBasicBlock(BasicBlock *BB){ // 克隆之前先修复所有逃逸变量 vector<Instruction*> origReg; BasicBlock &entryBB = BB->getParent()->getEntryBlock(); for(Instruction &I : *BB){ if(!(isa<AllocaInst>(&I) && I.getParent() == &entryBB) && I.isUsedOutsideOfBlock(BB)){ origReg.push_back(&I); } } for(Instruction *I : origReg){ DemoteRegToStack(*I, entryBB.getTerminator()); } // 创建一个映射表类型变量 ValueToValueMapTy VMap; BasicBlock *cloneBB = CloneBasicBlock(BB, VMap, "cloneBB", BB->getParent()); // 对克隆基本块的引用进行修复 for(Instruction &I : *cloneBB){ for(int i = 0;i < I.getNumOperands();i ++){ Value *V = MapValue(I.getOperand(i), VMap); // 如果映射出来不为空,(成功) if(V){ I.setOperand(i, V); } } } return cloneBB;}Utils.h
#ifndef _UTILS_H_#define _UTILS_H_
#include "llvm/IR/Function.h"// 获取当前函数 context#define INIT_CONTEXT(F) CONTEXT=&F.getContext()#define TYPE_I32 Type::getInt32Ty(*CONTEXT)// 创建常量#define CONST_I32(V) ConstantInt::get(TYPE_I32, V, false)#define CONST(T, V) ConstantInt::get(T, V)
extern llvm::LLVMContext *CONTEXT;
// 对 PHI 指令和逃逸变量进行修复函数,添加到命名空间 llvm 里namespace llvm{ void fixStack(Function &F); BasicBlock* createCloneBasicBlock(BasicBlock *BB);}
#endif文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!






