O-MVLL:支持ARM64的基于LLVM的代码混淆模块

铁佛  金牌会员 | 2022-11-22 12:55:46 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 540|帖子 540|积分 1620

O-MVLL介绍

O-MVLL的开发灵感来自于另一个著名的基于LLVM的代码混淆项目ollvm,并在其基础上做了创新和改进。O-MVLL的混淆逻辑实现方式也是通过LLVM Pass,支持也仅会支持ARM64架构,根据作者所说,这是由于当初的设计选择。此外,作者还使用了pybind11,用户可以使用python脚本来对O-MVLL进行配置,从而灵活的运用作者封装好的各种代码混淆方式。
混淆后的可执行文件相比于正常编译的可执行文件来说,抵抗逆向工程的能力增强,但与源代码的功能相同,能够在一定程度上保护源代码和程序,增加逆向工程的分析成本。
作者的介绍文档: O-MVLL Documentation (obfuscator.re)
开源项目github地址: GitHub - open-obfuscator/o-mvll: O-MVLL is a LLVM-based obfuscator for native code (Android & iOS)
作者的工作邮箱: ping@obfuscator.re(可以向他提交bug和issues,也可以问他一些项目的问题,回复很快,赞)
目前项目包含了7种代码混淆方式,它们分别是:Anti-Hooking,Arithmetic Obfuscation,Control-Flow Breaking,Control-Flow Flattening,Opaque Constants,Opaque Fields Access Strings Encoding。它们的实现细节分析见下一篇随笔。
 
项目编译安装

编译方式可见作者的介绍文档中,Compilation一栏。作者提供了Linux、macOS两个平台的编译方式,并且提供了docker file。这里简单介绍下使用docker 的编译安装方式
拉取docker镜像并下载依赖
  1. $ docker pull openobfuscator/omvll-ndk
  2. $ git clone https://github.com/open-obfuscator/o-mvll.git
  3. $ curl -LO https://data.romainthomas.fr/omvll-deps-ndk-r25.tar
  4. $ mkdir -p ./third-party
  5. $ tar xvf omvll-deps-ndk-r25.tar -C ./third-party
  6. $ docker run -it openobfuscator/omvll-ndk
复制代码
进入docker容器内部,将下载的依赖和文件复制过来
  1. $ docker cp ./third-party $你的容器id:/
  2. $ docker cp ./o-mvll $你的容器id:/
复制代码
之后给予文件运行权限并运行
  1. $ chmod +x /o-mvll/scripts/docker/ndk_r25_compile.sh
  2. $ sh /o-mvll/scripts/docker/ndk_r25_compile.sh
复制代码
此时完成整个项目的构建。
下载Clang from NDK

项目构建完成后,需要使用ndk的clang来调用该项目作为编译过程中的插件,因此还需要安装ndk clang,可以在此处下载:NDK 下载  |  Android NDK  |  Android Developers (google.cn)
选择Linux64位的下载,解压后复制到docker容器中,解压后的文件夹中的toolchains/llvm/prebuilt/linux-x86_x64/bin中包含有ndk所使用的clang,为了方便调用,可以将该路径加入到环境变量当中,之后在命令行中使用clang,即表示使用该路径下的ndk的clang。
 
基本使用

现在我们编写了一个文件名为main.c的程序,将要使用O-MVLL对其进行混淆,可以使用如下指令得到一份混淆后的可执行文件main:
  1. $ clang --target=aarch64-linux-android21 -fpass-plugin=libOMVLL.so main.c -o main
复制代码
其中,-fpass-plugin指定的动态链接库即为O-MVLL项目编译出来的文件,其位置应该处于o-mvll/src/build_ndk_r25当中。由于O-MVLL仅支持aarch64,因此还需要使用--target指明目标架构。或者也可以直接使用
  1. $ aarch64-linux-android21-clang -fpass-plugin=libOMVLL.so main.c -o main
复制代码
这样就不用显式地使用target指明目标架构了
配置文件omvll_config.py

之前提到,O-MVLL做出的创新是使用pybind11提供了pythonAPI,以供用户配置代码混淆的方式,因此在执行上述指令之前,需要配置好omvll_config.py文件。
O-MVLL将会尝试在调用clang的目录下寻找该文件,如果找不到该文件,就会报错
  1. ...
  2. error: ModuleNotFoundError: No module named 'omvll_config'
  3. make: *** [Makefile:31: strings.bin] Error 1
复制代码
可以通过环境变量来指明omvll_config.py的路径和文件名,像这样:
export OMVLL_CONFIG=~/project/obfu/config_test.py
这样O-MVLL就会去寻找~/project/obfu/config_test.py作为混淆的配置文件
配置文件中必须要实现一个名为omvll_get_config的函数,和一个继承自omvll.ObfuscationConfig的类,omvll_get_config的返回值必须是这个类才行。
这个函数由pass调用,从而访问用户定义的混淆方案,因为混淆的配置必须是唯一的,因此作者强烈建议使用@functools来包装这个函数:
  1. import omvll
  2. from functools import lru_cache
  3. class MyConfig(omvll.ObfuscationConfig):
  4.     def __init__(self):
  5.         super().__init__()
  6. @lru_cache(maxsize=1)
  7. def omvll_get_config() -> omvll.ObfuscationConfig:
  8.     """
  9.     Return an instance of `ObfuscationConfig` which
  10.     aims at describing the obfuscation scheme
  11.     """
  12.     return MyConfig()
复制代码
现在,我们可以在MyConfig中配置我们的混淆方案了。例如调用字符串混淆时,就需要重写obfuscate_string(self, module: omvll.Module, func: omvll.Function, string: bytes)这个函数。
该函数的输入为继承自llvm:Module的omvll:Modul,继承自llvm:Function的omvll:Fcuntion以及传入的字符串,它会遍历每个模块当中每个函数中调用的字符串。当函数的返回值为true或者某个字符串时,启动字符串混淆
  1. class MyConfig(omvll.ObfuscationConfig):
  2.     def __init__(self):
  3.         super().__init__()
  4.     def obfuscate_string(self, module: omvll.Module, func: omvll.Function,
  5.                                string: bytes):
  6.         if func.name == "hello":
  7.             return True
  8.         if b"debug.cpp" in string:
  9.             return "<REMOVED>"
  10.         return False
复制代码
上述配置,就会将函数名为hello的函数中的字符串进行加密,并且将程序中包含debug.cpp的字符串替换为
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

铁佛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表