【技术分享】为OLLVM添加字符串混淆功能

http://p5.qhimg.com/t019b5df46c4539a729.png

本文简单介绍了下使用上海交大GoSSIP小组开源的“孤挺花”混淆框架来给OLLVM加上字符串混淆的功能。


0x01 OLLVM 4.0

OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个针对LLVM代码混淆项目,主要作用是增加逆向难度,从而一定程度上保护代码的安全。因为后期转向了商业项目strong.protect,所以项目的进度一度停滞,而在17年3月,LLVM已经更新到了4.0版本,新版本的一些特性导致老版本的OLLVM存在一定的局限性。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

几天前,上海交大密码与计算机安全实验室GoSSIP小组开源了他们设计的基于LLVM 4.0的孤挺花混淆框架,功能包含字符串加密,控制流扁平化和指令替换。出于稳定性考虑,目前开源的代码仅包括对编译源代码中的常量字符串加密一项基本功能(相关简介)。给上海交大的同学点赞 : )

YSRC简单的做了下分析,发现该功能主要是实现了一个用于字符串加密的pass,具体什么是pass,可以参考如下文章( ,),本文主要介绍将孤挺花的字符串加密pass集成到OLLVM 4.0中。(官方分支暂时还未支持Constants encryption)


0x02 pass集成

字符串加密的pass位于如下目录

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

提取出该文件,放到OLLVM相同目录下,并将头文件也复制到对应目录下

在Obfuscation下的cmakelists.txt将StringObfuscation.cpp添加到编译库中,最后只需要在Transforms/IPO下的PassManagerBuilder.cpp将字符串加密的编译选项添加进去即可

1. 添加#include “llvm/Transforms/Obfuscation/StringObfuscation.h”引用

2. 在合适的地方插入以下两条函数声明,即编译时的编译参数-mllvm -sobf: 

3. 在PassManagerBuilder::PassManagerBuilder()构造函数中添加随机数因子的初始化

static cl::opt<std::string> Seed("seed", cl::init(""), cl::desc("seed for the random")); static cl::opt<bool> StringObf("sobf", cl::init(false), cl::desc("Enable the string obfuscation"));

4. 最后将该pass添加进void PassManagerBuilder::populateModulePassManager中即可

0x03 Windows下编译OLLVM

这里编译环境选择的是windows,其它平台类似 

编译器:

MinGW64 for Windows

Cmake 3.9 rc5 for Windows x64

这里注意下套件都是选择的64位版本的,并且要注意最好清除下系统变量中之前配置的变量。

官方编译命令:

git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git

mkdir build

cd build

cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/

make -j7

如果cmake如果不指定参数的话,会默认去选择当前电脑里已有的编译器,如果安装了vs的话,会自动去查找vs的编译器

如果打算使用vs编译 

cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/ 

会生成32位的依赖版本 

cmake -G “Visual Studio 15 2017 Win64” -DCMAKE_BUILD_TYPE=Release ../obfuscator/ 

上面这种方法就会生成64位版本的编译环境,不过在测试编译时,32位正常编译通过,64位踩了很多坑,所以还是不建议使用vs编译。

使用MinGw编译时,需要加上参数 

cmake -G “MinGW Makefiles” -DCMAKE_BUILD_TYPE=Release ../obfuscator/ 

最后再执行make -j7 即可,数字可根据电脑配置进行选择,编译完成后,会在build/bin下看到编译完成的二进制文件。

0x04 NDK使用OLLVM

将编译好的clang.exe , clang++.exe 以及上级目录下 lib/clang下的文件夹拷贝出来,我这里使用的是ndk 13,直接将这些文件拷贝到toolchainsllvmprebuiltwindows-x86_64,其中exe文件复制到bin目录下,lib文件夹直接复制到windows-x86_64目录下即可。

新建一个Android Studio工程测试下效果,开启字符串加密编译选项

编写测试函数

在函数前添加了fla属性,该属性代表ollvm的Control Flow Flattening ,具体可见ollvm项目的wiki,编译运行查看结果。

使用IDA打开编译后的so文件,可以看到函数中的字符串已经不显示了,

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

而Test函数的流程也被进行了混淆。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

F5后:

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=


0x05 总结

在项目中合理的使用ollvm可以帮助增加逆向难度,并且针对关键的函数混淆对性能的影响也比较小。

(完)