OLLVM介绍

是LLVM项目的一个开源分支,目的是通过代码混淆和防篡改来提高软件的安全性。

OLLVM提供了三种经典代码混淆方式:

  • 控制流平坦化 Control Flow Flattening
  • 虚假控制流 Bogus Control Flow
  • 指令替换 Instruction Subsititution

环境配置

1
2
3
4
5
6
7
8
9
10
11
docker pull nickdiego/ollvm-build
git clone https://github.com/nickdiego/docker-ollvm.git
git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git
#切换到docker-ollvm文件夹内
#打开ollvm-build.sh文件,在149与150行之间加入
DOCKER_CMD+=" -DLLVM_INCLUDE_TESTS=OFF"
#运行脚本
sudo ./ollvm-build.sh ../obfuscator
#配置软链接指向ollvm的clang,防止与llvm中的clang以及ubuntu自带的clang冲突
ln -s /home/zhuyuan/obfuscator/build_release/bin/clang /usr/local/bin/ollvm-clang
ln -s /home/zhuyuan/obfuscator/build_release/bin/clang++ /usr/local/bin/ollvm-clang++

控制流平坦化(Control Flow Flattening)

通过创建分发块和返回块来实现将嵌套的循环平坦化为扁平的基本块序列

1
2
3
4
入口块:进入函数第一个执行的基本块。
主分发块与子分发块:负责跳转到下一个要执行的原基本块。
原基本块:混淆之前的基本块,真正完成程序工作的基本块。
返回块:返回到主分发块。

img

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "llvm/IR/Function.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <vector>
#include <cstdlib>
#include <ctime>
#include <random>
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include "llvm/Transforms/Utils/Cloning.h"

using namespace llvm;
using namespace std;

//newpass写法
namespace{
class Flattening :public PassInfoMixin<Flattening>{
public :
std::mt19937 rng;
static char ID;
Flattening() : rng(std::random_device{}()) {}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
flatten(F);
fixStack(F);
return PreservedAnalyses::all();
}
// Flatten function
void flatten(Function &F);
void fixStack(Function &F);
};
}

void Flattening::flatten(Function &F){

//将所有基本块保存到vector容器中
vector<BasicBlock*>origBB;
for(Function::iterator it = F.begin();it != F.end();it++){
BasicBlock *tmp = &*it;
origBB.push_back(tmp);

BasicBlock *BB = &*it;
if(isa<InvokeInst>(BB->getTerminator())){
return;
}
}
//errs() << "Flatten: " << F.getName() << "\n";
//如果只有一个基本块则直接返回
if(origBB.size() <= 1){
return;
}
//删掉vector容器中的入口块
origBB.erase(origBB.begin());

Function::iterator it = F.begin();
BasicBlock *entry = &*it;
// 如果第一个基本块的末尾是条件跳转,单独分离
BranchInst *br = nullptr;
if(isa<BranchInst>(entry->getTerminator())){
br = cast<BranchInst>(entry->getTerminator());
}

if((br!=nullptr && br->isConditional()) || entry->getTerminator()->getNumSuccessors() > 1){
BasicBlock::iterator it = entry->end();
--it;
if(entry->size() > 1){
--it;
}

BasicBlock *tmpBB = entry->splitBasicBlock(it,"newBB");
origBB.insert(origBB.begin(),tmpBB);
}
//删除原入口块的跳转指令
entry->getTerminator()->eraseFromParent();

//在入口块创建一个switchVar变量并通过随机数赋值
AllocaInst *switchVar = new AllocaInst(Type::getInt32Ty(F.getContext()),0,"switchVar",entry);
new StoreInst(ConstantInt::get(Type::getInt32Ty(F.getContext()),rng()),switchVar,entry);
//在入口块前创建一个dispatchBB块和endBB块
BasicBlock *dispatchBB = BasicBlock::Create(F.getContext(),"dispatchBB",&F,entry);
BasicBlock *endBB = BasicBlock::Create(F.getContext(),"endBB",&F,entry);
//在dispatchBB块中创建一个load指令将入口块的switchVar变量赋值到dispatchBB中的switchVar
LoadInst *load = new LoadInst(Type::getInt32Ty(F.getContext()),switchVar,"switchVar",dispatchBB);
//将入口块挪到dispatchBB块之前
entry->moveBefore(dispatchBB);
//在入口块创建一个跳转指令,跳转到dispatchBB块
BranchInst::Create(dispatchBB,entry);
//在endBB块创建一个跳转指令,跳转到dispatchBB块
BranchInst::Create(dispatchBB,endBB);
//在endBB块前创建一个swDefault块,并在swDefault块中创建一个跳转指令,跳到endBB块
BasicBlock *swDefault = BasicBlock::Create(F.getContext(),"swDefault",&F,endBB);
BranchInst::Create(endBB,swDefault);
//在dispatchBB块中创建一个switch语句
SwitchInst *switchI = SwitchInst::Create(&*F.begin(),swDefault,0,dispatchBB);
switchI->setCondition(load);
//删除入口块的末尾指令,再添加跳转从入口块跳到dispatchBB中
F.begin()->getTerminator()->eraseFromParent();
BranchInst::Create(dispatchBB,&*F.begin());
//枚举更改各个case 基本块
for(vector<BasicBlock*>::iterator it = origBB.begin();it != origBB.end();++it){
BasicBlock *BB = *it;
ConstantInt *numCase = nullptr;

BB->moveBefore(endBB);

numCase = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),rng()));
switchI->addCase(numCase,BB);
//直接返回的基本块
if(BB->getTerminator()->getNumSuccessors() == 0 ){
continue;
}
//非条件跳转的基本块
if(BB->getTerminator()->getNumSuccessors() == 1){
BasicBlock *succ = BB->getTerminator()->getSuccessor(0);
BB->getTerminator()->eraseFromParent();

numCase = switchI->findCaseDest(succ);

if(numCase == nullptr){
numCase = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),rng()));
}
new StoreInst(numCase,load->getPointerOperand(),BB);
BranchInst::Create(endBB,BB);
continue;
}
//条件跳转
if(BB->getTerminator()->getNumSuccessors() == 2){
ConstantInt *numCaseTrue = switchI->findCaseDest(BB->getTerminator()->getSuccessor(0));
ConstantInt *numCaseFalse = switchI->findCaseDest(BB->getTerminator()->getSuccessor(1));
if(numCaseTrue == nullptr){
numCaseTrue = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),rng()));
}
if(numCaseFalse == nullptr){
numCaseFalse = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),rng()));
}

BranchInst *br = cast<BranchInst>(BB->getTerminator());
SelectInst *sel = SelectInst::Create(br->getCondition(),numCaseTrue,numCaseFalse,"",BB->getTerminator());

BB->getTerminator()->eraseFromParent();

new StoreInst(sel,load->getPointerOperand(),BB);
BranchInst::Create(endBB,BB);
continue;
}

}
}
void Flattening::fixStack(Function &F){
vector<PHINode*> origPHI;
vector<Instruction*> origReg;
BasicBlock &entryBB = F.getEntryBlock();
// 搜索PHI指令和逃逸变量添加到对应vector容器
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);
}
for(Instruction *I : origReg){
DemoteRegToStack(*I);
}
}

//注册插件,加载pass
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK

llvmGetPassPluginInfo(){
return {
LLVM_PLUGIN_API_VERSION,"FlatteningPass","v0.1",
[](PassBuilder &PB){
PB.registerPipelineParsingCallback(
[](StringRef Name,FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>){
if(Name == "Flatten"){
FPM.addPass(Flattening());
return true;
}
return false;
}
);
}
};
}

未完待学习