参考网站:Obfuscator-llvm源码分析
参考网站:ollvm源码分析
Pass之BogusControlFlow
实现功能是:添加虚假控制流
1 命令
命令 | 解析 |
---|---|
-mllvm -bcf | 激活虚假控制流 |
-mllvm -bcf_loop | 若被激活,指定虚假控制流应用次数,默认为1 |
-mllvm -bcf_prob=40 | 若被激活,指定某比率的基本块被混淆,默认为30% |
2 代码分析
2.1 入口函数runOnFunction
继承了FunctionPass,因此它的入口函数即为runOnFunction。
virtual bool runOnFunction(Function &F){
// Check if the percentage is correct
if (ObfTimes <= 0) {
errs()<<"BogusControlFlow application number -bcf_loop=x must be x > 0";
return false;
}
// Check if the number of applications is correct
if ( !((ObfProbRate > 0) && (ObfProbRate <= 100)) ) {
errs()<<"BogusControlFlow application basic blocks percentage -bcf_prob=x must be 0 < x <= 100";
return false;
}
// If fla annotations
if(toObfuscate(flag,&F,"bcf")) {
bogus(F);
doF(*F.getParent());
return true;
}
return false;
} // end of runOnFunction()
首先判断ObfTimes与ObfProbRate。ObfTimes指循环执行的次数,必须大于0,默认为它;ObfProbRate指每个基本块被混淆的几率,必须在0到100之间,默认为30。然后toObfuscate(flag,&F,“bcf”)函数判断是否包含了启动bcf的命令,满足条件则调用bogus函数与doF函数。
2.2 bogus函数
bogus函数首先将本function的所有basicblock存放到一个list容器中,然后使用一个while循环调用addBogusFlow函数对选中的basicblock进行增加虚假控制流。
void bogus(Function &F) {
// For statistics and debug
++NumFunction;
int NumBasicBlocks = 0;
bool firstTime = true; // First time we do the loop in this function
bool hasBeenModified = false;
DEBUG_WITH_TYPE("opt", errs() << "bcf: Started on function " << F.getName() << "\n");
DEBUG_WITH_TYPE("opt", errs() << "bcf: Probability rate: "<< ObfProbRate<< "\n");
if(ObfProbRate < 0 || ObfProbRate > 100){
DEBUG_WITH_TYPE("opt", errs() << "bcf: Incorrect value,"
<< " probability rate set to default value: "
<< defaultObfRate <<" \n");
ObfProbRate = defaultObfRate;
}
DEBUG_WITH_TYPE("opt", errs() << "bcf: How many times: "<< ObfTimes<< "\n");
if(ObfTimes <= 0){
DEBUG_WITH_TYPE("opt", errs() << "bcf: Incorrect value,"
<< " must be greater than 1. Set to default: "
<< defaultObfTime <<" \n");
ObfTimes = defaultObfTime;
}
NumTimesOnFunctions = ObfTimes;
int NumObfTimes = ObfTimes;
// Real begining of the pass
// Loop for the number of time we run the pass on the function
do{
DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function " << F.getName()
<<", before the pass:\n");
DEBUG_WITH_TYPE("cfg", F.viewCFG());
// Put all the function's block in a list
std::list<BasicBlock *> basicBlocks;
for (Function::iterator i=F.begin();i!=F.end();++i) {
basicBlocks.push_back(&*i);
}
DEBUG_WITH_TYPE("gen", errs() << "bcf: Iterating on the Function's Basic Blocks\n");
while(!basicBlocks.empty()){
NumBasicBlocks ++;
// Basic Blocks' selection
if((int)llvm::cryptoutils->get_range(100) <= ObfProbRate){
DEBUG_WITH_TYPE("opt", errs() << "bcf: Block "
<< NumBasicBlocks <<" selected. \n");
hasBeenModified = true;
++NumModifiedBasicBlocks;
NumAddedBasicBlocks += 3;
FinalNumBasicBlocks += 3;
// Add bogus flow to the given Basic Block (see description)
BasicBlock *basicBlock = basicBlocks.front();
addBogusFlow(basicBlock, F);
}
else{
DEBUG_WITH_TYPE("opt", errs() << "bcf: Block "
<< NumBasicBlocks <<" not selected.\n");
}
// remove the block from the list
basicBlocks.pop_front();
if(firstTime){ // first time we iterate on this function
++InitNumBasicBlocks;
++FinalNumBasicBlocks;
}
} // end of while(!basicBlocks.empty())
DEBUG_WITH_TYPE("gen", errs() << "bcf: End of function " << F.getName() << "\n");
if(hasBeenModified){ // if the function has been modified
DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function " << F.getName()
<<", after the pass: \n");
DEBUG_WITH_TYPE("cfg", F.viewCFG());
}
else{
DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function's not been modified \n");
}
firstTime = false;
}while(--NumObfTimes > 0);
}
外层do…while循环是根据ObfTimes的值来进行多次混淆。遍历基本块,随机决定当前基本块是否需要修改,若ObfProbRate满足条件则调用addBogusFlow函数。
2.3 addBogusFlow函数
BasicBlock::iterator i1 = basicBlock->begin();
if(basicBlock->getFirstNonPHIOrDbgOrLifetime())
i1 = (BasicBlock::iterator)basicBlock->getFirstNonPHIOrDbgOrLifetime();
Twine *var;
var = new Twine("originalBB");
BasicBlock *originalBB = basicBlock->splitBasicBlock(i1, *var);
首先调用getFirstNonPHIOrDbgOrLifetime()函数获取本basicblock中第一个不是Phi、Dbg、Lifetime的指令的地址,然后调用splitBasicBlock函数。splitBasicBlock函数可根据上述指令的地址将一个basicblock一分为二(basicBlock和originalBB)。
Twine * var3 = new Twine("alteredBB");
BasicBlock *alteredBB = createAlteredBasicBlock(originalBB, *var3, &F);
使用createAlteredBasicBlock函数对originalBB进行复制,得到alteredBB。
alteredBB->getTerminator()->eraseFromParent();
basicBlock->getTerminator()->eraseFromParent();
现在有3个基本块basicBlock、originalBB 、alteredBB,需要清除basicBlock、alteredBB与父节点的关系。
Value * LHS = ConstantFP::get(Type::getFloatTy(F.getContext()), 1.0);
Value * RHS = ConstantFP::get(Type::getFloatTy(F.getContext()), 1.0);
Twine * var4 = new Twine("condition");
FCmpInst * condition = new FCmpInst(*basicBlock, FCmpInst::FCMP_TRUE , LHS, RHS, *var4);
BranchInst::Create(originalBB, alteredBB, (Value *)condition, basicBlock);
BranchInst::Create(originalBB, alteredBB);
对于基本块basicBlock创建一个条件,若为真则其跳转到originalBB,否则跳转到alteredBB。同时为alteredBB创建一条跳转到originalBB的指令(该跳转指令不会执行)。
BasicBlock::iterator i = originalBB->end();
Twine * var5 = new Twine("originalBBpart2");
BasicBlock * originalBBpart2 = originalBB->splitBasicBlock(--i , *var5);
originalBB->getTerminator()->eraseFromParent();
Twine * var6 = new Twine("condition2");
FCmpInst * condition2 = new FCmpInst(*originalBB, CmpInst::FCMP_TRUE , LHS, RHS, *var6);
BranchInst::Create(originalBBpart2, alteredBB, (Value *)condition2, originalBB);
获取originalBB最后一条指令的位置,调用splitBasicBlock将originalBB分为originalBB与originalBBpart2,并消除两者间关系。对于基本块originalBB创建一个条件,若为真则跳转到originalBBpart2,为假则跳转到alteredBB。
至此,执行完addBogusFlow函数后的基本块的关系图如下所示。
2.4 createAlteredBasicBlock函数
用于对复制得到的alteredBB进行变换。遍历alteredBB中的所有OpCode,若包含有Add、Sub、UDiv、SDiv、URem、SRem、Shl、LShr、AShr、And、Or、Xor以及FAdd、FSub、FMul、FDiv、FRem指令,则用随机生成一些指令来进行替换。
2.5 doF函数
将Module中所有恒真的判断用不透明谓词(y < 10 || x * (x + 1) % 2 == 0)进行替换。
Twine * varX = new Twine("x");
Twine * varY = new Twine("y");
Value * x1 =ConstantInt::get(Type::getInt32Ty(M.getContext()), 0, false);
Value * y1 =ConstantInt::get(Type::getInt32Ty(M.getContext()), 0, false);
GlobalVariable * x = new GlobalVariable(M,Type::getInt32Ty(M.getContext()), false,GlobalValue::CommonLinkage, (Constant * )x1,*varX);
GlobalVariable * y = new GlobalVariable(M,Type::getInt32Ty(M.getContext()), false,GlobalValue::CommonLinkage, (Constant * )y1,varY);
创建两个全局变量。
for(Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi){
for(Function::iterator fi = mi->begin(), fe = mi->end(); fi != fe; ++fi){
TerminatorInst * tbb= fi->getTerminator();
if(tbb->getOpcode() == Instruction::Br){
BranchInst * br = (BranchInst *)(tbb);
if(br->isConditional()){
FCmpInst * cond = (FCmpInst *)br->getCondition();
unsigned opcode = cond->getOpcode();
if(opcode == Instruction::FCmp){
if (cond->getPredicate() == FCmpInst::FCMP_TRUE){
DEBUG_WITH_TYPE("gen",
errs()<<"bcf: an always true predicate !\n");
toDelete.push_back(cond); // The condition
toEdit.push_back(tbb); // The branch using the condition
}
}
}
}
}
}
然后遍历模块中所有基本块,搜索出条件为真的语句。
最后用y < 10 || x * (x + 1) % 2 == 0替换。