Android LLVM-Obfuscator C/C++ 混淆编译的深入研究

一、 LLVM是什么?
(1)LLVM是lowlevel virtual machine的简称,是一个编译器框架。苹果公司的Xcode 4.0之后用的都是LLVM编译器。
(2)LLVM 诞生于2003.10伊利诺伊大学香槟分校,创始人ChrisLattner,现任苹果公司『开发者工具』部门的主管。
   
二、 LLVM-Obfuscator 是什么?
(1)LLVM-Obfuscator 是瑞士西北应用科技大学安全实验室针对LLVM编译组件开发的代码混淆工具,该工具完全开源,目的是为了增加逆向工程的难度,保证代码的安全性。
(2)Obfuscator-llvm最新版本集成了LLVM-3.4编译器,并且兼容LLVM支持的所有语言(C,C++, Objective-C, Ada and Fortran)和平台(x86, x86-64, PowerPC, PowerPC-64,ARM, Thumb, SPARC, Alpha, CellSPU, MIPS, MSP430, SystemZ,and XCore)。

1. 混淆方法一: InstructionsSubstitution
-mllvm -sub: activate instructions substitution
-mllvm -funcSUB="func1,func2,func3": if instructions substitution is activated, apply it only on functions func1, func2 and func3
-mllvm -perSUB=20: if instructions substitution is activated, apply it with a probability of 20% on each function
2. 混淆方法二: BogusControlFlow
-mllvm -bcf: activates the bogus control flow pass
-mllvm -funcBCF="func1,func2,func3": if the pass is activated, applies it only on functions func1, func2, func3
-mllvm -perBCF=20: if the pass is activated, applies it on all functions with a probability of 20%. Default: 100
-mllvm -boguscf-loop=3: if the pass is activated, applies it 3 times on a function. Default: 1
-mllvm -boguscf-prob=40: if the pass is activated, a basic bloc will be obfuscated with a probability of 40%. Default: 30
3. 混淆方法三: ControlFlow Flattening
-mllvm -fla: activates control flow flattening
-mllvm -funcFLA="func1,func2,func3": if control flow flattening is activated, apply it only on functions func1, func2 and func3
-mllvm -perFLA=20: if control flow flattening is activated, apply it with a probability of 20% on each function
4. 如何用开源 source code 编译出混淆器O-LLVM ?
$ git clone -b llvm-3.5 https://github.com/obfuscator-llvm/obfuscator.git
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE:String=Release ../obfuscator/
$ make -j5
编译后的结果只有bin 和 lib 是有用的,其余的都可以删除:

三、 LLVM-Obfuscator for iOS: Xcode + Obfuscator
从Xcode-5.0之后苹果就将Clang-LLVM作为Xcode的默认编译器,因此O-llvm也可以与Xcode友好地集成。通过编写插件直接集成:
1.设置使用O-LLVM编译器作为 Xcode 默认编译器
(1)按链接中的指导进行配置:https://github.com/obfuscator-llvm/obfuscator/wiki/Installation ,在Xcode5.1.1和Xcode4.6.3下测试都可以配置成功。
(2)change build options compiler from Default to Obfuscator llvm。
2. 发现第一个编译错误:

(1)原因:可以观察到错误提示,提示有些framework的常量在mac上不可用。明明是build  iOS平台的framework,但却提示在mac上不可用,说明应该是有些编译参数出现了问题。Xcode默认的编译器没有这个问题,所以我猜测可能是Xcode对于自定义的编译器没有做到100%的支持。 
(2)解决问题
-mmacosx-version-min=10.6
-通过对比发现换了编译器之后Xcode的编译命令中多了上述参数
-找到下图的配置:先把OS X Deployment Target改成10.9,编译还是报错。这时将其改回Compiler Default,发现后面没有$(inherited)那一堆东西了。是不是看到了希望?再build,你就会惊奇的发现那个参数不见了,build成功了,原因未知。

-还有一个问题,这个时候Xcode build的target只能是真机,而不能是模拟器。如果是模拟器的话,会产生和之前一样的错误。不过不用担心,工程默认的build active architecture only是NO,所以选真机也会得到适用于真机和模拟器的版本。
3. iOS5 测试失败
-还是对比我们的编译器和Xcode默认编译器的编译参数
-惊奇的发现,Xcode在使用我们的编译器的时候少了一个“-miphoneos-version-min=4.3”参数
-解决办法:需要在Other C Flags处添加相应参数 -miphoneos-version-min=4.3

4.与测试相关的问题
-如果想运行test,需要在目标是ios7 simulator的时候编译通过
-需要把build active architecture only设置成Yes
-需要在Other link flags 里面加上-mios-simulator-version-min=7.0
-此时可以通过command+u 运行test得到有关于效率的CSV文件
5.总结(配置)
-按官方文档将编译器配置到Xcode环境下
-修改SecurityGuardSDK这个Target下, Build Options->Compiler for C/C++/Objective-C 为Obfuscator 3.4
-Deployment->OS X Deployment Target 修改为10.9后修改回Default
-Obfuscator 3.4 – Custom Compiler Flags->Other C Flags添加-miphoneos-version-min=4.3以支持ios5
-完成上述步骤后可以正常编译,生成同时适用于真机和simulator的framework。
-如需加入混淆功能,可以在Other C Flags后继续添加-mllvm –sub,-mllvm –bcf,-mllvm –fla进行混淆。编译出来的framework即为混淆后的版本。
6.总结(测试)
-修改Build Active Architecture Only 为Yes
-Obfuscator 3.4 – Custom Compiler Flags->Other C Flags修改为-mios-simulator-version-min=7.0
-如需加入混淆功能,可以在Other C Flags后继续添加-mllvm –sub,-mllvm –bcf,-mllvm –fla进行混淆。编译出来的framework即为混淆后的版本
-Command+U 即可运行测试
-过程中还发现许多小问题,但是上述方法经测试可用
四、 LLVM-Obfuscator for Android:NDK+Obfuscator
Android: 从NDK-r8d以后(目前最新是r10)就已经在toolchains中集成了Clang-LLVM编译器,因此可以通过修改NDK的配置文件来集成O-llvm:

1. NDK-Build 默认采用GCC编译器。ndk-build 其实就是对GNU Make的封装,它的目的是调用系统NDK编译脚本,它等价于 make -f $NDK/build/core/build-local.mk。
    ndk-build  命令行参数:

2. NDK工具链toolchains组织结构

3. 如何将O-LLVM 集成到NDK 交叉编译工具链中?
(1)对于独立编译方式,先用 make-standalone-toolchain.sh脚本创建 standalone-toolchain, 然后将LLVM-Obfuscator源码编译生成的 /bin 和/lib 拷贝到standalone-toolchain 对应的folder下面。然后利用 android. toolchain.cmake 脚本配置交叉编译环境,然后在shell 脚步中执行编译命令:
cmake -DOS=ANDROID 
      -DANDROID_ABI=armeabi 
      -DANDROID_STANDALONE_TOOLCHAIN=standalon-toolchain 
      -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake .
make -j8
编译错误一直没有解决:(直接放弃集成独立编译方式)
-ld: library not found for –lSystem
-ld:no archive symbol table (run ranlib)
-“-soname” is not supported by LLVM/Clang
(2)对于ndk-build方式, 首先按照NDK 文件结构和命名规则在toolchain folder 下创建obfuscator-llvm, 并将原有的LLVM-3.4 下面的setup.mk, config.mk, setup-common.mk 直接拷贝到obfuscator-llvm 中,不用任何修改。并把源码编译出来的混淆器lib和bin 文件夹(参见上述 “如何用开源 source code 编译出混淆器O-LLVM”),按照 LLVM-3.4 的目录结构 /prebuild/darwin-x86_64 也拷贝到obfuscator-llvm 中。
然后分别创建arm-linux-androideabi-obfuscator, mipsel-linux-android-obfuscator, x86-obfuscator 文件夹,注意命名必须保持一致,只有后缀“obfuscator” 可以变化,其它都不得修改。并把与之对应的arm-linux-androideabi-clang3.4, mipsel-linux-android-clang3.4, x86-clang3.4文件夹下的config.mk和 setup.mk 都拷贝过来,但需要在setup.mk中修改LLVM_NAME, TARGET_CC 和 TARGET_CXX, 其它都不用动。到此就一切OK了。
LLVM_NAME := obfuscator-llvm-3.4
TARGET_CC := $(LLVM_TOOLCHAIN_PREFIX)clang$(HOST_EXEEXT)
TARGET_CXX := $(LLVM_TOOLCHAIN_PREFIX)clang++$(HOST_EXEEXT)

配置好NDK 的ToolChain之后,进行混淆编译只需要在Application.mk中指定编译器名字即可:
NDK_TOOLCHAIN_VERSION := obfuscator
然后在Android.mk 中设置混淆参数
LOCAL_CFLAGS += -mllvm -sub -mllvm -bcf -mllvm -fla
最后命令行下直接执行:
$ ndk-build APP_ABI="armeabi armeabi-v7a mips”
已知问题:
-只能编译ARM,MIPS,无法编译x86,编译器编译报错

-__asm__ 内联汇编指令无法编译
-inline 函数无法编译
五、如何解决NDK + LLVM-Obfuscator 无法编译x86的问题?
因为NDK的eabi=x86没有添加到LLVM-Obfuscator中, 导致在link的时候使用来系统的默认linker,从而报错。
使用下面的patch之后,重新编译LLVM-Obfuscator的源码,生成的混淆编译器可以支持arm/arm64, x86/x86_64和 mipsel (注: mips64会有异常linking mips:isa64 module with previous mips:isa64r6, 估计是clang产生的指令和linker要求的不一样)。
在 obfuscator/tools/clang/lib/Driver/ToolChains.cpp文件中,从1112行开始按下面的(“-”删除一行)(“+”增加一行)修改文件:
@@ -1112,30 +1112,35 @@ 
void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
   // lifetime or initialization issues.
   static const char *const AArch64LibDirs[] = { "/lib" };
   static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu",
-                                                "aarch64-linux-gnu" };
+                                                "aarch64-linux-gnu",
+                                                "aarch64-linux-android"
+  };
 
   static const char *const ARMLibDirs[] = { "/lib" };
   static const char *const ARMTriples[] = { "arm-linux-gnueabi",
                                             "arm-linux-androideabi" };
   static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf",
+                                              "arm-linux-androideabihf",
                                               "armv7hl-redhat-linux-gnueabi" };
 
   static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
   static const char *const X86_64Triples[] = {
     "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu",
     "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux",
-    "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux"
+    "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux",
+    "x86_64-linux-android"
   };
   static const char *const X86LibDirs[] = { "/lib32", "/lib" };
   static const char *const X86Triples[] = {
     "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu",
     "i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux",
     "i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux",
-    "i686-montavista-linux"
+    "i686-montavista-linux", "i686-linux-android"
   };
 
   static const char *const MIPSLibDirs[] = { "/lib" };
   static const char *const MIPSTriples[] = { "mips-linux-gnu",
+                                             "mips-linux-android",
                                              "mips-mti-linux-gnu" };
   static const char *const MIPSELLibDirs[] = { "/lib" };
   static const char *const MIPSELTriples[] = { "mipsel-linux-gnu",
@@ -1143,23 +1148,28 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
 
   static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" };
   static const char *const MIPS64Triples[] = { "mips64-linux-gnu",
+                                               "mips64-linux-android",
                                                "mips-mti-linux-gnu" };
   static const char *const MIPS64ELLibDirs[] = { "/lib64", "/lib" };
   static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu",
-                                                 "mips-mti-linux-gnu" };
+                                                 "mips-mti-linux-gnu",
+                                                 "mips64el-linux-android"
+  };
 
   static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
   static const char *const PPCTriples[] = {
     "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
-    "powerpc-suse-linux", "powerpc-montavista-linuxspe"
+    "powerpc-suse-linux", "powerpc-montavista-linuxspe", "powerpc-linux-android"
   };
   static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
   static const char *const PPC64Triples[] = { "powerpc64-linux-gnu",
+                                              "powerpc64-linux-android",
                                               "powerpc64-unknown-linux-gnu",
                                               "powerpc64-suse-linux",
                                               "ppc64-redhat-linux" };
   static const char *const PPC64LELibDirs[] = { "/lib64", "/lib" };
   static const char *const PPC64LETriples[] = { "powerpc64le-linux-gnu",
+                                                "powerpc64le-linux-android",
                                                 "powerpc64le-unknown-linux-gnu",
                                                 "powerpc64le-suse-linux",
                                                 "ppc64le-redhat-linux" };
@@ -1167,7 +1177,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
   static const char *const SystemZLibDirs[] = { "/lib64", "/lib" };
   static const char *const SystemZTriples[] = {
     "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
-    "s390x-suse-linux", "s390x-redhat-linux"
+    "s390x-suse-linux", "s390x-redhat-linux", "s390x-linux-android"
   };
 


  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
这些都是 Android NDK 内部的 `Android.mk` 文件。其中,`./android-ndk-r25c/sources/android/native_app_glue/Android.mk` 是用于编译 Native Activity 示例应用程序的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/support/Android.mk` 是包含一些 Android 支持库的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/ndk_helper/Android.mk` 是包含一些辅助函数和类的 `Android.mk` 文件;`./android-ndk-r25c/sources/android/cpufeatures/Android.mk` 是用于编译 `cpufeatures` 库的 `Android.mk` 文件,该库提供了一些 CPU 相关的信息和功能;`./android-ndk-r25c/sources/cxx-stl/llvm-libc++abi/Android.mk` 和 `./android-ndk-r25c/sources/cxx-stl/llvm-libc++/Android.mk` 是用于编译 C++ STL 库的 `Android.mk` 文件,分别对应 libc++abi 和 libc++ 两个 STL 库;`./android-ndk-r25c/sources/third_party/googletest/Android.mk` 是用于编译 Google Test 测试框架的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/Android.mk` 是用于编译 Shaderc 编译器的 `Android.mk` 文件,该编译器可以将 GLSL 代码编译成 SPIR-V 代码;`./android-ndk-r25c/sources/third_party/shaderc/libshaderc/Android.mk` 是用于编译 Shaderc 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/libshaderc_util/Android.mk` 是用于编译 Shaderc Util 库的 `Android.mk` 文件,该库提供了一些辅助函数和类;`./android-ndk-r25c/sources/third_party/shaderc/third_party/Android.mk` 是用于编译 Shaderc 编译器依赖的第三方库的 `Android.mk` 文件,包括 glslang 和 spirv-tools 两个库;`./android-ndk-r25c/sources/third_party/shaderc/third_party/glslang/Android.mk` 是用于编译 glslang 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/shaderc/third_party/spirv-tools/Android.mk` 是用于编译 spirv-tools 库的 `Android.mk` 文件;`./android-ndk-r25c/sources/third_party/vulkan/src/build-android/jni/Android.mk` 是用于编译 Vulkan 库的 `Android.mk` 文件。 如果您要在 Android NDK 中编写自己的 `Android.mk` 文件,可以参考这些示例文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值