其他分享
首页 > 其他分享> > 初识OLLVM

初识OLLVM

作者:互联网

编译器

一般编译器分为前端,中间优化和后端三部分。前端进行语法分析,中间进行优化后由后端编译成对应平台的代码(arm,x86)。现在主流的编译器有linux平台下的gcc 和 llvm-clang,以及windows平台下的msvc编译器。

LLVM

gcc编译器虽然强大但是有一个缺点就是因为其相当于一个完整的可执行文件,编译器的前端,中间优化和后端中间的耦合度比较高,所以要想增加一个前端用来支持一种新的语言,或者增加一个后端来生成一种新平台的机器码都需要做很大的改动很不方便。于是就有了LLVM的出现,LLVM是一个编译器框架,和传统的编译器一样也分为前端,中间优化和后端三部分。但是其利用与平台无关的中间语言IR来实现前端,中间优化和后端的分离,这样如果编译器需要新增加一种语言只需要增加一个前端语法解析器即可。例如Clang就是基于LLVM架构的能够支持C/C++/Objective-C语言的编译器前端。

LLVM编译过程

llvm编译过程大致分为 预处理-->语法分析-->生成IR代码-->IR代码优化-->生成汇编代码(x86, arm)-->Link-->生成目标文件,之后就是链接器链接各个目标文件并生成可执行文件的过程。(所以汇编的过程实际包含在编译过程中)

LLVM IR代码文件的格式为bc/llc,bc是一种bitcode的格式,而llc是一种人类可以阅读的格式。还有一种格式就是内存中的格式,LLVM在内存中会将IR分为Module,function,basicblock,Instruction四种表达形式。

LLVM中间优化过程

llvm通过将前端代码(c/cpp等)生成与平台无关的llvm IR中间代码,然后通过多个pass(就是一个一个的类,每一个类对应一种功能)来对IR代码进行优化。

OLLVM

OLLVM是一种通过利用LLVM回生产IR中间代码并通过pass优化代码的特点,通过增加自己的pass来对代码进行优化,但是这种优化不是为了让代码更简洁相反是让代码更复杂,达到混淆的目的。一般支持三种主要的混淆手段:控制流平坦化,虚假执行流和替换指令。

OLLVM之控制流平坦化

ollvm三种混淆手段中控制流平坦化混淆效果最佳。其原理是将函数分为若干个控制流基本块,这些基本块是以跳转指令(不包含调用指令)结尾的,然后利用switch结构通过判断状态变量的值来执行相应的控制流基本块,因为一个基本块可能会跳转到一个或者两个基本块中,所以还需要通过新增加一些块或代码来控制修改状态变量的值从而跳转到不同的基本块中。

去除ollvm控制流平坦化

根据ollvm控制流平坦化混淆的原理可得接混淆的步骤如下。

利用unicron模拟执行去除控制流平坦化

测试程序是一个arm-v7a(thumb)的程序
混淆前的代码流程图

混淆后的代码流程图

参考看雪无名侠大佬的思路

因为在过滤预处理的时候也把序言过滤了,序言其实也属于真实块,所以需要加上。

观察到return块是一个以bne开头的代码块,也属于真实块需要加上。(所以在实际寻找真实块的过程中有很多需要特殊处理的过程,具体情况具体分析)

寻找一个真实块路径的思路是:如果模拟执行到一个地址是某个真实块的起始地址说明找到了目标真实块。

对于包含条件判断的真实块,也就是有两条路径的真实块需要人为的控制指令指令流程寻找两条路径对应的真实块。为了更好的在后续patch,我们每次都先寻找满足较小条件会执行的路径。

还原后的程序流程图

参考链接:https://bbs.pediy.com/thread-252321.htm

标签:真实,代码,控制流,编译器,初识,指令,跳转,OLLVM
来源: https://www.cnblogs.com/revercc/p/16336307.html