移植ollvm
OLLVM项目代码在 https://github.com/obfuscator-llvm/obfuscator
github中,ollvm是基于llvm4.0进行开发的,下图中 initial LLVM and Clang4.0是llvm原始的代码,其他的都是ollvm修改的代码,我们需要把这些修改的代码,复制到自己llvm项目中。
需要修改的内容如下
ollvm4.0 | llvm-project-9.0.1 | |
---|---|---|
1 | obfuscator/include/llvm/Transforms/Obfuscation/ | llvm-project-9.0.1/llvm/include/llvm/Transforms/Obfuscation |
2 | obfuscator/include/llvm/CryptoUtils.h | llvm-project-9.0.1/llvm/include/llvm/CryptoUtils.h(这个有位置点问题) |
3 | obfuscator/lib/Transforms/Obfuscation/ | llvm-project-9.0.1/llvm/lib/Transforms/Obfuscation |
4 | obfuscator/lib/Transforms/CMakeLists.txt | |
5 | obfuscator/lib/Transforms/LLVMBuild.txt | |
6 | obfuscator/lib/Transforms/IPO/LLVMBuild.txt | |
7 | obfuscator/lib/Transforms/IPO/PassManagerBuilder.cpp | |
8 | obfuscator/lib/Transforms/Obfuscation/Flattening.cpp | |
9 | obfuscator/lib/Transforms/Obfuscation/BogusControlFlow.cpp | |
make LLVMObfuscation | ||
make clang | ||
10 | fix some bug #76 | https://github.com/obfuscator-llvm/obfuscator/pull/76/files |
1、将项1、2、3、指定的文件或者目录复制到对应的位置
2、修改内容
4)obfuscator/lib/Transforms/CMakeLists.txt
add_subdirectory(Obfuscation)
5)obfuscator/lib/Transforms/LLVMBuild.txt
[common]
subdirectories = AggressiveInstCombine Coroutines IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC TestEncodeFuncName Obfuscation
6)obfuscator/lib/Transforms/IPO/LLVMBuild.txt
required_libraries 中添加 Obfuscation
7)obfuscator/lib/Transforms/IPO/PassManagerBuilder.cpp
添加头文件
#include "llvm/Transforms/Obfuscation/BogusControlFlow.h"
#include "llvm/Transforms/Obfuscation/Flattening.h"
#include "llvm/Transforms/Obfuscation/Split.h"
#include "llvm/Transforms/Obfuscation/Substitution.h"
#include "llvm/CryptoUtils.h"
添加代码 参考 https://github.com/obfuscator-llvm/obfuscator/blob/llvm-4.0/lib/Transforms/IPO/PassManagerBuilder.cpp
8)obfuscator/lib/Transforms/Obfuscation/Flattening.cpp
导入头文件
9)obfuscator/lib/Transforms/Obfuscation/BogusControlFlow.cpp
尝试编译
make LLVMObfuscation
make clang
能编译通过说明代码移植没有啥问题了
下面修复ollvm自身的bug
https://github.com/obfuscator-llvm/obfuscator/pull/76/files
编译
make LLVMObfuscation
make clang 应该是代码没有啥问题的(还是有问题、但是当前没影响、之后有影响的时候再进行修改)
ollvm有哪些功能
- 指令替换
- 虚假流程
- 控制流程平坦化
- 函数属性(指示llvm是否对函数进行混淆、进行那种混淆)
指令替换
比方:当有一个变量 a
进行指令替换: a = b - (-c) ,将指令替换为更加复杂的方式
对于IDA F5插件的功能,可以将 a = b -(-c) 和 a = -(-b + (-c)) 全局静态变量进行优化
当时,当指令替换中存在随机数时、无法进行优化。看看ollvm的指令替换功能。
#include<stdio.h>
int main(int argc,char** argv)
{
int n = argc + 8;
if(n >= 10)
{
printf("hello ollvm:%d\r\n",n);
}else{
printf("hello show me\r\n");
}
return 0;
}
设置环境变量、并仅编译一个可执行文件,看看clang和代码是否正常
export PATH=/home/me/workspace/llvm-project/llvm/cmake-build-debug/bin:$PATH
clang hello_ollvm.c -o hello_ollvm
先看看clang编译上面的代码时、最原始的中间文件
clang -emit-llvm -S multiply.c -o multiply.ll
; ModuleID = 'multiply.c'
source_filename = "multiply.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.16.0"
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
%retval = alloca i32, align 4
%argc.addr = alloca i32, align 4
%argv.addr = alloca i8**, align 8
%a = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 %argc, i32* %argc.addr, align 4
store i8** %argv, i8*** %argv.addr, align 8
%0 = load i32, i32* %argc.addr, align 4
%add = add nsw i32 %0, 10
store i32 %add, i32* %a, align 4
%1 = load i32, i32* %a, align 4
%cmp = icmp sge i32 %1, 10
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
store i32 11, i32* %a, align 4
br label %if.end
if.end: ; preds = %if.then, %entry
ret i32 0
}
默认的指令替换
clang -mllvm -sub -emit-llvm -S multiply.c -o multiply.ll
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
%retval = alloca i32, align 4
%argc.addr = alloca i32, align 4
%argv.addr = alloca i8**, align 8
%a = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 %argc, i32* %argc.addr, align 4
store i8** %argv, i8*** %argv.addr, align 8
%0 = load i32, i32* %argc.addr, align 4
%1 = sub i32 %0, 130102393
%2 = add i32 %1, 10
%3 = add i32 %2, 130102393
%add = add nsw i32 %0, 10
store i32 %3, i32* %a, align 4
%4 = load i32, i32* %a, align 4
%cmp = icmp sge i32 %4, 10
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
store i32 11, i32* %a, align 4
br label %if.end
if.end: ; preds = %if.then, %entry
ret i32 0
}
可以增加 指令替换的复杂度
clang -mllvm -sub -emit-llvm -mllvm -sub_loop=3 -S multiply.c -o multiply_sub_3.ll
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
%retval = alloca i32, align 4
%argc.addr = alloca i32, align 4
%argv.addr = alloca i8**, align 8
%a = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 %argc, i32* %argc.addr, align 4
store i8** %argv, i8*** %argv.addr, align 8
%0 = load i32, i32* %argc.addr, align 4
%1 = sub i32 0, -1990704939
%2 = add i32 0, %1
%3 = sub i32 0, -1990704939
%4 = sub i32 0, 10
%5 = add i32 %2, %4
%6 = sub i32 %2, 10
%7 = sub i32 0, -1990704939
%8 = sub i32 %5, %7
%9 = add i32 %5, -1990704939
%10 = sub i32 0, 1617860029
%11 = sub i32 %10, 10
%12 = add i32 %11, 1617860029
%13 = sub i32 0, 10
%14 = sub i32 %0, -1578002009
%15 = sub i32 %14, -510241612
%16 = add i32 %15, -1578002009
%17 = sub i32 %0, -510241612
%18 = sub i32 0, %8
%19 = add i32 %16, %18
%20 = sub i32 %16, %8
%21 = add i32 %19, -426374699
%22 = add i32 %21, -510241612
%23 = sub i32 %22, -426374699
%24 = add i32 %19, -510241612
%25 = add i32 %0, 76155044
%26 = sub i32 %25, %8
%27 = sub i32 %26, 76155044
%28 = sub i32 %0, %8
%29 = sub i32 0, -1106340572
%30 = add i32 %0, %29
%31 = sub i32 %0, -1106340572
%32 = sub i32 %30, 1721883602
%33 = add i32 %32, 10
%34 = add i32 %33, 1721883602
%35 = add i32 %30, 10
%36 = sub i32 0, -1106340572
%37 = sub i32 %34, %36
%38 = add i32 %34, -1106340572
%39 = sub i32 0, %0
%40 = sub i32 0, 10
%41 = add i32 %39, %40
%42 = sub i32 0, %41
%add = add nsw i32 %0, 10
store i32 %23, i32* %a, align 4
%43 = load i32, i32* %a, align 4
%cmp = icmp sge i32 %43, 10
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
store i32 11, i32* %a, align 4
br label %if.end
if.end: ; preds = %if.then, %entry
ret i32 0
}
虚假流程
使用如下的代码演示、执行之后的指令自己查看区别
int main(int argc, char** argv) {
int a = argc + 8;
if(a == 0)
return 1;
else
return 10;
return 0;
}
clang -emit-llvm -S bcf.c -o bcf.ll
clang -emit-llvm -mllvm -bcf -S bcf.c -o bcf_bcf.ll
clang -emit-llvm -mllvm -bcf -mllvm -bcf_loop=3 -S bcf.c -o bcf_bcf_3.ll
clang -emit-llvm -mllvm -bcf -mllvm -bcf_loop=3 -mllvm -bcf_prob=80 -S bcf.c -o bcf_bcf_3_prob.ll
控制流程平坦化
使用的代码还是虚假流程的代码
需要修改一下代码,在lib/Transforms/Obfuscation/Flattening.cpp 文件中,注释下面的行
#include <llvm/Transforms/Utils.h>
FunctionPass *lower = createLowerSwitchPass();
lower->runOnFunction(*f);
在lib/Transforms/IPO/PassManagerBuilder.cpp 文件中,添加如下的内容
MPM.add(createSplitBasicBlock(Split));
MPM.add(createBogus(BogusControlFlow));
// TODO 添加的内容
if(Flattening){
MPM.add(createLowerSwitchPass());
}
MPM.add(createFlattening(Flattening));
clang -emit-llvm -mllvm -fla -S fla.c -o fla_fla.ll
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
%.reg2mem = alloca i32
%retval = alloca i32, align 4
%argc.addr = alloca i32, align 4
%argv.addr = alloca i8**, align 8
%a = alloca i32, align 4
store i32 0, i32* %retval, align 4
store i32 %argc, i32* %argc.addr, align 4
store i8** %argv, i8*** %argv.addr, align 8
%0 = load i32, i32* %argc.addr, align 4
%add = add nsw i32 %0, 8
store i32 %add, i32* %a, align 4
%1 = load i32, i32* %a, align 4
store i32 %1, i32* %.reg2mem
%switchVar = alloca i32
store i32 637648687, i32* %switchVar
br label %loopEntry
loopEntry: ; preds = %entry, %loopEnd
%switchVar1 = load i32, i32* %switchVar
switch i32 %switchVar1, label %switchDefault [
i32 637648687, label %first
i32 972343720, label %if.then
i32 1878977632, label %if.else
i32 1565953112, label %return
]
switchDefault: ; preds = %loopEntry
br label %loopEnd
first: ; preds = %loopEntry
%.reload = load volatile i32, i32* %.reg2mem
%cmp = icmp eq i32 %.reload, 0
%2 = select i1 %cmp, i32 972343720, i32 1878977632
store i32 %2, i32* %switchVar
br label %loopEnd
if.then: ; preds = %loopEntry
store i32 1, i32* %retval, align 4
store i32 1565953112, i32* %switchVar
br label %loopEnd
if.else: ; preds = %loopEntry
store i32 10, i32* %retval, align 4
store i32 1565953112, i32* %switchVar
br label %loopEnd
return: ; preds = %loopEntry
%3 = load i32, i32* %retval, align 4
ret i32 %3
loopEnd: ; preds = %if.else, %if.then, %first, %switchDefault
br label %loopEntry
}
函数属性
只看看这个属性怎么用就行了,可以自己到源码里看
#include<stdlib.h>
int foo() __attribute((__annotate__(("fla")))); // 会进行fla的混淆
int foo()
{
return 2;
}
int bbb() __attribute((__annotate__(("nofla")))); // 不会进行fla的混淆
int bbb()
{
return 2;
}