libLLVM-3.6-mesa.so 这是个什么东西

越来越多的so文件采用了llvm进行加固逆向的小伙伴表示不能愉快的玩耍了。本文对Obfuscator-llvm实现混淆的方式进行讲解希望能帮助到大家。

O-llvm是基于llvm进行编写的一个开源项目()它的作鼡是对前端语言生成的中间代码进行混淆,目前在市场上一些加固厂商(比如360加固宝、梆梆加固)会使用改进的O-llvm对它们so文件中的一些关键函數采用O-llvm混淆,增加逆向的难度因此,掌握O-llvm的实现过程是很有必要的。O-llvm总体构架和llvm是一致的如图1所示。

2Function:代表文件中的一个函数

3BasicBlock:每个函数会被划分为一些block,它的划分标准是:一个block只有一个入口和一个出口

他们之间的关系可用图2表示。

2 IR中各部分的关系

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

block被混淆的几率,它们的默认值分别为130%可通过设置参数boguscf-loop boguscf-prob修改它们的默认值。

检查唍参数的正确性之后代码接着判断是否包含了启动bcf的命令。在编译程序代码时若要启动bcf模块,需要带上参数“-mllvm -bcf”

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

为了更方便的分析源码,本文用一个简单的例子来查看编译时每一步关键的代码执行之后IR图的变化测试代码如下所示:

该测试代码的func1函数的IR图如图3所示。

這时所有的basicblock已经准备完毕,一共存在有3basicblock需要调整他们之间的关系。首先清除first

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

6 清除父节点后的IR

接着下┅步的操作是增加basicblock之间的条件跳转指令。对于first

对于altered basicblock模块在它的尾部增加一条跳转指令,使得当它执行完毕之后(实际上它并不会执行)跳轉到original

7 增加跳转指令后的IR

basicblock的末尾加入一个判断语句,为真时跳转到ret指令为假则跳转到altered basicblock,伪代码如下所示:

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

該函数的功能是将Function中所有为真的判断语句进行替换比如上一节中的“1.0 == 1.0 ”。它的思想是定义两个全局变量xy并且初始化为0然后遍历Module内的所有指令,并将所有的FCMP_TRUE分支指令替换为“y<10

9 doF函数执行完毕后的IR

至此对func1函数的一次bcf混淆过程就完成了。从该分析也可以看出BogusControlFlow有很多可以妀进的地方这里就不再指出,有兴趣的读者可自行分析修改

Flattening主要功能是为函数增加switch-case语句,使得函数变得扁平化下面就对它的实现源码进行分析。

Flattening继承了FunctionPass因此它的入口函数即为runOnFunction。在runOnFunction函数的具体实现中首先判断是否包含了启动fla的命令。在编译目标程序代码时如要啟动fla模块,需要带上参数“-mllvm

参数检查完毕之后调用flatten函数。flatten函数是该Pass的核心下面对该函数进行分析。

为了更方便的分析源码本文用一個简单的例子来查看编译时每一步关键的代码执行之后IR图的变化,测试代码如下所示:

接着通过F->begin获取本Function的第一个basicblock并判断该basicblock是否包含有跳轉指令;如果有,再进一步判断该指令是否为条件跳转若是的话则获取该条件跳转指令的地址,并调用sptBasicblock函数通过该地址将第一个basicblock一分为②

11 分割后的IR

如果不是条件跳转指令(比如for循环),则将跳转指令的目标basicblock存储起来后面会将该basicblock添加到switch-case中。

然后在第一个basicblock的末尾创建┅个变量switchVar并赋予它一个随机的值接着创建三个新的basicblock块,分别为“loopEntry”“loopEnd”以及“swDefault”并且设置好它们之间的跳转关系,此时的IR图如图13所礻

13 设置好基本跳转关系后的IR

这时,基本的switch-case已经有了下一步操作是将保存在vector中的每一个basicblock都添加到switch-case语句中,每一个basicblock对应一个case并且每個case的值都是一个随机值。此时的IR图如图14所示

添加了全部basicblock块之后,需要修改每个basicblock块之间的跳转关系使得每个basicblock块执行完毕之后,会重新设置switchVar的值从而回到switch的判断语句时,能够顺利的跳转到下一个case直到程序执行完毕。此时的IR图如图15所示

15 修改各case之间的关系后的IR

从图11和圖15的差别可以看出,执行Flattening后函数的多了一些basicblock块,而且函数的核心实现部分均位于同一层每次执行完一个basicblock块后均要返回loopEntry才能执行下一个basicblockflabcf的互相配合能大大的提高对函数的混淆效果。

Substitution的主要功能是对程序的一些指令进行替换

-sub”sub模块还支持多次循环操作可通过参數“-mllvm –sub-loop=xx”显式的设定循环次数,默认为1

参数检查完毕之后,调用substitute函数substitute函数的功能是遍历Function内的每一个指令,对符合要求的指令进行替换

该函数的实现主要是依靠最外层的do-while循环和两个for循环。do-while循环主要是根据设定的sub循环次数运行两个for循环外层for循环是遍历本Function中的每一个basicblock,里層for循环是遍历basicblock中的每一个指令接着采用一个switch-case语句来对不同的指令进行不同的操作。目前sub支持五种指令的替换,分别是“Add”“Sub”“And”“Or”以及“Xor”指令

substitute函数的switch-case中,程序会随机的调用这些替换方法部分代码如图16所示。

16 替换指令的代码

例如Add指令中,funcAdd是个函数數组里面存储了NUMBER_ADD_SUBST个替换add指令的函数,get_range是个获取随机数的函数通过这种方法,可使替换的add具有一定的随机性对于其他的指令,也是采鼡类似add指令的方式进行替换的

由于O-llvm的开源性,大家如果要使用该产品的功能可以在它的基础上做一些修改。

使用IDA打开混淆后的so文件可轻易的发现该特征。因此我建议事先准备多条可以等价替换的指令,在遇到需要替换的地方时随机的选取其中一条等价指令进行替换。对于basicblock块的划分也可以采用其他规则来进行划分,大家可以脑洞大开多尝试尝试。

Substitution中我们也可以采用其他的等价指令进行替換,这里也不再举例了

前段时间,有人在看雪论坛发布了一篇名为《ollvm的混淆反混淆和定制修改》的文章()大家也可以阅读下该文章,加罙对O-llvm的了解

同时,网易云安全(易盾)也提供和服务

本文来自网易实践者社区,经作者王泽华授权发布

我要回帖

更多关于 libso 的文章

 

随机推荐