一、 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友好地集成。通过编写插件直接集成:
https ://github.com/obfuscator-llvm/obfuscator/wiki/ Installation
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:
http://fuzion24.github.io/android/obfuscation/ndk/llvm/o-llvm/2014/07/27/android-obfuscation-o-llvm-ndk /
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"
};