Straw's B1og.

OLLVM-虚假控制流

字数统计: 1.2k阅读时长: 6 min
2024/03/17

OLLVM-虚假控制流

建议结合代码后的注释食用!

恶心棉

原理

虚控0

步骤

第一步:基本块拆分

虚控1

第二步:基本块克隆

虚控2

第三步:构造虚假跳转

虚控3

代码

BogusControlFlow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Instructions.h"
#include "SplitBasicBlock.h"
#include "Utils.h"
#include <vector>
#include <cstdlib>
#include <ctime>
using std::vector;
using namespace llvm;
//混淆次数
static cl::opt<int> obfuTimes("bcf_loop",cl::init(1),cl::desc("Obfucase a function <bcf_loop> time()."));
namespace{
class BogusControlFlow : public FunctionPass{
public:
static char ID;
BogusControlFlow():FunctionPass(ID){
srand(time(NULL));
}
bool runOnFunction(Function &F);
void bogus(BasicBlock *BB);
Value * createBogusCmp(BasicBlock *insertAfter);
};
}

bool BogusControlFlow::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){
bogus(BB);
}
}
return true;

}
Value *BogusControlFlow::createBogusCmp(BasicBlock * insertAfter){
//构建虚假跳转
Module *M=insertAfter->getModule();
GlobalVariable *xptr= new GlobalVariable(*M,TYPE_I32,false,GlobalValue::CommonLinkage,CONST_I32(0),"x");
//设置 x 初始值为 0;
GlobalVariable *yptr= new GlobalVariable(*M,TYPE_I32,false,GlobalValue::CommonLinkage,CONST_I32(0),"y");
//设置 y 初始值为 0;
LoadInst *x=new LoadInst(TYPE_I32,xptr,"",insertAfter);
//全局变量不能直接使用,用load来读取
LoadInst *y=new LoadInst(TYPE_I32,yptr,"",insertAfter);
ICmpInst *cmp1=new ICmpInst(*insertAfter,CmpInst::ICMP_SLT,y,CONST_I32(10));//y<10
BinaryOperator *opt1=BinaryOperator::CreateAdd(x,CONST_I32(1),"",insertAfter);//x+1
BinaryOperator *opt2=BinaryOperator::CreateMul(x,opt1,"",insertAfter); //x*(x+1)
BinaryOperator *opt3=BinaryOperator::CreateSRem(opt2,CONST_I32(2),"",insertAfter);//x*(x+1)%2
ICmpInst *cmp2=new ICmpInst(*insertAfter,CmpInst::ICMP_EQ,opt3,CONST_I32(0));//x*(x+1)%2==0
return BinaryOperator::CreateOr(cmp1,cmp2,"",insertAfter);
//创建了if((y<10||x*(x+1)%2==0)) 等价于if(true)
}
void BogusControlFlow::bogus(BasicBlock *entryBB){
//第一步,将基本快拆分成entryBB,bodyBB,endBB
BasicBlock *bodyBB=entryBB->splitBasicBlock(entryBB->getFirstNonPHI(),"BodyBB");
BasicBlock *endBB=bodyBB->splitBasicBlock(bodyBB->getTerminator(),"endBB");

//第二步,对中间的基本块 BodyBB 进行克隆,得到cloneBB
BasicBlock *cloneBB=createCloneBasicBlock(bodyBB);

//第三部 构建虚假跳转
//1.将entryBB,bodyBB,cloneBB末尾的绝对跳转移除
entryBB->getTerminator()->eraseFromParent();
bodyBB->getTerminator()->eraseFromParent();
cloneBB->getTerminator()->eraseFromParent();
//2.在entryBB和bodyBB的末尾插入条件恒为真的虚假比较指令
Value *cond1 =createBogusCmp(entryBB);
Value *cond2 =createBogusCmp(bodyBB);
//3.将entryBB到bodyBB的绝对跳转改为条件跳转
BranchInst::Create(bodyBB,cloneBB,cond1,entryBB);
//4.将bodyBB到endBB的绝对跳转改为条件跳转
BranchInst::Create(endBB,cloneBB,cond2,bodyBB);
//5.添加bodyBB.clone到bodyBB的绝对跳转
BranchInst::Create(bodyBB,cloneBB);

}
char BogusControlFlow::ID=0;
static RegisterPass<BogusControlFlow> X("bcf","My control bogus control flattening obfuscation");
//向LLVM注册我们的pass 其中X()中的第一个参数是指定LLVM Pass的参数 ,这样再使用opt加载这个so文件的时候,用这个参数来指定用哪个Pass来优化,第二个参数就是对Pass的描述。

Utils.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#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;
//第五步 修复PHI指令和逃逸变量
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)){//判断是不是逃逸变量(除了通过Alloc,并且定义在入口块的,都要处理)
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)){//判断是不是逃逸变量(除了通过Alloc,并且定义在入口块的,都要处理)
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++){ //遍历操作数不能用for:each ,要用for循环
Value *V=MapValue(I.getOperand(i),VMap);
if(V){//判断映射是否成功
I.setOperand(i,V);
}
}
}
return cloneBB;
}

效果

1
2
3
4
opt -load ../Build/LLVMObfuscator.so -bcf -S -enable-new-pm=0 IR/TestProgram.ll -o IR/TestProgram_bcf.ll
# opt -load ../Build/LLVMObfuscator.so -bcf -bcf_loop 2 -S -enable-new-pm=0 IR/TestProgram.ll -o IR/TestProgram_bcf.ll
#多次混淆
clang IR/TestProgram_bcf.ll -o Bin/TestProgram_bcf

用以下指令将其进行编译

dm1

得到一个还行的173行的代码,用D810跑一下还能看

再试着进行混淆2次

dm2

已经变成了一坨763行代码的粑粑,比一次混淆的文件大了一倍(感觉真实情况不会这么搞,太冗长了)

欣赏一下流程图()

pic

CATALOG
  1. 1. OLLVM-虚假控制流
    1. 1.1. 原理
    2. 1.2. 步骤
      1. 1.2.1. 第一步:基本块拆分
      2. 1.2.2. 第二步:基本块克隆
      3. 1.2.3. 第三步:构造虚假跳转
    3. 1.3. 代码
    4. 1.4. 效果