简介
OLLVM(Obfuscator-LLVM)是基于LLVM(Low Level Virtual Machine)框架的一种代码混淆器。它主要用于对C/C++和汇编语言程序进行混淆,以增加代码的复杂性,提高代码的安全性和抵抗逆向工程的能力。
IR(Intermediate Representation)是指中间表示,是编译器在将源代码转化为目标代码的过程中使用的一种中间形式。它作为源代码和目标机器代码之间的一个抽象层,方便进行代码优化、分析和生成。
Module、Function、BasicBlock和Instruction是IR的四个主要部分,它们有不同的作用和层次。
- Module(模块)
Module是IR的最高层次,表示整个程序或库。它可以包含全局变量、函数定义和其他相关信息,并且提供了一个组织单元,用于表示源代码的不同模块或文件。Module可以包含多个Function。 - Function(函数)
Function是IR的第二层,表示程序中的函数。每个Function对应一个具体的源代码函数或方法。Function包含了函数的参数、局部变量、控制流信息以及函数体中的指令。一个Function通常由多个BasicBlock组成。 - BasicBlock(基本块)
BasicBlock是IR中的一个基本块,表示一段连续的中间代码指令序列。一个BasicBlock通常只有一条入口和一条出口,因此它只能被顺序执行或者通过跳转指令执行。BasicBlock通常用于表示条件语句、循环语句和其他控制流结构。 - Instruction(指令)
Instruction是IR中的最小单元,表示一条中间代码指令。Instruction通常执行一些基本操作,例如赋值、算术运算、逻辑运算和控制流指令等。Instruction之间通过数据依赖关系建立联系,用于指导代码优化和并行化。
BCF源码分析-WIP
//===- BogusControlFlow.cpp - BogusControlFlow Obfuscation pass-------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------------------===//
//
// This file implements BogusControlFlow's pass, inserting bogus control flow.
// It adds bogus flow to a given basic block this way:
//
// Before :
// entry
// |
// ______v______
// | Original |
// |_____________|
// |
// v
// return
//
// After :
// entry
// |
// ____v_____
// |condition*| (false)
// |__________|----+
// (true)| |
// | |
// ______v______ |
// +-->| Original* | |
// | |_____________| (true)
// | (false)| !-----------> return
// | ______v______ |
// | | Altered |<--!
// | |_____________|
// |__________|
//
// * The results of these terminator's branch's conditions are always true, but these predicates are
// opacificated. For this, we declare two global values: x and y, and replace the FCMP_TRUE
// predicate with (y < 10 || x * (x + 1) % 2 == 0) (this could be improved, as the global
// values give a hint on where are the opaque predicates)
//
// The altered bloc is a copy of the original's one with junk instructions added accordingly to the
// type of instructions we found in the bloc
//
// Each basic block of the function is choosen if a random number in the range [0,100] is smaller
// than the choosen probability rate. The default value is 30. This value can be modify using
// the option -boguscf-prob=[value]. Value must be an integer in the range [0, 100], otherwise
// the default value is taken. Exemple: -boguscf -boguscf-prob=60
//
// The pass can also be loop many times on a function, including on the basic blocks added in
// a previous loop. Be careful if you use a big probability number and choose to run the loop
// many times wich may cause the pass to run for a very long time. The default value is one loop,
// but you can change it with -boguscf-loop=[value]. Value must be an integer greater than 1,
// otherwise the default value is taken. Exemple: -boguscf -boguscf-loop=2
//
//
// Defined debug types:
// - "gen" : general informations
// - "opt" : concerning the given options (parameter)
// - "cfg" : printing the various function's cfg before transformation
// and after transformation if it has been modified, and all
// the functions at end of the pass, after doFinalization.
//
// To use them all, simply use the -debug option.
// To use only one of them, follow the pass' command by -debug-only=name.
// Exemple, -boguscf -debug-only=cfg
//
//
// Stats:
// The following statistics will be printed if you use
// the -stats command:
//
// a. Number of functions in this module
// b. Number of times we run on each function
// c. Initial number of basic blocks in this module
// d. Number of modified basic blocks
// e. Number of added basic blocks in this module
// f. Final number of basic blocks in this module
//
// file : lib/Transforms/Obfuscation/BogusControlFlow.cpp
// date : june 2012
// version: 1.0
// author : julie.michielin@gmail.com
// modifications: pjunod, Rinaldini Julien
// project: Obfuscator
// option : -boguscf
//
//===----------------------------------------------------------------------------------===//
#include "llvm/Transforms/Obfuscation/BogusControlFlow.h"
#include "llvm/Transforms/Obfuscation/Utils.h"
// Stats
#define DEBUG_TYPE "BogusControlFlow"
STATISTIC(NumFunction, "a. Number of functions in this module");
STATISTIC(NumTimesOnFunctions, "b. Number of times we run on each function");
STATISTIC(InitNumBasicBlocks, "c. Initial number of basic blocks in this module");
STATISTIC(NumModifiedBasicBlocks, "d. Number of modified basic blocks");
STATISTIC(NumAddedBasicBlocks, "e. Number of added basic blocks in this module");
STATISTIC(FinalNumBasicBlocks, "f. Final number of basic blocks in this module");
// Options for the pass
const int defaultObfRate = 30, defaultObfTime = 1;
static cl::opt<int>
ObfProbRate("bcf_prob", cl::desc("Choose the probability [%] each basic blocks will be obfuscated by the -bcf pass"), cl::value_desc("probability rate"), cl::init(defaultObfRate), cl::Optional);
static cl::opt<int>
ObfTimes("bcf_loop", cl::desc("Choose how many time the -bcf pass loop on a function"), cl::value_desc("number of times"), cl::init(defaultObfTime), cl::Optional);
namespace {
struct BogusControlFlow : public FunctionPass {
static char ID; // Pass identification
bool flag;
BogusControlFlow() : FunctionPass(ID) {}
BogusControlFlow(bool flag) : FunctionPass(ID) {this->flag = flag; BogusControlFlow();}
/* runOnFunction
*
* Overwrite FunctionPass method to apply the transformation
* to the function. See header for more details.
*/
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()
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);
}
/* addBogusFlow
*
* Add bogus flow to a given basic block, according to the header's description
*/
virtual void addBogusFlow(BasicBlock * basicBlock, Function &F){
// Split the block: first part with only the phi nodes and debug info and terminator
// created by splitBasicBlock. (-> No instruction)
// Second part with every instructions from the original block
// We do this way, so we don't have to adjust all the phi nodes, metadatas and so on
// for the first block. We have to let the phi nodes in the first part, because they
// actually are updated in the second part according to them.
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);
DEBUG_WITH_TYPE("gen", errs() << "bcf: First and original basic blocks: ok\n");
// Creating the altered basic block on which the first basicBlock will jump
Twine * var3 = new Twine("alteredBB");
BasicBlock *alteredBB = createAlteredBasicBlock(originalBB, *var3, &F);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Altered basic block: ok\n");
// Now that all the blocks are created,
// we modify the terminators to adjust the control flow.
alteredBB->getTerminator()->eraseFromParent();
basicBlock->getTerminator()->eraseFromParent();
DEBUG_WITH_TYPE("gen", errs() << "bcf: Terminator removed from the altered"
<<" and first basic blocks\n");
// Preparing a condition..
// For now, the condition is an always true comparaison between 2 float
// This will be complicated after the pass (in doFinalization())
Value * LHS = ConstantFP::get(Type::getFloatTy(F.getContext()), 1.0);
Value * RHS = ConstantFP::get(Type::getFloatTy(F.getContext()), 1.0);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Value LHS and RHS created\n");
// The always true condition. End of the first block
Twine * var4 = new Twine("condition");
FCmpInst * condition = new FCmpInst(*basicBlock, FCmpInst::FCMP_TRUE , LHS, RHS, *var4);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Always true condition created\n");
// Jump to the original basic block if the condition is true or
// to the altered block if false.
BranchInst::Create(originalBB, alteredBB, (Value *)condition, basicBlock);
DEBUG_WITH_TYPE("gen",
errs() << "bcf: Terminator instruction in first basic block: ok\n");
// The altered block loop back on the original one.
BranchInst::Create(originalBB, alteredBB);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Terminator instruction in altered block: ok\n");
// The end of the originalBB is modified to give the impression that sometimes
// it continues in the loop, and sometimes it return the desired value
// (of course it's always true, so it always use the original terminator..
// but this will be obfuscated too;) )
// iterate on instruction just before the terminator of the originalBB
BasicBlock::iterator i = originalBB->end();
// Split at this point (we only want the terminator in the second part)
Twine * var5 = new Twine("originalBBpart2");
BasicBlock * originalBBpart2 = originalBB->splitBasicBlock(--i , *var5);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Terminator part of the original basic block"
<< " is isolated\n");
// the first part go either on the return statement or on the begining
// of the altered block.. So we erase the terminator created when splitting.
originalBB->getTerminator()->eraseFromParent();
// We add at the end a new always true condition
Twine * var6 = new Twine("condition2");
FCmpInst * condition2 = new FCmpInst(*originalBB, CmpInst::FCMP_TRUE , LHS, RHS, *var6);
BranchInst::Create(originalBBpart2, alteredBB, (Value *)condition2, originalBB);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Terminator original basic block: ok\n");
DEBUG_WITH_TYPE("gen", errs() << "bcf: End of addBogusFlow().\n");
} // end of addBogusFlow()
/* createAlteredBasicBlock
*
* This function return a basic block similar to a given one.
* It's inserted just after the given basic block.
* The instructions are similar but junk instructions are added between
* the cloned one. The cloned instructions' phi nodes, metadatas, uses and
* debug locations are adjusted to fit in the cloned basic block and
* behave nicely.
*/
virtual BasicBlock* createAlteredBasicBlock(BasicBlock * basicBlock,
const Twine & Name = "gen", Function * F = 0){
// Useful to remap the informations concerning instructions.
ValueToValueMapTy VMap;
BasicBlock * alteredBB = llvm::CloneBasicBlock (basicBlock, VMap, Name, F);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Original basic block cloned\n");
// Remap operands.
BasicBlock::iterator ji = basicBlock->begin();
for (BasicBlock::iterator i = alteredBB->begin(), e = alteredBB->end() ; i != e; ++i){
// Loop over the operands of the instruction
for(User::op_iterator opi = i->op_begin (), ope = i->op_end(); opi != ope; ++opi){
// get the value for the operand
Value *v = MapValue(*opi, VMap, RF_None, 0);
if (v != 0){
*opi = v;
DEBUG_WITH_TYPE("gen", errs() << "bcf: Value's operand has been setted\n");
}
}
DEBUG_WITH_TYPE("gen", errs() << "bcf: Operands remapped\n");
// Remap phi nodes' incoming blocks.
if (PHINode *pn = dyn_cast<PHINode>(i)) {
for (unsigned j = 0, e = pn->getNumIncomingValues(); j != e; ++j) {
Value *v = MapValue(pn->getIncomingBlock(j), VMap, RF_None, 0);
if (v != 0){
pn->setIncomingBlock(j, cast<BasicBlock>(v));
}
}
}
DEBUG_WITH_TYPE("gen", errs() << "bcf: PHINodes remapped\n");
// Remap attached metadata.
SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
i->getAllMetadata(MDs);
DEBUG_WITH_TYPE("gen", errs() << "bcf: Metadatas remapped\n");
// important for compiling with DWARF, using option -g.
i->setDebugLoc(ji->getDebugLoc());
ji++;
DEBUG_WITH_TYPE("gen", errs() << "bcf: Debug information location setted\n");
} // The instructions' informations are now all correct
DEBUG_WITH_TYPE("gen", errs() << "bcf: The cloned basic block is now correct\n");
DEBUG_WITH_TYPE("gen",
errs() << "bcf: Starting to add junk code in the cloned bloc...\n");
// add random instruction in the middle of the bloc. This part can be improve
for (BasicBlock::iterator i = alteredBB->begin(), e = alteredBB->end() ; i != e; ++i){
// in the case we find binary operator, we modify slightly this part by randomly
// insert some instructions
if(i->isBinaryOp()){ // binary instructions
unsigned opcode = i->getOpcode();
BinaryOperator *op, *op1 = NULL;
Twine *var = new Twine("_");
// treat differently float or int
// Binary int
if(opcode == Instruction::Add || opcode == Instruction::Sub ||
opcode == Instruction::Mul || opcode == Instruction::UDiv ||
opcode == Instruction::SDiv || opcode == Instruction::URem ||
opcode == Instruction::SRem || opcode == Instruction::Shl ||
opcode == Instruction::LShr || opcode == Instruction::AShr ||
opcode == Instruction::And || opcode == Instruction::Or ||
opcode == Instruction::Xor){
for(int random = (int)llvm::cryptoutils->get_range(10); random < 10; ++random){
switch(llvm::cryptoutils->get_range(4)){ // to improve
case 0: //do nothing
break;
case 1: op = BinaryOperator::CreateNeg(i->getOperand(0),*var,&*i);
op1 = BinaryOperator::Create(Instruction::Add,op,
i->getOperand(1),"gen",&*i);
break;
case 2: op1 = BinaryOperator::Create(Instruction::Sub,
i->getOperand(0),
i->getOperand(1),*var,&*i);
op = BinaryOperator::Create(Instruction::Mul,op1,
i->getOperand(1),"gen",&*i);
break;
case 3: op = BinaryOperator::Create(Instruction::Shl,
i->getOperand(0),
i->getOperand(1),*var,&*i);
break;
}
}
}
// Binary float
if(opcode == Instruction::FAdd || opcode == Instruction::FSub ||
opcode == Instruction::FMul || opcode == Instruction::FDiv ||
opcode == Instruction::FRem){
for(int random = (int)llvm::cryptoutils->get_range(10); random < 10; ++random){
switch(llvm::cryptoutils->get_range(3)){ // can be improved
case 0: //do nothing
break;
case 1: op = BinaryOperator::CreateFNeg(i->getOperand(0),*var,&*i);
op1 = BinaryOperator::Create(Instruction::FAdd,op,
i->getOperand(1),"gen",&*i);
break;
case 2: op = BinaryOperator::Create(Instruction::FSub,
i->getOperand(0),
i->getOperand(1),*var,&*i);
op1 = BinaryOperator::Create(Instruction::FMul,op,
i->getOperand(1),"gen",&*i);
break;
}
}
}
if(opcode == Instruction::ICmp){ // Condition (with int)
ICmpInst *currentI = (ICmpInst*)(&i);
switch(llvm::cryptoutils->get_range(3)){ // must be improved
case 0: //do nothing
break;
case 1: currentI->swapOperands();
break;
case 2: // randomly change the predicate
switch(llvm::cryptoutils->get_range(10)){
case 0: currentI->setPredicate(ICmpInst::ICMP_EQ);
break; // equal
case 1: currentI->setPredicate(ICmpInst::ICMP_NE);
break; // not equal
case 2: currentI->setPredicate(ICmpInst::ICMP_UGT);
break; // unsigned greater than
case 3: currentI->setPredicate(ICmpInst::ICMP_UGE);
break; // unsigned greater or equal
case 4: currentI->setPredicate(ICmpInst::ICMP_ULT);
break; // unsigned less than
case 5: currentI->setPredicate(ICmpInst::ICMP_ULE);
break; // unsigned less or equal
case 6: currentI->setPredicate(ICmpInst::ICMP_SGT);
break; // signed greater than
case 7: currentI->setPredicate(ICmpInst::ICMP_SGE);
break; // signed greater or equal
case 8: currentI->setPredicate(ICmpInst::ICMP_SLT);
break; // signed less than
case 9: currentI->setPredicate(ICmpInst::ICMP_SLE);
break; // signed less or equal
}
break;
}
}
if(opcode == Instruction::FCmp){ // Conditions (with float)
FCmpInst *currentI = (FCmpInst*)(&i);
switch(llvm::cryptoutils->get_range(3)){ // must be improved
case 0: //do nothing
break;
case 1: currentI->swapOperands();
break;
case 2: // randomly change the predicate
switch(llvm::cryptoutils->get_range(10)){
case 0: currentI->setPredicate(FCmpInst::FCMP_OEQ);
break; // ordered and equal
case 1: currentI->setPredicate(FCmpInst::FCMP_ONE);
break; // ordered and operands are unequal
case 2: currentI->setPredicate(FCmpInst::FCMP_UGT);
break; // unordered or greater than
case 3: currentI->setPredicate(FCmpInst::FCMP_UGE);
break; // unordered, or greater than, or equal
case 4: currentI->setPredicate(FCmpInst::FCMP_ULT);
break; // unordered or less than
case 5: currentI->setPredicate(FCmpInst::FCMP_ULE);
break; // unordered, or less than, or equal
case 6: currentI->setPredicate(FCmpInst::FCMP_OGT);
break; // ordered and greater than
case 7: currentI->setPredicate(FCmpInst::FCMP_OGE);
break; // ordered and greater than or equal
case 8: currentI->setPredicate(FCmpInst::FCMP_OLT);
break; // ordered and less than
case 9: currentI->setPredicate(FCmpInst::FCMP_OLE);
break; // ordered or less than, or equal
}
break;
}
}
}
}
return alteredBB;
} // end of createAlteredBasicBlock()
/* doFinalization
*
* Overwrite FunctionPass method to apply the transformations to the whole module.
* This part obfuscate all the always true predicates of the module.
* More precisely, the condition which predicate is FCMP_TRUE.
* It also remove all the functions' basic blocks' and instructions' names.
*/
bool doF(Module &M){
// In this part we extract all always-true predicate and replace them with opaque predicate:
// For this, we declare two global values: x and y, and replace the FCMP_TRUE predicate with
// (y < 10 || x * (x + 1) % 2 == 0)
// A better way to obfuscate the predicates would be welcome.
// In the meantime we will erase the name of the basic blocks, the instructions
// and the functions.
DEBUG_WITH_TYPE("gen", errs()<<"bcf: Starting doFinalization...\n");
// The global values
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);
std::vector<Instruction*> toEdit, toDelete;
BinaryOperator *op,*op1 = NULL;
LoadInst * opX , * opY;
ICmpInst * condition, * condition2;
// Looking for the conditions and branches to transform
for(Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi){
for(Function::iterator fi = mi->begin(), fe = mi->end(); fi != fe; ++fi){
//fi->setName("");
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
}
}
}
}
/*
for (BasicBlock::iterator bi = fi->begin(), be = fi->end() ; bi != be; ++bi){
bi->setName(""); // setting the basic blocks' names
}
*/
}
}
// Replacing all the branches we found
for(std::vector<Instruction*>::iterator i =toEdit.begin();i!=toEdit.end();++i){
//if y < 10 || x*(x+1) % 2 == 0
opX = new LoadInst ((Value *)x, "", (*i));
opY = new LoadInst ((Value *)y, "", (*i));
op = BinaryOperator::Create(Instruction::Sub, (Value *)opX,
ConstantInt::get(Type::getInt32Ty(M.getContext()), 1,
false), "", (*i));
op1 = BinaryOperator::Create(Instruction::Mul, (Value *)opX, op, "", (*i));
op = BinaryOperator::Create(Instruction::URem, op1,
ConstantInt::get(Type::getInt32Ty(M.getContext()), 2,
false), "", (*i));
condition = new ICmpInst((*i), ICmpInst::ICMP_EQ, op,
ConstantInt::get(Type::getInt32Ty(M.getContext()), 0,
false));
condition2 = new ICmpInst((*i), ICmpInst::ICMP_SLT, opY,
ConstantInt::get(Type::getInt32Ty(M.getContext()), 10,
false));
op1 = BinaryOperator::Create(Instruction::Or, (Value *)condition,
(Value *)condition2, "", (*i));
BranchInst::Create(((BranchInst*)*i)->getSuccessor(0),
((BranchInst*)*i)->getSuccessor(1),(Value *) op1,
((BranchInst*)*i)->getParent());
DEBUG_WITH_TYPE("gen", errs() << "bcf: Erase branch instruction:"
<< *((BranchInst*)*i) << "\n");
(*i)->eraseFromParent(); // erase the branch
}
// Erase all the associated conditions we found
for(std::vector<Instruction*>::iterator i =toDelete.begin();i!=toDelete.end();++i){
DEBUG_WITH_TYPE("gen", errs() << "bcf: Erase condition instruction:"
<< *((Instruction*)*i)<< "\n");
(*i)->eraseFromParent();
}
// Only for debug
DEBUG_WITH_TYPE("cfg",
errs() << "bcf: End of the pass, here are the graphs after doFinalization\n");
for(Module::iterator mi = M.begin(), me = M.end(); mi != me; ++mi){
DEBUG_WITH_TYPE("cfg", errs() << "bcf: Function " << mi->getName() <<"\n");
DEBUG_WITH_TYPE("cfg", mi->viewCFG());
}
return true;
} // end of doFinalization
}; // end of struct BogusControlFlow : public FunctionPass
}
char BogusControlFlow::ID = 0;
static RegisterPass<BogusControlFlow> X("boguscf", "inserting bogus control flow");
Pass *llvm::createBogus() {
return new BogusControlFlow();
}
Pass *llvm::createBogus(bool flag) {
return new BogusControlFlow(flag);
}
FLA源码分析
//===- Flattening.cpp - Flattening Obfuscation pass------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the flattening pass
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Obfuscation/Flattening.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/CryptoUtils.h"
#define DEBUG_TYPE "flattening"
using namespace llvm;
// Stats
STATISTIC(Flattened, "Functions flattened");
namespace {
struct Flattening : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
bool flag;
Flattening() : FunctionPass(ID) {}
Flattening(bool flag) : FunctionPass(ID) { this->flag = flag; }
bool runOnFunction(Function &F);
bool flatten(Function *f);
};
}
char Flattening::ID = 0;
static RegisterPass<Flattening> X("flattening", "Call graph flattening");
Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); }
bool Flattening::runOnFunction(Function &F) {
Function *tmp = &F;
// Do we obfuscate
if (toObfuscate(flag, tmp, "fla")) {
if (flatten(tmp)) {
++Flattened;
}
}
return false;
}
bool Flattening::flatten(Function *f) {
vector<BasicBlock *> origBB;
BasicBlock *loopEntry;
BasicBlock *loopEnd;
LoadInst *load;
SwitchInst *switchI;
AllocaInst *switchVar;
// SCRAMBLER
char scrambling_key[16];
llvm::cryptoutils->get_bytes(scrambling_key, 16);
// END OF SCRAMBLER
// Lower switch
FunctionPass *lower = createLowerSwitchPass();
lower->runOnFunction(*f);
// Save all original BB
for (Function::iterator i = f->begin(); i != f->end(); ++i) {
BasicBlock *tmp = &*i;
origBB.push_back(tmp);
BasicBlock *bb = &*i;
if (isa<InvokeInst>(bb->getTerminator())) {
return false;
}
}
// Nothing to flatten
if (origBB.size() <= 1) {
return false;
}
// Remove first BB
origBB.erase(origBB.begin());
// Get a pointer on the first BB
Function::iterator tmp = f->begin(); //++tmp;
BasicBlock *insert = &*tmp;
// If main begin with an if
BranchInst *br = NULL;
if (isa<BranchInst>(insert->getTerminator())) {
br = cast<BranchInst>(insert->getTerminator());
}
if ((br != NULL && br->isConditional()) ||
insert->getTerminator()->getNumSuccessors() > 1) {
BasicBlock::iterator i = insert->end();
--i;
if (insert->size() > 1) {
--i;
}
BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
origBB.insert(origBB.begin(), tmpBB);
}
// Remove jump
insert->getTerminator()->eraseFromParent();
// Create switch variable and set as it
switchVar =
new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert);
new StoreInst(
ConstantInt::get(Type::getInt32Ty(f->getContext()),
llvm::cryptoutils->scramble32(0, scrambling_key)),
switchVar, insert);
// Create main loop
loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert);
loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert);
load = new LoadInst(switchVar, "switchVar", loopEntry);
// Move first BB on top
insert->moveBefore(loopEntry);
BranchInst::Create(loopEntry, insert);
// loopEnd jump to loopEntry
BranchInst::Create(loopEntry, loopEnd);
BasicBlock *swDefault =
BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
BranchInst::Create(loopEnd, swDefault);
// Create switch instruction itself and set condition
switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry);
switchI->setCondition(load);
// Remove branch jump from 1st BB and make a jump to the while
f->begin()->getTerminator()->eraseFromParent();
BranchInst::Create(loopEntry, &*f->begin());
// Put all BB in the switch
for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();
++b) {
BasicBlock *i = *b;
ConstantInt *numCase = NULL;
// Move the BB inside the switch (only visual, no code logic)
i->moveBefore(loopEnd);
// Add case to switch
numCase = cast<ConstantInt>(ConstantInt::get(
switchI->getCondition()->getType(),
llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
switchI->addCase(numCase, i);
}
// Recalculate switchVar
for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();
++b) {
BasicBlock *i = *b;
ConstantInt *numCase = NULL;
// Ret BB
if (i->getTerminator()->getNumSuccessors() == 0) {
continue;
}
// If it's a non-conditional jump
if (i->getTerminator()->getNumSuccessors() == 1) {
// Get successor and delete terminator
BasicBlock *succ = i->getTerminator()->getSuccessor(0);
i->getTerminator()->eraseFromParent();
// Get next case
numCase = switchI->findCaseDest(succ);
// If next case == default case (switchDefault)
if (numCase == NULL) {
numCase = cast<ConstantInt>(
ConstantInt::get(switchI->getCondition()->getType(),
llvm::cryptoutils->scramble32(
switchI->getNumCases() - 1, scrambling_key)));
}
// Update switchVar and jump to the end of loop
new StoreInst(numCase, load->getPointerOperand(), i);
BranchInst::Create(loopEnd, i);
continue;
}
// If it's a conditional jump
if (i->getTerminator()->getNumSuccessors() == 2) {
// Get next cases
ConstantInt *numCaseTrue =
switchI->findCaseDest(i->getTerminator()->getSuccessor(0));
ConstantInt *numCaseFalse =
switchI->findCaseDest(i->getTerminator()->getSuccessor(1));
// Check if next case == default case (switchDefault)
if (numCaseTrue == NULL) {
numCaseTrue = cast<ConstantInt>(
ConstantInt::get(switchI->getCondition()->getType(),
llvm::cryptoutils->scramble32(
switchI->getNumCases() - 1, scrambling_key)));
}
if (numCaseFalse == NULL) {
numCaseFalse = cast<ConstantInt>(
ConstantInt::get(switchI->getCondition()->getType(),
llvm::cryptoutils->scramble32(
switchI->getNumCases() - 1, scrambling_key)));
}
// Create a SelectInst
BranchInst *br = cast<BranchInst>(i->getTerminator());
SelectInst *sel =
SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "",
i->getTerminator());
// Erase terminator
i->getTerminator()->eraseFromParent();
// Update switchVar and jump to the end of loop
new StoreInst(sel, load->getPointerOperand(), i);
BranchInst::Create(loopEnd, i);
continue;
}
}
fixStack(f);
return true;
}
SUB源码分析
//===- Substitution.cpp - Substitution Obfuscation
// pass-------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements operators substitution's pass
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Obfuscation/Substitution.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Obfuscation/Utils.h"
#include "llvm/IR/Intrinsics.h"
#define DEBUG_TYPE "substitution"
#define NUMBER_ADD_SUBST 4
#define NUMBER_SUB_SUBST 3
#define NUMBER_AND_SUBST 2
#define NUMBER_OR_SUBST 2
#define NUMBER_XOR_SUBST 2
static cl::opt<int>
ObfTimes("sub_loop",
cl::desc("Choose how many time the -sub pass loops on a function"),
cl::value_desc("number of times"), cl::init(1), cl::Optional);
// Stats
STATISTIC(Add, "Add substitued");
STATISTIC(Sub, "Sub substitued");
// STATISTIC(Mul, "Mul substitued");
// STATISTIC(Div, "Div substitued");
// STATISTIC(Rem, "Rem substitued");
// STATISTIC(Shi, "Shift substitued");
STATISTIC(And, "And substitued");
STATISTIC(Or, "Or substitued");
STATISTIC(Xor, "Xor substitued");
namespace {
struct Substitution : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
void (Substitution::*funcAdd[NUMBER_ADD_SUBST])(BinaryOperator *bo);
void (Substitution::*funcSub[NUMBER_SUB_SUBST])(BinaryOperator *bo);
void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo);
void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo);
void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo);
bool flag;
Substitution() : FunctionPass(ID) {}
Substitution(bool flag) : FunctionPass(ID) {
this->flag = flag;
funcAdd[0] = &Substitution::addNeg;
funcAdd[1] = &Substitution::addDoubleNeg;
funcAdd[2] = &Substitution::addRand;
funcAdd[3] = &Substitution::addRand2;
funcSub[0] = &Substitution::subNeg;
funcSub[1] = &Substitution::subRand;
funcSub[2] = &Substitution::subRand2;
funcAnd[0] = &Substitution::andSubstitution;
funcAnd[1] = &Substitution::andSubstitutionRand;
funcOr[0] = &Substitution::orSubstitution;
funcOr[1] = &Substitution::orSubstitutionRand;
funcXor[0] = &Substitution::xorSubstitution;
funcXor[1] = &Substitution::xorSubstitutionRand;
}
bool runOnFunction(Function &F);
bool substitute(Function *f);
void addNeg(BinaryOperator *bo);
void addDoubleNeg(BinaryOperator *bo);
void addRand(BinaryOperator *bo);
void addRand2(BinaryOperator *bo);
void subNeg(BinaryOperator *bo);
void subRand(BinaryOperator *bo);
void subRand2(BinaryOperator *bo);
void andSubstitution(BinaryOperator *bo);
void andSubstitutionRand(BinaryOperator *bo);
void orSubstitution(BinaryOperator *bo);
void orSubstitutionRand(BinaryOperator *bo);
void xorSubstitution(BinaryOperator *bo);
void xorSubstitutionRand(BinaryOperator *bo);
};
}
char Substitution::ID = 0;
static RegisterPass<Substitution> X("substitution", "operators substitution");
Pass *llvm::createSubstitution(bool flag) { return new Substitution(flag); }
bool Substitution::runOnFunction(Function &F) {
// Check if the percentage is correct
if (ObfTimes <= 0) {
errs()<<"Substitution application number -sub_loop=x must be x > 0";
return false;
}
Function *tmp = &F;
// Do we obfuscate
if (toObfuscate(flag, tmp, "sub")) {
substitute(tmp);
return true;
}
return false;
}
bool Substitution::substitute(Function *f) {
Function *tmp = f;
// Loop for the number of time we run the pass on the function
int times = ObfTimes;
do {
for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) {
for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) {
if (inst->isBinaryOp()) {
switch (inst->getOpcode()) {
case BinaryOperator::Add:
// case BinaryOperator::FAdd:
// Substitute with random add operation
(this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(
cast<BinaryOperator>(inst));
++Add;
break;
case BinaryOperator::Sub:
// case BinaryOperator::FSub:
// Substitute with random sub operation
(this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(
cast<BinaryOperator>(inst));
++Sub;
break;
case BinaryOperator::Mul:
case BinaryOperator::FMul:
//++Mul;
break;
case BinaryOperator::UDiv:
case BinaryOperator::SDiv:
case BinaryOperator::FDiv:
//++Div;
break;
case BinaryOperator::URem:
case BinaryOperator::SRem:
case BinaryOperator::FRem:
//++Rem;
break;
case Instruction::Shl:
//++Shi;
break;
case Instruction::LShr:
//++Shi;
break;
case Instruction::AShr:
//++Shi;
break;
case Instruction::And:
(this->*
funcAnd[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
++And;
break;
case Instruction::Or:
(this->*
funcOr[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
++Or;
break;
case Instruction::Xor:
(this->*
funcXor[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
++Xor;
break;
default:
break;
} // End switch
} // End isBinaryOp
} // End for basickblock
} // End for Function
} while (--times > 0); // for times
return false;
}
// Implementation of a = b - (-c)
void Substitution::addNeg(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create sub
if (bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}/* else {
op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FSub, bo->getOperand(0), op, "",
bo);
}*/
}
// Implementation of a = -(-b + (-c))
void Substitution::addDoubleNeg(BinaryOperator *bo) {
BinaryOperator *op, *op2 = NULL;
if (bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, op2, "", bo);
op = BinaryOperator::CreateNeg(op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
op = BinaryOperator::CreateFNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FAdd, op, op2, "", bo);
op = BinaryOperator::CreateFNeg(op, "", bo);
}
bo->replaceAllUsesWith(op);
}
// Implementation of r = rand (); a = b + r; a = a + c; a = a - r
void Substitution::addRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Add) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of r = rand (); a = b - r; a = a + b; a = a + r
void Substitution::addRand2(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Add) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Add, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of a = b + (-c)
void Substitution::subNeg(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op, "",
bo);
}
bo->replaceAllUsesWith(op);
}
// Implementation of r = rand (); a = b + r; a = a - c; a = a - r
void Substitution::subRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Add, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Sub, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FAdd,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,co,"",bo);
} */
}
// Implementation of r = rand (); a = b - r; a = a - c; a = a + r
void Substitution::subRand2(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if (bo->getOpcode() == Instruction::Sub) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
op =
BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), co, "", bo);
op =
BinaryOperator::Create(Instruction::Sub, op, bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, co, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
bo->replaceAllUsesWith(op);
}
/* else {
Type *ty = bo->getType();
ConstantFP *co =
(ConstantFP*)ConstantFP::get(ty,(float)llvm::cryptoutils->get_uint64_t());
op = BinaryOperator::Create(Instruction::FSub,bo->getOperand(0),co,"",bo);
op = BinaryOperator::Create(Instruction::FSub,op,bo->getOperand(1),"",bo);
op = BinaryOperator::Create(Instruction::FAdd,op,co,"",bo);
} */
}
// Implementation of a = b & c => a = (b^~c)& b
void Substitution::andSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create NOT on second operand => ~c
op = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// Create XOR => (b^~c)
BinaryOperator *op1 =
BinaryOperator::Create(Instruction::Xor, bo->getOperand(0), op, "", bo);
// Create AND => (b^~c) & b
op = BinaryOperator::Create(Instruction::And, op1, bo->getOperand(0), "", bo);
bo->replaceAllUsesWith(op);
}
// Implementation of a = a && b <=> !(!a | !b) && (r | !r)
void Substitution::andSubstitutionRand(BinaryOperator *bo) {
// Copy of the BinaryOperator type to create the random number with the
// same type of the operands
Type *ty = bo->getType();
// r (Random number)
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !b
BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !r
BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo);
// (!a | !b)
BinaryOperator *opa =
BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// (r | !r)
opr = BinaryOperator::Create(Instruction::Or, co, opr, "", bo);
// !(!a | !b)
op = BinaryOperator::CreateNot(opa, "", bo);
// !(!a | !b) && (r | !r)
op = BinaryOperator::Create(Instruction::And, op, opr, "", bo);
// We replace all the old AND operators with the new one transformed
bo->replaceAllUsesWith(op);
}
// Implementation of a = b | c => a = (b & c) | (b ^ c)
void Substitution::orSubstitutionRand(BinaryOperator *bo) {
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
BinaryOperator *op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !b
BinaryOperator *op1 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !r
BinaryOperator *op2 = BinaryOperator::CreateNot(co, "", bo);
// !a && r
BinaryOperator *op3 =
BinaryOperator::Create(Instruction::And, op, co, "", bo);
// a && !r
BinaryOperator *op4 =
BinaryOperator::Create(Instruction::And, bo->getOperand(0), op2, "", bo);
// !b && r
BinaryOperator *op5 =
BinaryOperator::Create(Instruction::And, op1, co, "", bo);
// b && !r
BinaryOperator *op6 =
BinaryOperator::Create(Instruction::And, bo->getOperand(1), op2, "", bo);
// (!a && r) || (a && !r)
op3 = BinaryOperator::Create(Instruction::Or, op3, op4, "", bo);
// (!b && r) ||(b && !r)
op4 = BinaryOperator::Create(Instruction::Or, op5, op6, "", bo);
// (!a && r) || (a && !r) ^ (!b && r) ||(b && !r)
op5 = BinaryOperator::Create(Instruction::Xor, op3, op4, "", bo);
// !a || !b
op3 = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// !(!a || !b)
op3 = BinaryOperator::CreateNot(op3, "", bo);
// r || !r
op4 = BinaryOperator::Create(Instruction::Or, co, op2, "", bo);
// !(!a || !b) && (r || !r)
op4 = BinaryOperator::Create(Instruction::And, op3, op4, "", bo);
// [(!a && r) || (a && !r) ^ (!b && r) ||(b && !r) ] || [!(!a || !b) && (r ||
// !r)]
op = BinaryOperator::Create(Instruction::Or, op5, op4, "", bo);
bo->replaceAllUsesWith(op);
}
void Substitution::orSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Creating first operand (b & c)
op = BinaryOperator::Create(Instruction::And, bo->getOperand(0),
bo->getOperand(1), "", bo);
// Creating second operand (b ^ c)
BinaryOperator *op1 = BinaryOperator::Create(
Instruction::Xor, bo->getOperand(0), bo->getOperand(1), "", bo);
// final op
op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
bo->replaceAllUsesWith(op);
}
// Implementation of a = a ~ b => a = (!a && b) || (a && !b)
void Substitution::xorSubstitution(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create NOT on first operand
op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo); // !a
// Create AND
op = BinaryOperator::Create(Instruction::And, bo->getOperand(1), op, "",
bo); // !a && b
// Create NOT on second operand
BinaryOperator *op1 =
BinaryOperator::CreateNot(bo->getOperand(1), "", bo); // !b
// Create AND
op1 = BinaryOperator::Create(Instruction::And, bo->getOperand(0), op1, "",
bo); // a && !b
// Create OR
op = BinaryOperator::Create(Instruction::Or, op, op1, "",
bo); // (!a && b) || (a && !b)
bo->replaceAllUsesWith(op);
}
// implementation of a = a ^ b <=> (a ^ r) ^ (b ^ r) <=> (!a && r || a && !r) ^
// (!b && r || b && !r)
// note : r is a random number
void Substitution::xorSubstitutionRand(BinaryOperator *bo) {
BinaryOperator *op = NULL;
Type *ty = bo->getType();
ConstantInt *co =
(ConstantInt *)ConstantInt::get(ty, llvm::cryptoutils->get_uint64_t());
// !a
op = BinaryOperator::CreateNot(bo->getOperand(0), "", bo);
// !a && r
op = BinaryOperator::Create(Instruction::And, co, op, "", bo);
// !r
BinaryOperator *opr = BinaryOperator::CreateNot(co, "", bo);
// a && !r
BinaryOperator *op1 =
BinaryOperator::Create(Instruction::And, bo->getOperand(0), opr, "", bo);
// !b
BinaryOperator *op2 = BinaryOperator::CreateNot(bo->getOperand(1), "", bo);
// !b && r
op2 = BinaryOperator::Create(Instruction::And, op2, co, "", bo);
// b && !r
BinaryOperator *op3 =
BinaryOperator::Create(Instruction::And, bo->getOperand(1), opr, "", bo);
// (!a && r) || (a && !r)
op = BinaryOperator::Create(Instruction::Or, op, op1, "", bo);
// (!b && r) || (b && !r)
op1 = BinaryOperator::Create(Instruction::Or, op2, op3, "", bo);
// (!a && r) || (a && !r) ^ (!b && r) || (b && !r)
op = BinaryOperator::Create(Instruction::Xor, op, op1, "", bo);
bo->replaceAllUsesWith(op);
}