首页
社区
课程
招聘
OLLVM混淆源码解读
发表于: 2024-6-16 16:58 24292

OLLVM混淆源码解读

2024-6-16 16:58
24292

IR(intermediate representation)是前端语言生成的中间代码表示,也是Pass操作的对象,它主要包含四个部分:

它们之间的关系如下图所示:

检查是否能够进行Substitution混淆,混淆的具体操作主要通过调用substitute函数进行的。

整个函数的功能主要是根据运算指令中的操作符进行相应的混淆操作,由于同一指令的混淆操作有很多种,因此通过llvm::cryptoutils->get_range获取随机数来指定某种混淆操作。

由于这些运算混淆都大同小异,所以接下来以一个例子来进行Substitution混淆的介绍。

主要是创建一个取反指令和一个整型减法指令来替换原有的指令。

一开始我不理解这些操作具体体现是什么,于是为了探究这些代码对IR进行了什么操作,因此在源码上进行打印调试,打印更改前后的IR。主要修改如下:

打印结果如下:

从结果上看,Create***等指令创建函数会影响后面的IR代码,即后续代码会进行相应的调整以保证IR代码的正确性,至于其具体过程,本篇博客不进行介绍。replaceAllUsesWith函数并不是真正的将源指令替换或删除,仅仅只是让后续IR代码中对源指令的结果的引用转变成对新指令的结果的引用,也就是说,源指令对后续的操作无任何作用,这样之后的优化应该会删除这种无效IR代码(如果指定了优化等级的话)。

至于其他的运算混淆,通过这个例子可以知其一而知其二。

进行一些类似的操作,然后是调用split函数。

这部分主要是遍所有基本块,如果基本块中只含有一条指令或者含有PHI节点,则不进行基本块拆分,同时调整分割次数以防止分割次数大于基本块中的指令数。接下来就是生成分割点,具体操作为对1~size-1的有序vetor打乱顺序,然后对前splitN个进行从小到大的排序,这样做的目的一是随机分割,二是重排序以防止分割不会出错。最后,调整分割点,调用splitBasicBlock进行分割。

先来看看PHI节点是什么。

所有LLVM指令都以静态单一赋值(SSA)形式表示。从本质上讲,这意味着任何变量只能分配给一次。因此就存在如下情况的问题:

假设v的值小于10,变量a就会被赋值为2,但是a已经被赋值了一次,由于SSA性质的约束,不能继续给a赋值了。为了解决这一问题,LLVM中引入了PHI节点(PHI Node),用于处理基本块之间的分支和合并。当一个基本块有多个前驱基本块时,PHI节点可以用来表示从不同的前驱基本块中接收的值,这在处理分支和合并的情况下非常有用。

上述代码就会被转换成:

if分支里面的赋值被转换成另一个变量,b的赋值也就在两个变量之间选择,通过添加一个PHI Node,让它来决定选择哪个变量赋值给b

以指令I为分割点,所有在分割点之前的指令保留在原来的基本快中,分割点处的指令以及之后的指令保留到新的基本块中,并且在原来的基本块后面增加跳转到新的基本块的br指令。之后是修正新基本块的后继基本块(同样也是分割之前的基本块的后继基本块)中的PHINode,具体操作为替换PHINode的前驱基本块(即分割之前的基本块)为新的基本块。

runOnFunction函数没啥好看的,直接看重点:flatten函数,将该函数分为以下几块进行讲解。(这一部分的理解可以参考Obfuscator-llvm源码分析 - 知乎 (zhihu.com)中的CFG图)

首先弄了一个随机数,这个不需要着重分析。

然后是创建LowerSwitchPass并执行该Pass

LowerSwitchPass的作用是将函数中的switch指令转换成一系列连续的if-then指令。具体的操作我没仔细看,也不打算深究。

接下来将函数f的所有基本块存放一份到向量origBB中,同时检查基本块中的终止指令,如果终止指令是Invoke指令,则对整个函数f不进行平坦化混淆。如果函数f的基本块数量<1也不进行平坦化混淆。最后是将函数f的第一个基本块从向量origBB中删除。

接下来引入3个问题。

第一个问题:什么是Terminator?

LLVMIR中,每个基本块必须以Terminator指令结尾,它标志着基本块的结束,用于控制接下来代码流进入到哪一个基本块中。Terminator指令,它可以是分支指令(如BranchInst)、返回指令(如ReturnInst)或者抛出异常的指令(如InvokeInst)等。

第二个问题:什么是InvokeInst?

InvokeInst是一种特殊的调用指令,用于调用有异常处理的函数。与普通的CallInst不同,如果函数调用期间抛出异常,则控制流会转移到指定的异常处理代码中,而不是继续执行后续的指令。InvokeInst指令,这个指令有两个后继,但是一个是正常的基本块处,另一个是跳转到unwind相关的逻辑中(异常处理),这个unwind基本块的开头必须为LandingPadInst,且只能通过InvokeInst指令来到达。

第三个问题:为什么基本块中含有InvokeInst就对所在函数不进行平坦化处理?

由于unwind基本块只能通过InvokeInst指令来到达。所以当LandingPadInst被插入到SwitchInst中去的时候,由于不是通过InvokeInst到达的,所以会报错。然而对所在函数不进行平坦化,感觉应该不太妥,对于这部分的优化可以参考OLLVM控制流平坦化的改进 - 知乎 (zhihu.com)

对第一个基本块进行单独处理。

具体而言,如果该基本块的后续基本块有多个,则进行基本块拆分,将拆分出的新的基本块插入到origBB中的第一个基本块之前。基本块拆分是为了保证第一个基本块只有一个后继基本块,以便后续跳转到loopEntry基本块中。最后删除第一个基本块中的末尾指令(删除到后继基本块的跳转指令,后续会添加到loopEntry基本块的跳转)。

构建一个循环switch-case的框架,建立基本块之间的跳转连接。

具体来说是,在函数f第一个基本块(拆分后)的末尾创建switchVar路由变量并赋予随机值。接着创建loopEntryloopEndswDefault基本块。然后在loopEntry基本块的末尾加载switchVar路由变量,之后又在loopEntry基本块的末尾创建SwitchInst指令,设置默认分支为swDefault基本块,设置case分支数量为0,最后设置SwitchInst指令的路由变量为load指令加载的switchVar。其余的BranchInst则是建立基本块之间的跳转。

此时CFG图如下:

origBB中所有的基本块按照case索引值加入到switch-case分支中。

看完整个Flattening源码后,我还在想源码中并没有通过设置switchVar来确保代码流在第一个基本块能够正确进入到原本的后续基本块中。后面我反复阅读源码后才发现,其实它们之间的跳转关系在这里就确定了!

注意看!!!初始switchVar的值为:

origBB中的第一个基本块的case索引值为:

此时switchI->getNumCases()的值就是0,这么一来,初始switchVar的值恰好指向下一个正确的基本块。

此时CFG图如下:

根据基本块的后继基本块数量,决定是否在基本块中添加更新switchVar(路由变量)的指令,使代码流能够进入正确的基本块中。

将基本块分为三种类型进行处理:

此时CFG图如下:

优化函数中的堆栈分配

对应具体代码如下:

这个函数处理了两种类型的指令:

PHI 指令

PHI 指令我们前面介绍过。因为PHI指令是基于前驱基本块的指令,前驱基本块被打乱了,PHI指令会出现错误,因此需要对PHI指令进行修复。

含有逃逸变量的指令

逃逸变量指的是在当前基本块中被定义,在其他的基本块中被引用了的变量。这类逃逸变量在编译(LLVM IR->目标平台机器代码)时会出现分不清定义和引用顺序的问题,因此也需要进行修复。

DemoteRegToStack函数用于将存储指令结果值的虚拟寄存器替换为堆栈上的局部变量。具体而言,首先创建Alloca指令,插入到函数的入口基本块中,然后如果该指令是Invoke指令,则进行基本块分割,然后对于使用逃逸变量的基本块,采用Load指令从堆栈中加载变量的值,最后创建Store将逃逸变量的值存储到堆栈中。

DemotePHIToStack函数用于将存储PHI节点的结果值的虚拟寄存器替换为堆栈上的局部变量。具体而言是创建Alloca指令,插入到函数的入口基本块中,对于PHI节点的每一个前驱基本块,插入一个Store指令,将前驱基本块传递过来的值存储到堆栈中。之后在PHI节点所在的位置插入一个Load指令,将之前存储在堆栈中的值加载出来。

简而言之,DemotexxxToStack函数就是使用AllocaStoreLoad指令来代替这些需要待修复的指令。

runOnFunction函数入手看:

这部分主要是调用bogus函数进行虚假控制流混淆,然后调用doF函数替换在bogus函数中创建的永真条件跳转指令。我们先来看bogus函数然后再看doF函数。

外面一层while循环是循环虚假控制流混淆次数,对于每次混淆,先将函数的所有基本块加入到basicBlocks中,然后内层while循环遍历每个基本块,生成对应的混淆概率,如果满足预设混淆概率,就调用addBogusFlow函数进行混淆。

首先是获取分割点,然后对要混淆的基本块进行基本块分割,新的基本块的名字为originalBB

此时,CFG的情况如下:

然后是通过createAlteredBasicBlock函数(这个函数主要是根据传入的基本块fork出新的基本块,然后进行修正和垃圾指令填充)创建一个名为alteredBB基本块,删除alteredBBbasicBlock末尾的分支指令。

此时,CFG的情况如下:

接下来是创建了一个永真的Fcmp指令(因为1.0 == 1.0),并以该指令为条件码创建条件跳转指令,都插入到basicBlock的末尾,如果为True,跳转到originalBB,否则跳转到alteredBB。之后创建从alteredBB跳转到originalBB的跳转指令。

此时,CFG的情况如下:

最后,以originalBB的末尾跳转指令分割originalBB,新的基本块名为originalBBpart2,删除originalBB末尾的跳转指令(跳转到originalBBpart2),然后创建一个永真的Fcmp指令,并以该指令为条件码创建条件跳转指令,都插入到originalBB的末尾,如果为True,跳转到originalBBpart2,否则跳转到alteredBB

此时,CFG的情况如下:

首先调用CloneBasicBlock函数从basicBlock中克隆alteredBB,这个basicBlock是待混淆的基本块通过splitBasicBlock函数分割出来的新的基本块。

然后是修复alteredBB,主要是重映射指令中的操作数和PHINode的前驱基本块。

最后是往alteredBB中添加垃圾指令。

首先是创建两个全局变量x,y,初始值为0。

然后是遍历指令,将永真条件跳转指令加入到toEdit中,以及将对应的永真比较指令加入到toDelete中。

接下来是遍历toEdit中存放的永真条件跳转指令,创建条件码x*(x-1)%2 == 0 || y < 10,以该条件码创建条件跳转分支,然后删除之前的永真条件跳转指令。最后删除toDelete中存放的永真比较指令。

参考:

LLVM Concepts — llvmpy 0.9.0 documentation(phi node)

LLVM API 官方文档

Obfuscator-llvm源码分析 - 知乎 (zhihu.com)(有详细的CFG图)

[原创]基于LLVM Pass实现控制流平坦化-软件逆向-看雪-安全社区|安全招聘|kanxue.com(flatten混淆)

OLLVM控制流平坦化的改进 - 知乎 (zhihu.com)(flatten混淆)

[原创]OLLVM控制流平坦化之fixStack解析-软件逆向-看雪-安全社区|安全招聘|kanxue.com(fixStack函数)

https://bbs.kanxue.com/thread-266201.htm(BogusControlFlow混淆)

bool Substitution::runOnFunction(Function &F) {
    // 检查sub混淆次数
    if (ObfTimes <= 0) {
        errs()<<"Substitution application number -sub_loop=x must be x > 0";
        return false;
    }
    Function *tmp = &F;
    // 先通过toObfuscate函数检查是否需要进行混淆
    if (toObfuscate(flag, tmp, "sub")) {
        //混淆的具体操作
        substitute(tmp);
        return true;
    }
    return false;
}
bool Substitution::runOnFunction(Function &F) {
    // 检查sub混淆次数
    if (ObfTimes <= 0) {
        errs()<<"Substitution application number -sub_loop=x must be x > 0";
        return false;
    }
    Function *tmp = &F;
    // 先通过toObfuscate函数检查是否需要进行混淆
    if (toObfuscate(flag, tmp, "sub")) {
        //混淆的具体操作
        substitute(tmp);
        return true;
    }
    return false;
}
bool Substitution::substitute(Function *f) {
    Function *tmp = f;
    // 混淆次数
    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()) {
                    //获取指令的操作码进行case判断
                    switch (inst->getOpcode()) {
                        case BinaryOperator::Add:
                            // 随机选择add混淆中的一个方案
                            (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(
                                cast<BinaryOperator>(inst));
                            ++Add;
                            break;
                        case BinaryOperator::Sub:
                            // 随机选择sub混淆中的一个方案
                            (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(
                                cast<BinaryOperator>(inst));
                            ++Sub;
                            break;
                        ...
                    }              // End switch
                }                // End isBinaryOp
            }                  // End for basickblock
        }                    // End for Function
    } while (--times > 0); // for times
    return false;
}
bool Substitution::substitute(Function *f) {
    Function *tmp = f;
    // 混淆次数
    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()) {
                    //获取指令的操作码进行case判断
                    switch (inst->getOpcode()) {
                        case BinaryOperator::Add:
                            // 随机选择add混淆中的一个方案
                            (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(
                                cast<BinaryOperator>(inst));
                            ++Add;
                            break;
                        case BinaryOperator::Sub:
                            // 随机选择sub混淆中的一个方案
                            (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(
                                cast<BinaryOperator>(inst));
                            ++Sub;
                            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) {
    //创建一个取反指令,生成bo指令中第二个操作数的负数,插入到bo指令的前面,返回创建的指令
    op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
    //创建一个sub指令,第一个操作数是bo指令中的第一个操作数,第二个操作数是刚才生成的op,然后插入到bo指令的前面,返回创建的指令
    op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
    //用op指令来替换原来的bo指令
    bo->replaceAllUsesWith(op);
  }
}
// Implementation of a = b - (-c)
void Substitution::addNeg(BinaryOperator *bo) {
  BinaryOperator *op = NULL;
  // Create sub
  if (bo->getOpcode() == Instruction::Add) {
    //创建一个取反指令,生成bo指令中第二个操作数的负数,插入到bo指令的前面,返回创建的指令
    op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
    //创建一个sub指令,第一个操作数是bo指令中的第一个操作数,第二个操作数是刚才生成的op,然后插入到bo指令的前面,返回创建的指令
    op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
    //用op指令来替换原来的bo指令
    bo->replaceAllUsesWith(op);
  }
}
//打印基本块中的指令
void printBasicBlockInfo(BasicBlock* bb){
    for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst){
        inst->print(errs());
        errs() << "\n";
    }
}
 
void Substitution::addNeg(BinaryOperator *bo) {
    BinaryOperator *op = NULL;
 
    if (bo->getOpcode() == Instruction::Add) {
        //新增
        //current instruction
        errs() << "current BinaryOperator:";
        bo->print(errs());
        errs() << "\n";
        //get BasicBlock that current instruction located
        BasicBlock* bb = bo->getParent();
        //print Instruction in BasicBlock before CreateNeg
        errs() << "BasicBlock before CreateNeg: " << "\n";
        printBasicBlockInfo(bb);
 
        op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
         
        //新增
        //print Instruction in BasicBlock after CreateNeg and before Create
        errs() << "BasicBlock after CreateNeg and before Create: " << "\n";
        printBasicBlockInfo(bb);
 
        op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
 
        //新增
        //print Instruction in BasicBlock after Create and before replaceAllUsesWith
        errs() << "BasicBlock after Create and before replaceAllUsesWith: " << "\n";
        printBasicBlockInfo(bb);
 
        bo->replaceAllUsesWith(op);
 
        //新增
        //print Instruction in BasicBlock after replaceAllUsesWith
        errs() << "BasicBlock after replaceAllUsesWith: " << "\n";
        printBasicBlockInfo(bb);
    }
}
//打印基本块中的指令
void printBasicBlockInfo(BasicBlock* bb){
    for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst){
        inst->print(errs());
        errs() << "\n";
    }
}
 
void Substitution::addNeg(BinaryOperator *bo) {
    BinaryOperator *op = NULL;
 
    if (bo->getOpcode() == Instruction::Add) {
        //新增
        //current instruction
        errs() << "current BinaryOperator:";
        bo->print(errs());
        errs() << "\n";
        //get BasicBlock that current instruction located
        BasicBlock* bb = bo->getParent();
        //print Instruction in BasicBlock before CreateNeg
        errs() << "BasicBlock before CreateNeg: " << "\n";
        printBasicBlockInfo(bb);
 
        op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
         
        //新增
        //print Instruction in BasicBlock after CreateNeg and before Create
        errs() << "BasicBlock after CreateNeg and before Create: " << "\n";
        printBasicBlockInfo(bb);
 
        op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo);
 
        //新增
        //print Instruction in BasicBlock after Create and before replaceAllUsesWith
        errs() << "BasicBlock after Create and before replaceAllUsesWith: " << "\n";
        printBasicBlockInfo(bb);
 
        bo->replaceAllUsesWith(op);
 
        //新增
        //print Instruction in BasicBlock after replaceAllUsesWith
        errs() << "BasicBlock after replaceAllUsesWith: " << "\n";
        printBasicBlockInfo(bb);
    }
}
current Function: main//混淆操作
current BinaryOperator: %7 = add nsw i32 %5, %6 //在substitute函数中被选中要进行sub混淆的指令
BasicBlock before CreateNeg:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = add nsw i32 %5, %6
  store i32 %7, i32* %2, align 4
  ret i32 0
BasicBlock after CreateNeg and before Create:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4 // a
  store i32 1, i32* %3, align 4 // b
  store i32 2, i32* %4, align 4 // c
  %5 = load i32, i32* %3, align 4 // %5 = b
  %6 = load i32, i32* %4, align 4 // %6 = c
  %7 = sub i32 0, %6// CreateNeg新增指令,对源指令中第二个操作数(c)进行取反指令
  %8 = add nsw i32 %5, %6 // 源指令,%7变成%8
  store i32 %8, i32* %2, align 4 // %7变成%8
  ret i32 0
BasicBlock after Create and before replaceAllUsesWith:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = sub i32 0, %6 // CreateNeg新增指令
  %8 = sub i32 %5, %7 // Create新增指令,源指令中第一个操作数(b)与CreateNeg新增指令的结果相加
  %9 = add nsw i32 %5, %6 // 源指令, %8变成%9
  store i32 %9, i32* %2, align 4 // %8变成%9
  ret i32 0
BasicBlock after replaceAllUsesWith:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = sub i32 0, %6
  %8 = sub i32 %5, %7
  %9 = add nsw i32 %5, %6
  store i32 %8, i32* %2, align 4 // 这里发生更改,原本存储%9 (b+c),先在存储%8 (b-(-c))
  ret i32 0
current Function: main//混淆操作
current BinaryOperator: %7 = add nsw i32 %5, %6 //在substitute函数中被选中要进行sub混淆的指令
BasicBlock before CreateNeg:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = add nsw i32 %5, %6
  store i32 %7, i32* %2, align 4
  ret i32 0
BasicBlock after CreateNeg and before Create:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4 // a
  store i32 1, i32* %3, align 4 // b
  store i32 2, i32* %4, align 4 // c
  %5 = load i32, i32* %3, align 4 // %5 = b
  %6 = load i32, i32* %4, align 4 // %6 = c
  %7 = sub i32 0, %6// CreateNeg新增指令,对源指令中第二个操作数(c)进行取反指令
  %8 = add nsw i32 %5, %6 // 源指令,%7变成%8
  store i32 %8, i32* %2, align 4 // %7变成%8
  ret i32 0
BasicBlock after Create and before replaceAllUsesWith:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = sub i32 0, %6 // CreateNeg新增指令
  %8 = sub i32 %5, %7 // Create新增指令,源指令中第一个操作数(b)与CreateNeg新增指令的结果相加
  %9 = add nsw i32 %5, %6 // 源指令, %8变成%9
  store i32 %9, i32* %2, align 4 // %8变成%9
  ret i32 0
BasicBlock after replaceAllUsesWith:
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %3, align 4
  store i32 2, i32* %4, align 4
  %5 = load i32, i32* %3, align 4
  %6 = load i32, i32* %4, align 4
  %7 = sub i32 0, %6
  %8 = sub i32 %5, %7
  %9 = add nsw i32 %5, %6
  store i32 %8, i32* %2, align 4 // 这里发生更改,原本存储%9 (b+c),先在存储%8 (b-(-c))
  ret i32 0
bool SplitBasicBlock::runOnFunction(Function &F) {
    // 基本块拆分次数要在(1,10]区间中
    if (!((SplitNum > 1) && (SplitNum <= 10))) {
        errs()<<"Split application basic block percentage -split_num=x must be 1 < x <= 10";
        return false;
    }
 
    Function *tmp = &F;
 
    // 检查当前函数是否需要进行split操作
    if (toObfuscate(flag, tmp, "split")) {
        split(tmp);//进行split操作
        ++Split;
    }
 
    return false;
}
bool SplitBasicBlock::runOnFunction(Function &F) {
    // 基本块拆分次数要在(1,10]区间中
    if (!((SplitNum > 1) && (SplitNum <= 10))) {
        errs()<<"Split application basic block percentage -split_num=x must be 1 < x <= 10";
        return false;
    }
 
    Function *tmp = &F;
 
    // 检查当前函数是否需要进行split操作
    if (toObfuscate(flag, tmp, "split")) {
        split(tmp);//进行split操作
        ++Split;
    }
 
    return false;
}
void SplitBasicBlock::split(Function *f) {
    std::vector<BasicBlock *> origBB;
    int splitN = SplitNum;
    // 保存函数中所有的基本块到vector中
    for (Function::iterator I = f->begin(), IE = f->end(); I != IE; ++I) {
        origBB.push_back(&*I);
    }
    // 遍历所有基本块
    for (std::vector<BasicBlock *>::iterator I = origBB.begin(),IE = origBB.end();I != IE; ++I) {
        BasicBlock *curr = *I;
        // 指令数<2的基本块和存在phi的基本块不进行分割操作
        if (curr->size() < 2 || containsPHI(curr)) {
            continue;
        }
        // 调整分割次数,以防止分隔次数大于基本块中的指令次数
        if ((size_t)splitN > curr->size()) {//这不应该还有等于嘛?
            splitN = curr->size() - 1;
        }
        //以下是生成分割点的操作
        // 存储分割点([1,size-1])到vector中
        std::vector<int> test;
        for (unsigned i = 1; i < curr->size(); ++i) {
            test.push_back(i);
        }
        if (test.size() != 1) {
            shuffle(test);// 搅乱指令vector中的顺序
            std::sort(test.begin(), test.begin() + splitN);//对前splitN个进行排序(从小到大),以便按顺序分割而不会出错
        }
        // 以下是进行分割的操作
        BasicBlock::iterator it = curr->begin();
        BasicBlock *toSplit = curr;
        int last = 0;
        for (int i = 0; i < splitN; ++i) {//分割次数
            //it调整到分割点处的指令
            for (int j = 0; j < test[i] - last; ++j) {//为什么要这么麻烦???
                ++it;
            }
            last = test[i];//分割后,记录新块的起始点
            //当前基本块的指令数 > 2 则进行基本块分割
            if(toSplit->size() < 2)
                continue;
            toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split");
        }
        ++Split;
    }
}
void SplitBasicBlock::split(Function *f) {
    std::vector<BasicBlock *> origBB;
    int splitN = SplitNum;
    // 保存函数中所有的基本块到vector中
    for (Function::iterator I = f->begin(), IE = f->end(); I != IE; ++I) {
        origBB.push_back(&*I);
    }
    // 遍历所有基本块
    for (std::vector<BasicBlock *>::iterator I = origBB.begin(),IE = origBB.end();I != IE; ++I) {
        BasicBlock *curr = *I;
        // 指令数<2的基本块和存在phi的基本块不进行分割操作
        if (curr->size() < 2 || containsPHI(curr)) {
            continue;
        }
        // 调整分割次数,以防止分隔次数大于基本块中的指令次数
        if ((size_t)splitN > curr->size()) {//这不应该还有等于嘛?
            splitN = curr->size() - 1;
        }
        //以下是生成分割点的操作
        // 存储分割点([1,size-1])到vector中
        std::vector<int> test;
        for (unsigned i = 1; i < curr->size(); ++i) {
            test.push_back(i);
        }
        if (test.size() != 1) {
            shuffle(test);// 搅乱指令vector中的顺序
            std::sort(test.begin(), test.begin() + splitN);//对前splitN个进行排序(从小到大),以便按顺序分割而不会出错
        }
        // 以下是进行分割的操作
        BasicBlock::iterator it = curr->begin();
        BasicBlock *toSplit = curr;
        int last = 0;
        for (int i = 0; i < splitN; ++i) {//分割次数
            //it调整到分割点处的指令
            for (int j = 0; j < test[i] - last; ++j) {//为什么要这么麻烦???
                ++it;
            }
            last = test[i];//分割后,记录新块的起始点
            //当前基本块的指令数 > 2 则进行基本块分割
            if(toSplit->size() < 2)
                continue;
            toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split");
        }
        ++Split;
    }
}
a = 1;
if (v < 10)
     a = 2;
b = a;
a = 1;
if (v < 10)
     a = 2;
b = a;
a1 = 1;
if (v < 10)
    a2 = 2;
b = PHI(a1, a2);
a1 = 1;
if (v < 10)
    a2 = 2;
b = PHI(a1, a2);
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) {
    assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!");
    assert(I != InstList.end() && "Trying to get me to create degenerate basic block!");
    //创建一个新的基本块,并插入到当前基本块的后面
    BasicBlock *New = BasicBlock::Create(getContext(), BBName, getParent(), this->getNextNode());
 
    // 保存分割点处的指令的调试信息
    DebugLoc Loc = I->getDebugLoc();
    // 将当前基本块的指令(从I到end())转移到新的基本块中
    New->getInstList().splice(New->end(), this->getInstList(), I, end());
 
    // 在当前基本块的末尾添加分支指令,跳转到新建基本块中
    BranchInst *BI = BranchInst::Create(New, this);
    BI->setDebugLoc(Loc);
 
    // 遍历新建基本块的后继基本块,更新后继基本块中的PHI nodes的前驱基本块为新的基本块而非原来的基本块
    for (succ_iterator I = succ_begin(New), E = succ_end(New); I != E; ++I) {
        BasicBlock *Successor = *I;
        PHINode *PN;
        // 遍历后继基本块中的PHINode(转型后)
        for (BasicBlock::iterator II = Successor->begin(); (PN = dyn_cast<PHINode>(II)); ++II) {
            //循环替换PHINOde(前驱基本块为当前基本块)的前驱基本块为新的基本块
            int IDX = PN->getBasicBlockIndex(this);//获取PHINode所在当前基本块的索引值
            while (IDX != -1) {
                PN->setIncomingBlock((unsigned)IDX, New);//设置PHINode的前驱基本块为新的基本块(对应索引值为IDX)
                IDX = PN->getBasicBlockIndex(this);
            }
        }
    }
    return New;
}
BasicBlock *BasicBlock::splitBasicBlock(iterator I, const Twine &BBName) {
    assert(getTerminator() && "Can't use splitBasicBlock on degenerate BB!");
    assert(I != InstList.end() && "Trying to get me to create degenerate basic block!");
    //创建一个新的基本块,并插入到当前基本块的后面
    BasicBlock *New = BasicBlock::Create(getContext(), BBName, getParent(), this->getNextNode());
 
    // 保存分割点处的指令的调试信息
    DebugLoc Loc = I->getDebugLoc();
    // 将当前基本块的指令(从I到end())转移到新的基本块中
    New->getInstList().splice(New->end(), this->getInstList(), I, end());
 
    // 在当前基本块的末尾添加分支指令,跳转到新建基本块中
    BranchInst *BI = BranchInst::Create(New, this);
    BI->setDebugLoc(Loc);
 
    // 遍历新建基本块的后继基本块,更新后继基本块中的PHI nodes的前驱基本块为新的基本块而非原来的基本块
    for (succ_iterator I = succ_begin(New), E = succ_end(New); I != E; ++I) {
        BasicBlock *Successor = *I;
        PHINode *PN;
        // 遍历后继基本块中的PHINode(转型后)
        for (BasicBlock::iterator II = Successor->begin(); (PN = dyn_cast<PHINode>(II)); ++II) {
            //循环替换PHINOde(前驱基本块为当前基本块)的前驱基本块为新的基本块
            int IDX = PN->getBasicBlockIndex(this);//获取PHINode所在当前基本块的索引值
            while (IDX != -1) {
                PN->setIncomingBlock((unsigned)IDX, New);//设置PHINode的前驱基本块为新的基本块(对应索引值为IDX)
                IDX = PN->getBasicBlockIndex(this);
            }
        }
    }
    return New;
}
// SCRAMBLER
char scrambling_key[16];
llvm::cryptoutils->get_bytes(scrambling_key, 16);
// END OF SCRAMBLER
// SCRAMBLER
char scrambling_key[16];
llvm::cryptoutils->get_bytes(scrambling_key, 16);
// END OF SCRAMBLER
// Lower switch
FunctionPass *lower = createLowerSwitchPass();
lower->runOnFunction(*f);
// 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());
// 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());
// 获取函数f中的第一个基本块
Function::iterator tmp = f->begin();  //++tmp;
BasicBlock *insert = &*tmp;
 
// 如果函数f中的第一个基本块的末尾为分支指令
BranchInst *br = NULL;
if (isa<BranchInst>(insert->getTerminator())) {
    br = cast<BranchInst>(insert->getTerminator());
}
// 最后一条指令是条件分支指令 或者 有多个后继基本块
if ((br != NULL && br->isConditional()) || insert->getTerminator()->getNumSuccessors() > 1) {
    //获取基本块中最后一个指令作为分割点(end()获取的是最后一个指令的下一个节点)
    BasicBlock::iterator i = insert->end();
    --i;
    //如果基本块中的指令 > 1,那么分割点为倒数第二条指令
    if (insert->size() > 1) {
        --i;
    }
    //以指令i为分割点分割基本块,并返回新的基本块,然后将新的基本块插入到origBB中的第一个基本块之前
    BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
    origBB.insert(origBB.begin(), tmpBB);
}
 
// 删除函数f中的第一个基本块(也就是分割之后的旧的基本块)的终止指令(末尾)
insert->getTerminator()->eraseFromParent();
// 获取函数f中的第一个基本块
Function::iterator tmp = f->begin();  //++tmp;
BasicBlock *insert = &*tmp;
 
// 如果函数f中的第一个基本块的末尾为分支指令
BranchInst *br = NULL;
if (isa<BranchInst>(insert->getTerminator())) {
    br = cast<BranchInst>(insert->getTerminator());
}
// 最后一条指令是条件分支指令 或者 有多个后继基本块
if ((br != NULL && br->isConditional()) || insert->getTerminator()->getNumSuccessors() > 1) {
    //获取基本块中最后一个指令作为分割点(end()获取的是最后一个指令的下一个节点)
    BasicBlock::iterator i = insert->end();
    --i;
    //如果基本块中的指令 > 1,那么分割点为倒数第二条指令
    if (insert->size() > 1) {
        --i;
    }
    //以指令i为分割点分割基本块,并返回新的基本块,然后将新的基本块插入到origBB中的第一个基本块之前
    BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
    origBB.insert(origBB.begin(), tmpBB);
}
 
// 删除函数f中的第一个基本块(也就是分割之后的旧的基本块)的终止指令(末尾)
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);
// first BB jump to loopEntry
BranchInst::Create(loopEntry, insert);
// loopEnd jump to loopEntry
BranchInst::Create(loopEntry, loopEnd);
 
// create swDefault BB
BasicBlock *swDefault = BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
// swDefault jump to 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());
// 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);
// first BB jump to loopEntry
BranchInst::Create(loopEntry, insert);
// loopEnd jump to loopEntry
BranchInst::Create(loopEntry, loopEnd);
 
// create swDefault BB
BasicBlock *swDefault = BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
// swDefault jump to 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());
// 遍历origBB的所有基本块
for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end(); ++b) {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;
 
    // 将基本块移动到loopEnd之前(位置意义上的,而非代码逻辑上的)
    i->moveBefore(loopEnd);
 
    // 生成numCase,并将基本块i加入到对应索引值的case分支处
    numCase = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),
        llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
    switchI->addCase(numCase, i);
}
// 遍历origBB的所有基本块
for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end(); ++b) {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;
 
    // 将基本块移动到loopEnd之前(位置意义上的,而非代码逻辑上的)
    i->moveBefore(loopEnd);
 
    // 生成numCase,并将基本块i加入到对应索引值的case分支处
    numCase = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),
        llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
    switchI->addCase(numCase, i);
}
llvm::cryptoutils->scramble32(0, scrambling_key))
llvm::cryptoutils->scramble32(0, scrambling_key))

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 15
支持
分享
最新回复 (3)
雪    币: 1229
活跃值: (1760)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
tql 太库辣
2024-6-18 11:29
0
雪    币: 2337
活跃值: (6708)
能力值: ( LV7,RANK:102 )
在线值:
发帖
回帖
粉丝
3
ollvm的灵魂是switch case
2024-11-13 17:41
0
雪    币: 4761
活跃值: (4387)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4

非常有用

最后于 2024-11-13 17:54 被木志本柯编辑 ,原因:
2024-11-13 17:53
0
游客
登录 | 注册 方可回帖
返回
//