一、引言
在移动应用开发中,应用的安全性越来越受到关注。特别是在Android应用中,SO(Shared Object)文件往往会保存一些需要加密的关键数据,如API密钥、应用密钥等。如果这些重要的信息没有经过适当的混淆和保护,极容易被恶意第三方通过逆向工程手段破解,进而导致一系列安全问题。
对SO文件进行混淆和保护与对Java和Kotlin代码进行混淆一样重要。混淆不仅可以增加破解难度,还可以有效地保护应用内部的核心算法和功能逻辑。本篇文章将探讨如何利用CMake常规方法和开源的OLLVM工具对SO文件进行混淆,以提高应用安全性。同时,我们也将对两种方法的混淆效果进行验证和对比,并探讨如何解决集成过程中的常见问题。
二、常规混淆方法
在对SO文件进行混淆保护时,我们常使用一些配置参数来编译和链接代码,以提升其安全性。以下是一些常用的CMake参数及其功能:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -fvisibility=hidden -fstack-protector-strong -fPIE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fvisibility=hidden -fstack-protector-strong -fPIE")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s -Wl,-z,relro,-z,now -pie")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s -Wl,-z,relro,-z,now -pie")
- -02:
进行较高级别的优化,既能提升代码执行效率,又不会显著增加编译时间。 - -fvisibility=hidden:
将符号默认可见性设为隐藏,避免外部重复定义或滥用内部API。 - -fstack-protector-strong:
防止栈溢出攻击,通过在函数的返回地址前插入保护符。 - -fPIE 和 -pie:
启用位置无关代码,使执行文件在内存中随处可加载,增加攻击难度。 - -s:
去除符号表和重定位信息,减小生成文件的大小。 - -Wl,-z,relro,-z,now:
relro(可重定位读写部分)和 now(完全重定位保护),这些参数进一步加强执行时的安全性。
为了验证这些参数的效果,我们使用IDA(Interactive Disassembler)对未混淆和混淆后的SO文件进行了分析。
未混淆SO文件
在不使用上述参数进行混淆的情况下,我们将生成的SO文件导入到IDA中,如下图所示:
![](https://img.haomeiwen.com/i3413002/0bc4904576dd1eae.png)
可以明显看到字符串和native方法,信息一览无遗,极易被逆向工程人员识别和破解。
使用常规参数混淆后的SO文件
当我们在CMake中添加上述混淆参数后,重新生成SO文件并在IDA中进行查看,发现以下变化:
![](https://img.haomeiwen.com/i3413002/cebb5710a70d7224.png)
尽管SO文件的大小有所减小,但混淆效果并不显著。字符串和native方法仍然容易被识别,代码行数虽然减少,但不足以达到预期的混淆效果。
通过上述比较,我们可以看出单纯依靠这些常规方法进行混淆效果有限。为进一步提高SO文件的混淆效果,我们接下来将介绍一种更为有效的开源工具——OLLVM。
三、OLLVM介绍
OLLVM(Obfuscator with LLVM)是基于LLVM(Low Level Virtual Machine)的一个开源混淆器。它通过对程序代码进行变形和混淆,使得逆向工程变得更加困难,从而显著增强了程序的安全性和保护机制。相比于传统的混淆方法,OLLVM提供了一些高级的混淆技术,使其成为保护SO文件的重要工具。
OLLVM的主要功能包括:
-
控制流扁平化(-mllvm -fla):通过扁平化控制流,使代码的执行路径变得复杂且难以理解,从而增加逆向工程的难度。
-
指令替换(-mllvm -sub):用等效但不同的指令序列替换原有指令,增加代码阅读和分析的复杂度。
-
虚假控制流程(-mllvm -bcf):在代码中插入虚假的控制流和逻辑,使得代码看起来混乱且难以推理。
-
字符串加密(-mllvm -sobf):对字符串进行加密处理,防止字符串在二进制文件中被轻易识别和解析。
通过结合使用这些功能,OLLVM能够大幅提升SO文件的防护能力,使其更加难以被破解。接下来,我们将深入探讨如何使用OLLVM对SO文件进行混淆,并验证其效果。
四、使用OLLVM进行混淆
接下来我们将介绍如何使用OLLVM对SO文件进行混淆,包括下载、编译、配置并验证其效果。
- 下载和编译OLLVM
首先,从GitHub下载OLLVM的源码,并进行编译:
$ git clone -b llvm-9.0.1 https://github.com/heroims/obfuscator
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON ../obfuscator/
$ make -j7
- 配置OLLVM
编译完成后,将生成的build/bin目录拷贝到Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/bin,并替换原有的bin文件夹(注意:是替换,而不是覆盖)。具体步骤如下:
$ cp -r build/bin /path/to/Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/
- 解决编译报错
在使用OLLVM进行编译时,可能会遇到缺少头文件的问题。根据提示信息,拷贝缺少的头文件到相应目录中。通常需要从build/lib/clang/9.0.0/include/目录复制以下文件:
stdarg.h
stddef.h
_stddef_max_align_t.h
float.h
stdbool.h
将以上文件复制到ndk目录/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include文件夹下。不同的NDK版本可能会有不同的头文件需求,请根据具体错误提示进行操作。
完成这些步骤后,OLLVM已经配置完毕。接下来,在Android Studio中选择Build --> Refresh Linked C++ Projects,然后再次运行程序,验证编译是否通过。
- 在CMakeLists.txt中应用OLLVM混淆配置
在CMakeLists.txt文件中增加以下配置,用以应用OLLVM的混淆功能:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mllvm -sub -mllvm -sobf -mllvm -fla -mllvm -bcf")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -sub -mllvm -sobf -mllvm -fla -mllvm -bcf")
这些参数分别启用了OLLVM的指令替换、字符串加密、控制流扁平化和虚假控制流程功能。
-
混淆效果验证
混淆后的SO文件在IDA中查看效果如下图所示:
1723777310240.png
可以看出,代码结构变得更加复杂,明文字符串也被加密,显著提升了代码的混淆效果和安全性。
五、结合使用OLLVM和常规混淆方法
虽然使用OLLVM进行混淆显著提高了SO文件的安全性,但我们发现包的大小却大幅增加。经过混淆处理后,SO文件的大小从原先的210KB增长到了1.2MB,这对应用的整体性能和分发带来了不小的负担。
为了解决包大小的问题,可以结合使用OLLVM和常规的混淆配置。具体的CMake配置如下所示:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -fvisibility=hidden -fstack-protector-strong -fPIE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fvisibility=hidden -fstack-protector-strong -fPIE")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s -Wl,-z,relro,-z,now -pie")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s -Wl,-z,relro,-z,now -pie")
这些配置参数的功能在前文已经进行详细介绍,应用它们不仅有助于提升代码的可读性和安全性,还能减少最终生成的SO文件的大小。
通过重新编译,我们发现SO文件的包大小问题得到了明显改善。最终生成的SO文件不仅保留了OLLVM带来的高级混淆效果,同时也得到了合理的优化和压缩,大小回到了较为理想的范围。
六、结论
通过本文的探讨,我们了解了如何使用OLLVM和常规方法对Android SO文件进行混淆和保护。常规方法易于配置,且对包大小控制良好,但混淆效果有限。OLLVM则提供了更高级的混淆技术,显著提升安全性,但会导致包大小增加。
结合使用OLLVM和常规混淆方法,可以同时实现强大的混淆效果和适当的包大小控制。这种组合方式,不仅提升了代码的安全性和复杂性,还保持了应用的整体性能。通过这些方法,Android应用可以更好地抵御逆向工程和恶意攻击,从而提高整体安全性。
网友评论