JNI和NDK开发(5)_使用Obfuscator-LLVM混淆JNI代码

版权声明:本博客主要记录学习笔记和遇到的一些问题解决方案,转载请注明出处! https://blog.csdn.net/u010982507/article/details/87927042

什么是LLVM

LLVMlow level virtual machine的简称,其实是一个编译器框架。llvm随着这个项目的不断的发展,已经无法完全的代表这个项目了,只是这种叫法一直延续下来。
llvm是一个开源的项目。它最早的时候是Illinois的一个研究项目,主要负责人是Chris Lattner,他现在就职于Apple. Apple 目前也是llvm项目的主要赞助者之一。
llvm的主要作用是它可以作为多种语言的后端,它可以提供可编程语言无关的优化和针对很多种CPU的代码生成功能。此外llvm目前已经不仅仅是个编程框架,它目前还包含了很多的子项目,比如最具盛名的clang.
llvm的优点是开源,有一个表达形式很好的IR语言,模块化作的特别好。
llvm这个框架目前已经有基于这个框架的大量的工具可以使用。
llvm的官方网站地址是:llvm.org。在这里可以下载最新的发布代码,也可以找到介绍llvm的相关文档
摘自:https://blog.csdn.net/snsn1984/article/details/8036032

Obfuscator-LLVM介绍

OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个针对LLVM代码混淆项目,主要作用是增加逆向难度,从而一定程度上保护代码的安全。因为后期转向了商业项目strong.protect,所以项目的进度一度停滞,而在17年3月,LLVM已经更新到了4.0版本,新版本的一些特性导致老版本的OLLVM存在一定的局限性。
github仓库最新版本:https://github.com/obfuscator-llvm/obfuscator/tree/llvm-4.0
摘自:https://baijiahao.baidu.com/s?id=1572199238543099&wfr=spider&for=pc

运行环境

运行环境:我使用的是Mac笔记本,其实跟Linux差不多。
IDE:Android Studio 3.1.2
Android SDK版本:

compileSdkVersion 26
buildToolsVersion '26.0.2'

NDK版本:android-ndk-r16b
我查了网上很多使用NDK 10的资料,有些老旧,NDK 16这个版本虽然不是最新,但是用着问题不多。

搭建环境

  • 安装CMake
    CMake是一个比make更高级的跨平台的安装、编译、配置工具,可以用简单的语句来描述所有平台的安装(编译过程)。并根据不同平台、不同的编译器,生成相应的Makefile或者project文件。
    1、下载CMake官网:https://cmake.org/download/
    在这里插入图片描述
    下载图中标注的cmake-3.14.0-rc3-Darwin-x86_64.dmg安装文件,在Mac上安装即可。
    2、配置CMake环境变量
    安装完成后,点击CMake图标打开,会弹出提示,选择打开即可。
    在这里插入图片描述
    选择左上角Tools,打开How to Install For Command Line Use
    在这里插入图片描述
    会弹出配置环境的提示框,如下图所示:
    在这里插入图片描述
    使用命令:PATH="/Applications/CMake.app/Contents/bin":"$PATH"执行完之后执行cmake -version会在当前命令行窗口生效,新打开一个窗口就不识别这个命令,所以还要执行sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install
    这样就配置好了camke环境。
    参考这篇文章:https://blog.csdn.net/baimafujinji/article/details/78588488

编译obfuscator-llvm源码

1、从https://github.com/obfuscator-llvm/obfuscator/tree/llvm-4.0下载最新代码,这个分支下有好几个版本。
在这里插入图片描述
我下载的是4.0版本,下载完成后解压即可,git clone会有点慢,所以我直接把压缩包下载下来了。解压后在同级目录创建build目录。
在这里插入图片描述
2、下面就是编译源码的过程了,是重点:

  • 进入build目录,cd build
  • 编译源码cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator-llvm-4.0/,后面的是目录名,网上文章一般是cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/,所以后面你的目录是什么就执行什么命令。这个编译很快,控制台会出现很多not found,这都不影响下一步操作。
  • 最后执行命令make -j7,这个过程会有点久,控制台会显示执行进度,大约15分钟到30分钟。

3、编译完成后会生成obfuscator-llvm的编译源码,在build目录下,我们只需要复制binlib目录即可。
在这里插入图片描述
4、配置ndk的llvm
build下的binlib复制到ndk下的/android-ndk-r16b/toolchains/llvm/prebuilt/darwin-x86_64目录中替换覆盖。
到这obfuscator-llvm源码编译与配置就完事了。

混淆JNI代码

1、新建LLVMDemo带JNI的工程,如果不了解JNI开发的可以先看下文章:https://blog.csdn.net/u010982507/article/details/85345985
2、配置CMakeLists.txt文件

cmake_minimum_required(VERSION 3.4.1)
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
find_library( log-lib log )
# 源码编译混淆配置
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mllvm -fla -mllvm -bcf -mllvm -sub")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mllvm -fla -mllvm -bcf -mllvm -sub")

target_link_libraries( native-lib ${log-lib} )

3、配置指令介绍

  • release环境
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mllvm -fla -mllvm -bcf -mllvm -sub")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mllvm -fla -mllvm -bcf -mllvm -sub")
  • debug环境
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mllvm -fla -mllvm -bcf -mllvm -sub")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mllvm -fla -mllvm -bcf -mllvm -sub")
  • -fla 控制流扁平化的PASS参数
  • -sub指令替换的PASS参数
  • -bcf虚假控制流的PASS参数

效果对比

1、源码

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring

JNICALL
Java_com_rzr_llvm_MainActivity_stringFromJNI (
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    int a = 0;
    int b = 1;
    int c = a + b;
    return env->NewStringUTF(hello.c_str());
}

2、使用IDA查看不混淆so文件

jstring __fastcall Java_com_rzr_llvm_MainActivity_stringFromJNI(JNIEnv *env, jobject a2)
{
  JNIEnv *v2; // r4
  _jstring *v3; // r4
  jstring result; // r0
  std::allocator<char> __a; // [sp+8h] [bp-1Ch]
  std::basic_string<char,std::char_traits<char>,std::allocator<char> > v6; // [sp+Ch] [bp-18h]
  std::allocator<char> v7; // [sp+14h] [bp-10h]
  int v8; // [sp+18h] [bp-Ch]

  v2 = env;
  std::string::string(&v6, "Hello from C++", &__a);
  v3 = (_jstring *)((int (__fastcall *)(JNIEnv *, unsigned __int8 *))v2->functions->NewStringUTF)(
                     v2,
                     v6._M_dataplus._M_p);
  std::string::_Rep::_M_dispose(
    (std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Rep *const )v6._M_dataplus._M_p - 1,
    &v7);
  result = (jstring)(_stack_chk_guard - v8);
  if ( _stack_chk_guard == v8 )
    result = v3;
  return result;
}

3、使用IDA查看混淆后so文件

扫描二维码关注公众号,回复: 6530492 查看本文章
int __fastcall Java_com_rzr_llvm_MainActivity_stringFromJNI(int a1)
{
  signed int v1; // r0
  signed int v2; // r2
  signed int v3; // r0
  signed int v4; // r2
  signed int v5; // r2
  signed int v6; // r3
  int v7; // r3
  int v8; // r2
  int *v9; // r5
  int v10; // r1
  int v11; // r4
  int result; // r0
  signed int v13; // [sp-1Ch] [bp-5Ch]
  int v14; // [sp-18h] [bp-58h]
  int v15; // [sp-10h] [bp-50h]
  signed int v16; // [sp-4h] [bp-44h]
  int *v17; // [sp+4h] [bp-3Ch]
  int v18; // [sp+8h] [bp-38h]
  int v19; // [sp+Ch] [bp-34h]
  int *v20; // [sp+10h] [bp-30h]
  int v21; // [sp+14h] [bp-2Ch]
  int *v22; // [sp+18h] [bp-28h]
  int v23; // [sp+1Ch] [bp-24h]
  int v24; // [sp+20h] [bp-20h]
  int v25; // [sp+24h] [bp-1Ch]
  int v26; // [sp+28h] [bp-18h]

  v18 = a1;
  v17 = &v25;
  v1 = 1;
  v16 = 1;
  v2 = 1;
  if ( y >= 10 )
  {
    v16 = 0;
    v2 = 0;
  }
  if ( (~((x - 1) * x) | 0xFFFFFFFE) != -1 )
  {
    v16 = 0;
    v1 = 0;
  }
  v16 = v2;
  v23 = -1;
  if ( !(v2 & v1) && (v2 ^ v1) != 1 )
    goto LABEL_13;
  while ( 1 )
  {
    v20 = &v14;
    __gnu_cxx::new_allocator<char>::new_allocator();
    v13 = 1;
    v3 = 1;
    if ( y <= 9 )
    {
      v13 = 0;
      v3 = 0;
    }
    v22 = &v15;
    v24 = 1;
    v21 = -v23;
    v13 = 1;
    v4 = 1;
    if ( !((v23 | 0x3364DB48) & (((x + v23) * x ^ v23 | v23 ^ 1) ^ v23)) )
    {
      v13 = 0;
      v4 = 0;
    }
    v13 = v3;
    if ( v3 != v4 || ((v3 | v4) ^ 1) == 1 )
      break;
LABEL_13:
    __gnu_cxx::new_allocator<char>::new_allocator();
  }
  sub_77B4(v22, "Hello from C++", v20);
  v20 = (int *)y;
  v19 = x;
  do
  {
    v5 = 1;
    v6 = 1;
    if ( (signed int)v20 >= 10 )
      v6 = 0;
    v7 = v6 ^ v24;
    if ( ((v19 - v21) * v19 ^ v23 ^ 1) & (v19 - v21) * v19 )
      v5 = 0;
    v8 = v5 ^ v24;
    v9 = v22;
  }
  while ( v7 == v8 && (((v7 | v8) ^ v24) & v24) != 1 );
  v10 = *v22;
  v11 = (*(int (**)(void))(*(_DWORD *)v18 + 668))();
  sub_6D34(*v9 + v23 - 11, &v26);
  result = _stack_chk_guard - *v17;
  if ( _stack_chk_guard == *v17 )
    result = v11;
  return result;
}

猜你喜欢

转载自blog.csdn.net/u010982507/article/details/87927042