移植OLLVM混淆pass

移植OLLVM混淆pass

文件

仅仅是学习混淆pass的编写,改动不是很大。将OLLVM的pass放进新版本(7.0.0 release)的LLVM源码下进行编译。
OLLVM的pass目录:OLLVM/lib/Transforms/Obfuscation

控制流平坦化:Flattening.cpp
虚假控制流:BogusControlFlow.cpp SplitBasicBlocks.cpp
指令替换:Substitution.cpp

对应头文件目录:OLLVM/include/llvm/Transforms/Obfuscation

这里以分割基本块的pass为例,将
SplitBasicBlocks.cpp SplitBasicBlocks.h
Utils.cpp Utils.h
CryptoUtils.h(include/llvm/)
复制到对应目录。

修改对应目录下的LLVMBuild.txt,subdirectories添加模块目录名称。修改对应目录下(Obfuscation目录下和Transforms目录下)的CMakeLists.txt,add_llvm_library添加模块名称和参与编译文件,add_dependencies添加模块名称。此时进行编译就可以看到build/lib目录下已经有libLLVMObfus.a(我把OLLVM里的Obfuscation改成了Obfus)。
但是此时运行opt,发现无-split参数。

所以我们还需要修改IPO(Transforms/IPO),加入PassManager之后可以直接通过clang的参数使用pass了
PassManagerBuilder.cpp:

1
2
3
+45      #include "llvm/Transforms/Obfus/Split.h"
+158 static cl::opt<bool> Split("split", cl::init(false),cl::desc("Enable basic block splitting"));
+433 MPM.add(createSplitBasicBlock(Split));

IPO的LLVMBuild.txt:
+required_libraries=Obfus

ok,此时编译完成后,opt参数列表里就有了-split

代码

split PASS的实现:

  • 保存Function的所有Block;

  • 逐个处理Block,对非单一指令BB和不包含PHI指令的BB进行分割;

  • 生成乱序表;

  • 乱序处理Block中的指令;

  • 具体处理单个指令的方法:
    *BasicBlock->splitBasicBlock(BasicBlock::iterator,*BasicBlock->getName()+".splist")
    位于OLLVM/lib/IR/BasicBlock.cpp

    在指定的指令处将一个基本块一分为二。注意所有在指定指令前的指令会作为原始基本块的一部分,一个无条件分支会被添加到新的BB,余下的指令会被移到新的BB,包括旧BB的终止符。这会使迭代器无效。
    注意这只针对一下格式合格的BB(有头有尾),并且指定的指令不允许是指令列表的最后一个(会导致生成一个退化的BB,而且内部带终止符)。

  • 新建一个BB,将指定指令移到新的BB,为新BB添加分支指令;

  • 遍历新block的后继block,更新所有PHI节点信息,将原来从旧block出来的分支路径改为从新block出来。

判断PHI节点:

1
2
3
4
5
6
7
8
for (BasicBlock::iterator II = Successor->begin();
(PN = dyn_cast<PHINode>(II)); ++II) {
int IDX = PN->getBasicBlockIndex(this);
while (IDX != -1) {
PN->setIncomingBlock((unsigned)IDX, New);
IDX = PN->getBasicBlockIndex(this);
}
}

这里添加几条打印信息代码:

1
2
3
4
5
6
7
8
9
10
#++ 88 
errs()<<"This BB size: "<<curr->size()<<"\n";
#++ 114
errs()<<"To split instruction: "<<*it<<"\n";
#++ 125
errs()<<"After split: \n";
for(BasicBlock::iterator sptit = toSplit->begin();sptit!=toSplit->end();++sptit){
errs()<<"[+] "<<*sptit<<"\n";
}
errs()<<"\n";

打印出对BB的分割点。

对比pass效果
./clang -save-temps -S -mllvm -split test.c -o test.s
拿到的是pass处理的汇编文件,和中间文件。
对test.bc->test.ll->test.s(得到未经过pass处理的汇编文件),可自行对比(处理的BB会被添上“.split”)。