title

5-3 OLLVM简介与移植

LLVM源码外开发Pass

在LLVM源码内开发Pass,需要在LLVM源码项目中创建文件目录,才能开发Pass。

源码外开发Pass,参考:Building LLVM with CMake — LLVM 15.0.0 documentation

源码外开发时,项目的目录格式

<**project dir**>/

** **|

** CMakeLists**.txt

** <**pass name**>/**

** **|

** CMakeLists**.txt

** Pass**.cpp

** ..**.

project dir/CMakeLists.txt内容如下:

find_package(LLVM REQUIRED CONFIG)

separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})

add_definitions(${LLVM_DEFINITIONS_LIST})

include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory()

project dir/pass name/CMakeLists.txt内容如下:

add_library(LLVMPassname MODULE Pass.cpp)

编译项目

build cmake ..

build make

编译完成后,在项目build目录中,产生so文件

使用opt加载Pass到IR文件

opt –load /home/kanxue/ollvm2/outpass/build/FunctionName2/libLLVMFunctionName2.so -function helloworld.ll -o helloworld-opt.bc

Clang集成Pass

在VScode命令行中,要llvm编译一个可执行文件,首先需要加载opt产生bc文件,在通过clang编译bc文件得到可执行文件。

如何使用Clang直接编译可执行文件?

00:08:30

OLLVM介绍

参考:github.com/obfuscator-llvm/obfuscator/wiki

基于旧版本llvm源码来开发大量混淆功能的Pass,主要支持三种混淆方案

指令替换,Instructions Substitution -mllvm -sub

原理:等价替换,a=b+c** 替换为 a=b-(-c) **

%0 = load i32*** %a, align 4 **//c取出来

%1 = load i32*** %b, align 4 **//b取出来

%2 = sub i32 0, **%1 **//0-c得负数

**%3 = sub nsw i32 %0, **%2 //b-c得到a

二次变换,a=b+c** 替换为 **a=-(-b+(-c))

%0 = load i32* %a, align 4

%1 = load i32* %b, align 4

%2 = sub i32 0, %0

%3 = sub i32 0, %1

%4 = add i32 %2, %3

%5 = sub nsw i32 0, %4

随机数,r = rand (); a = b + r; a = a + c; a = a - r 对同一个随机数进行+和-操作,最终达到平衡

%0 = load i32*** %a, align **4

%1 = load i32*** %b, align **4

**%2 = add i32 %0, **1107414009

**%3 = add i32 %2, **%1

**%4 = sub nsw i32 %3, **1107414009

虚假控制流,Bogus Control Flow -mllvm -bcf

原始代码流程:

**#include **<stdlib.h>

int main(int argc**,** char** argv**)** {

** int a = atoi(argv[1]);**

** if(**a == 0)

** return 1;**

** **else

** return 10;**

** return 0;**

}

经过虚假控制流混淆后:

控制流程平坦化,Control Flow Flattening -mllvm -fla

原理:将基本块(if.else)转为switch, 通过对一个变量反复的修改,赋值。来控制进入case的顺序,从而确定执行基本块的顺序。

原始代码流程:

**#include **<stdlib.h>

int main(int argc**,** char** argv**)** {

** int a = atoi(argv[1]);**

** if(**a == 0)

** return 1;**

** **else

** return 10;**

** return 0;**

}

经过控制流平坦化处理:

OLLVM函数注解

通过函数注解可以指定任意函数执行何种混淆特性(因此三种混淆方式可以同时出现在一个程序中)

int foo() __attribute((__annotate__((“fla”))));

int foo() {

** return 2;**

}

移植OLLVM项目

为了解决ollvm项目只更新到llvm4.0版本的问题,需要把ollvm Obfuscation移植到llvm最新版本中(这里是9.0示例)

克隆ollvm项目git clone https://github.com/obfuscator-llvm/obfuscator.git** (可能需要切换分支到llvm-4.0)**

Obfuscation 代码目录从Obfuscation/lib/Transforms/Obfuscation** 完整的拷贝到llvm/lib/Transforms/ 目录下**

Obfuscation 头文件目录从Obfuscation/include/llvm/Transforms/Obfuscation** 完整的拷贝到**llvm/include/llvm/Transforms/

查看其他文件的提交信息,把有更改的根据更改内容,对当前llvm进行补充。

obfuscator/lib/Tansforms/CMakeLists.txt 中加入了新的子目录add_subdirectory(Obfuscation)

obfuscator/lib/Tansforms/LLVMBuild.txt 中的subdirectories中增加Obfuscation

obfuscator/lib/Tansforms/IPO/LLVMBuild.txt 中的required_libraries中增加Obfuscation

obfuscator/lib/Tansforms/IPO/PassManagerBuilder.cpp 查看提交记录,从最初一次提交开始,把新增/修改代码复制到llvm的PassManagerBuilder.cpp

Obfuscation/include/llvm/CryptoUtils.h 文件拷贝到llvm/include/llvm/Tansforms/Obfuscation/ 目录下

修改CryptoUtils.cpp中的头文件包含#include ‘llvm/CryptoUtils.h’** 为**#include ‘llvm/Transforms/Obfuscation/CryptoUtils.h’

编译时其他报错的头文件引用代码,也需要如上方式修改。

有些llvm中的API在新版本修改了函数的返回值类型,遇到编译错误时,也需要进行调整Instruction* tbb=fi->getTerminator();

有些llvm中的API在新版本中删除了,需要将未定义的函数注释掉,FunctionPass *lower = createLowerSwitchPass();lower->runOnFunction(*f);** (这将导致删除了控制流程平坦化中创建switch的作用)**

在fork的用户中,找到heroims,参考其他人修复的错误。

//PassManagerBuilder.cpp

MPM.add(createBogus(BogusControlFlow));

**#if **LLVM_VERSION_MAJOR >= 9

** MPM**.add(createLowerSwitchPass());

**#**endif

MPM.add(createFlattening(Flattening));

编译项目:ninja LLVMObfuscation

项目编译后产生的只是.a的静态库lib/libLLVMObfuscation.a

还需要编译Clang:ninja clang

生成可执行文件:clang -mllvm -sub helloworld.c -o helloworld_sub

**生成IR文件: **clang -emit-llvm -S -mllvm -sub helloworld.c -o helloworld.ll

**生成原始IR文件(未混淆): **clang -emit-llvm -S -sub helloworld.c -o helloworld.ll

混淆IR文件和原始IR文件对比,以便于认识其中的差异

obfuscator 还需要根据Pull requests修复BogusControlFlow.cpp中的一个bug#76防止编译卡死

0条搜索结果。