美文网首页
关于LLVM pass的学习(3)-- BogusControl

关于LLVM pass的学习(3)-- BogusControl

作者: ldzSpace | 来源:发表于2018-11-01 16:05 被阅读0次

    功能:

    是为函数增加新的虚假控制流和添加垃圾指令

    入口函数:

    BogusControlFlow继承了FunctionPass,因此它的入口函数即为runOnFunction该入口函数进来先判断两个参数的值:ObfTimes和ObfProbRate ,分别代表bcf(BogusControlFlow)循环运行的次数和每个basic block被混淆的几率,它们的默认值分别为1和30%。可通过设置参数boguscf-loop、 boguscf-prob修改它们的默认值
    例如:

    if (!((ObfProbRate > 0) && (ObfProbRate <= 100))) 
    

    在编译程序代码时,若要启动bcf模块,需要带上参数“-mllvm -bcf”

         if (toObfuscate(flag, &F, "bcf")) 
    

    最后调用bogus函数。bogus函数首先将本function的所有basicblock存放到一个list容器中,然后使用一个while循环调用addBogusFlow函数对选中的basicblock进行增加虚假控制流

    核心函数:

    • bogus 函数
      首先判断ObfTimes和ObfProbRate 这两个参数

      判断函数
      一个大循环包括下面的内容,这个大循环是ObfTimes 来控制循环运行的次数:
      1:将函数中的所有BB 添加到list 中
      添加到list
      2: 判断上面的list 是否为空,将这个方法的内部的所有BB 根据混淆比例看是否去虚假流程
      有概率的执行虚假流
    • addBogusFlow 函数
      举个例子:

    int func1(int a,int b)
    {
           return a+b;
    }
    

    编译完后的IR图


    IR

    addBogusFlow函数
    1:调用getFirstNonPHIOrDbgOrLifetime函数获取本basicblock中第一个不是Phi、Dbg、Lifetime的指令的地址(在本例中,即为%a.addr = alloca i32, aling 4的地址)
    2:调用splitBasicBlock函数。splitBasicBlock函数可根据上述指令的地址将一个basicblock一分为二(可称为first basicblock 和original basicblock),i1 是%a.addr = alloca i32, aling 4的地址,分割的时候是第二块是从i1开始到最后,i1 上面的部分为一块


    分割过程
    分割后此时IR 如下:
    image.png

    接着调用createAlteredBasicBlock函数对original basicblock进行拷贝生成一个名为“altered basicblock”的basicblock,并对该basicblock加入一些垃圾指令。加入垃圾指令的方法是遍历该basicblock中的所有OpCode【操作码】,若包含有Add、Sub、UDiv、SDiv、URem、SRem、Shl、LShr、AShr、And、Or、Xor以及FAdd、FSub、FMul、FDiv、FRem指令,则用随机生成一些指令来进行替换。由于该block在程序运行时并不会执行,因此无需担心插入的指令对原始程序运行的结果产生影响。拷贝original basicblock后,


    image.png

    IR图如图5所示。


    image.png

    这时,所有的basicblock已经准备完毕,一共存在有3个basicblock,需要调整他们之间的关系。首先清除first basicblock和altered basicblock跟父节点的关系,代码为:

    basicBlock->getTerminator()->eraseFromParent();
    alteredBB->getTerminator()->eraseFromParent();
    

    清除完毕后的IR图如图6所示。


    image.png

    接着下一步的操作是增加basicblock之间的条件跳转指令。对于first basicblock(即为图中的entry),bcf源码的做法是先增加一条比较语句 1.0 = = 1.0 ,然后为真时跳转到original basicblock,为假则跳转到altered basicblock。可用伪代码如下表示:

    if( 1.0 == 1. 0)
        original basicblock
    else
        altered basicblock
    

    对于altered basicblock模块,在它的尾部增加一条跳转指令,使得当它执行完毕之后(实际上它并不会执行),跳转到original basicblock模块。此时的IR图如图7所示。


    image.png
    image.png

    最后,获取basicblock中最后一条指令的地址(在该例子中即ret指令的地址),调用splitBasicblock函数将original basicblock一分为二(original basicblok和originalBBpart2)


    image.png
    然后调用如下代码:
    originalBB->getTerminator()->eraseFromParent();
    

    消除original basicblok和originalBBpart2的关系后,再在original basicblock的末尾加入一个判断语句,为真时跳转到ret指令,为假则跳转到altered basicblock,伪代码如下所示:

    if( 1.0 == 1. 0)
        ret
    else
        altered basicblock
    

    此时该func1函数的IR图如图8所示:

    image.png
    doF函数 【和bogus 函数在位置相同】
    该函数的功能是将Function中所有为真的判断语句进行替换,比如上一节中的“1.0 == 1.0 ”。它的思想是定义两个全局变量x、y并且初始化为0,然后遍历Module内的所有指令,并将所有的FCMP_TRUE分支指令替换为“y<10 || x
    x(x-1)%2 ==0”。替换完毕后func1函数的IR流程图如图9所示: image.png
    至此,对func1函数的一次bcf混淆过程就完成了

    相关文章

      网友评论

          本文标题:关于LLVM pass的学习(3)-- BogusControl

          本文链接:https://www.haomeiwen.com/subject/cgyxxqtx.html