安卓 APK/AAB 保护最佳实践
#
安卓应用的安全性问题#
二次打包风险安卓原生应用一般使用 Java/Kotlin 语言编写,编译打包后生成Dex文件存放在APK中。Dex文件包含了类、方法、成员等信息,甚至包含了源文件名,使用jadx/jd-gui等工具可以轻松反编译出源代码。代码被反编译后,可以很容易使用apktool等工具修改代码,破解应用或者植入广告,再重新打包发布。
#
代码和资源易被窃取由于Dex文件可以完整地反编译出源代码,未经保护的代码发布后与开源无异,可能会被竞争对手无成本地直接窃取使用,包内的音视频和图片等资源文件也容易被直接窃取使用,严重损害开发者利益。
#
Virbox Protector功能介绍Virbox Protector对APK和AAB程序提供了运行时自保护、防逆向、防篡改、代码和资源加密等功能,全方位保护APK和AAB程序。
#
运行时自保护运行时自保护,是在应用启动和运行时保护自身,防止应用被恶意调试分析、动态注入,防止在一些开启了高权限的自定义设备或模拟器中运行,进而破解应用程序的行为。
功能 | 描述 |
---|---|
调试器检测 | 防止应用被 IDA Pro,gdb,lldb,jeb 等工具调试,检测到被调试后退出。 |
反注入 | 防止应用被 ptrace 附加,so 库注入,检测 xposed 等 hook 框架。 |
内存保护 | 防止其他进程(比如frida)通过内存进行hook进而读写内存。 |
模拟器检测 | 检测到应用在模拟器中运行时退出。 |
Root 检测 | 检测到应用在 Root 环境下运行时退出。 |
多开检测 | 检测到应用多开(分身)时退出。 |
代理检测 | 检测到APP使用代理时程序退出,防止抓包。 |
vpn检测 | 检测当前环境开启VPN时程序退出。 |
#
防逆向防止应用中的 Dex、SO库、脚本语言代码被反编译或窃取,防止逆向分析。
功能 | 描述 |
---|---|
Dex 加密 | 加密并隐藏 APK 中的所有 Dex 文件,防止 jadx, jeb 等工具反编译。 |
Dex 虚拟化 | 对指定的 Dex 中的方法进行虚拟化保护,将代码转换成自定义的 Native 层虚拟机中执行,可以防止一切内存截取方式还原代码。 |
字符串加密 | 加密Dex文件中所有 Java 方法引用的字符串。 |
资源加密 | 加密 apk 中的资源、脚本等文件,防止资源被提取。 |
SO 库保护 | 对 apk 中指定的 so 库保护,加密代码段,防止 IDA Pro 等工具反汇编、反编译。 |
SO 库保护(隐藏符号表) | 隐藏 SO 库中的导出函数、加密 SO 库中的 ELF 重定位,防止脱壳。 |
Dex 虚拟化效果
保护前:
保护后:
保护后跳转到自定义的解释器中执行(见上图 vm_void 方法)。
#
防篡改运行时校验代码及应用的完整性,防止应用被篡改,防止二次打包。
功能 | 描述 |
---|---|
签名校验 | 校验 APK 中的开发者签名,防止 APK 被第三方二次打包重签名。 |
文件校验 | 校验 APK 中的资源、脚本、SO 库等文件,防止 APK 中的文件被篡改进行二次打包。 |
#
支持范围#
操作系统和架构兼容性- 支持 Android 4.0 以上系统
- 支持 arm32/arm64/x86/x64 架构
#
保护指引#
保护前的准备#
JDK配置对APK/AAB签名,需要用到jdk中的 jarsigner
工具(位于jdk bin目录)和 java
命令,Windows平台需要将jdk的 bin目录加入环境变量,Linux/macOS 一般安装jdk后即可直接调用。
配置完毕后,在命令行终端下输入 jarsigner
即可验证环境是否生效。
#
生成 Keystore如果开发者尚未生成 Keystore,可以安装 jdk 后手动生成,生成命令如下:
keytool -genkeypair -keyalg RSA -keysize 1024 -sigalg SHA256withRSA -validity <validity_days> -alias <key_alias> -storepass <ks_pass> -keystore <keystore_path>
生成Keystore需要记录KeyStore路径
,KeyStore密钥
,密钥别名
,别名密码
,在保护过程中的签名设置
里需要填写。
举例:
# -validity :有效期天数,这里随便填写个足够长的数据即可# -keystore :KeyStore路径# -storepass :KeyStore密码# -alias :密钥别名# (别名密码可以在执行命令后的交互提示中填写)
keytool -genkeypair -keyalg RSA -keysize 1024 -sigalg SHA256withRSA -validity 500000 -alias MyCert -storepass MyCert.jks
#
反编译工具推荐反编译工具可以用于保护效果的评估。
对于APK中的 Java/Kotlin代码部分,推荐使用免费开源 Jadx:
Jadx 下载地址: Releases · skylot/jadx · GitHub
对 APK包的中 Native库,推荐使用 IDA Pro(收费),或 Ghidra(免费开源):
Ghidra 下载地址: Releases · NationalSecurityAgency/ghidra (github.com)
#
常规的保护方式Virbox Protector 的默认选项,可以防止程序被反编译、防资源窃取、防脱壳、防逆向、防二次打包等。一般可以满足大部分的安全性需求,以下是APK和AAB程序的保护选项和推荐。
功能 | 保护建议 | 保护效果 |
---|---|---|
Dex 加密 | 勾选 | 加密隐藏Dex文件,防止反编译 |
文件校验 | 勾选 | 校验APK包内除签名信息外的所有文件,防止被篡改 |
签名校验 | APK格式勾选;AAB格式如果由Google管理证书请勿勾选 | 校验开发者签名,防止被第三方重签名打包 |
反注入 | 勾选 | 防止内存Dump,防止调试器附加 |
调试器检测 | 勾选 | 检测到调试器调试,则退出进程 |
模拟器检测 | 按需选择 | 检测到运行环境为模拟器,则退出进程 |
Root检测 | 按需选择 | 检测到运行环境为Root环境,则退出进程 |
多开检测 | 按需选择 | 检测到运行环境为手机分身或应用分身,则退出进程 |
[V] 代码虚拟化 |
函数选项
Virbox Protector 默认会将入口Application和Activity类中的方法虚拟化,防止代码被还原脱壳,建议使用默认。
资源加密
1.按需选择是否启动资源加密;
2.设置资源密码后,默认开启"数据存储加密"功能,自动保护/data/data/***/shared_prefs/目录下的xml文件。
注:开发者用SharePreferences存储数据一般是对键值和键名进行加密存储,一般过检测的应用需要保护这些文件。
SO库保护
1.按需选择是否保护,保护后可以防止反编译;
2.隐藏符号表,可默认对so库的导入和导出符号进行隐藏;
注意:若so库中使用SoLoader Framework框架,则勾选隐藏符号表
后保护日志中提示不支持。
#
自定义虚拟化Virbox Protector 会默认对App 入口类和Activity类虚拟化保护,也支持自由选择类方法进行虚拟化保护,保护关键代码逻辑,用于应对高安全性的保护场景。
代码虚拟化,是将函数原本的汇编指令,转换自定义的虚拟机指令。函数被虚拟化保护后,运行时内存中不会出现原始字节码,而是以伪代码的形式出现,由自定义的解释器解释执行,安全性极高。如果一个加密方案可以逼迫破解者去分析虚拟化的代码,说明这个方案是非常成功的,需要分析的代码(破解点)越多,破解的难度就越大
。
代码虚拟化对程序的性能影响较大,不可大面积使用,常用于以下几类函数:
- 对安全性要求较高的一些自定义算法。
- 可能被篡改或者逆向的函数(如关键的授权验证逻辑、协议封装加密逻辑)。
#
自动化集成#
命令行工具Virbox Protector
的命令行工具 virboxprotector_con
的默认路径位于:
Windows:C:\Program Files\senseshield\Virbox Protector 3\bin
Linux:/usr/share/virboxprotector/bin
macOS:/Applications/Virbox Protector 3.app/Contents/MacOS/bin
#
使用配置文件保护使用工具界面进行保护,在被保护的程序旁边会生成 .ssp
文件,然后调用virboxprotector_con
:
virboxprotector_con <input_file> -o <output_file>
virboxprotector_con
会自动查找 <input_file>.ssp 作为配置文件开始保护。
#
无配置文件保护如果没有配置文件,virboxprotector_con
会使用默认参数保护,可以传入具体参数覆盖默认选项,参考命令行选项。
#
命令行选项#
保护选项选项 | 命令行 | 默认选项 |
---|---|---|
Dex 加密 | --dex-enc= | APK:1 , AAB:0 |
字符串加密 | --str-enc= | 0 |
文件校验 | --file-check= | 1 |
签名校验(APK) | --sign-check= | 0 |
反注入 | --anti-inject= | 1 |
内存保护 | --mem-protect= | 0 |
防截屏 | --anti-screenshot= | 0 |
调试器检测 | --detect-dbg= | 1 |
模拟器检测 | --detect-emu= | 0 |
Root检测 | --detect-root= | 0 |
多开检测 | --detect-multi= | 0 |
代理检测 | --detect-proxy= | 0 |
VPN检测 | --detect-vpn= | 0 |
输出 apks (AAB启用签名时生效) | --apks=<apks_path> | N/A |
#
函数选项选项 | 命令行 |
---|---|
代码虚拟化 | -v |
支持指定函数名称或规则保护,使用 ;
号隔开,支持通配符 *
,举例:
-v "class1.method2;class2.*"
#
资源加密使用 --res-enc=1
开启资源加密,资源列表使用 ;
隔开,支持通配符 *
。
选项 | 命令行 | 默认选项 |
---|---|---|
启用 | --res-enc= | 0 |
资源列表 | -res <resource_list> | 默认只支持assets和res/layout目录下的资源 |
移除不保护的资源文件 | --exclude-res=<exclude_list> | N/A |
举例:
保护指定的资源:--res-enc=1 -res "file1;file2;assets/file1;assets2/*"保护支持的所有资源:--res-enc=1 -res "*"
场景示例:
1.若res目录的资源混淆过
1)保护res/layout目录下所有的资源文件,命令参考如下
virboxprotector_con app-release.apk --filter-res=0 --res-enc=1 -res "@layout/*"
2)保护res目录下指定文件,文件路径需要以加壳工具界面显示的路径为准,命令参考如下
virboxprotector_con app-release.apk --filter-res=0 --res-enc=1 -res "@layout/abc_action_item"
2.若res目录的资源没有混淆过
1)保护res目录下所有的资源文件,命令参考如下
virboxprotector_con app-release.apk --filter-res=0 --res-enc=1 -res "res/*"
2)保护res目录下指定文件,文件路径需要以加壳工具界面显示的路径为准,命令参考如下
virboxprotector_con app-release.apk --filter-res=0 --res-enc=1 -res "res/layout/abc_action_item.xml"
#
SO库保护选项 | 命令行 | 默认选项 |
---|---|---|
隐藏符号表 | --hide-symtab= | 0 |
资源列表 | -lib <nativelib_list> | N/A |
移除不保护的so库 | --exclude-lib=<exclude_list> | N/A |
举例:
保护指定目录下的so库:--hide-symtab=0 -lib "lib/armeabi-v7a/libhello.so;lib/arm64-v8a/*"保护所有的so库:--hide-symtab=0 -lib "*"
注意:必须为双引号,如-lib "lib/arm64-v8a/*"
1)单引号不会生效,如-lib 'lib/arm64-v8a/*'
写法不会生效。
2)lib前不要加任何如-lib "/lib/arm64-v8a/*"
写法也不会生效。
#
命令行保护举例对 APK 进行保护,开启部分功能并设置签名:
virboxprotector_con app-release.apk --dex-enc=1 --file-check=1 --detect-dbg=1 --sign-check=1 --res-enc=1 -res "assets/*" --hide-symtab=0 -lib "lib/armeabi-v7a/libhello.so;/lib/arm64-v8a/*" --sign=1 --ks="test/android.ks" --ks-pass=mypass --ks-key-alias=CERT --key-pass=mykeypass -o app-release-protected.apk
#
问题1.Linux系统上使用命令行不加双引号不会生效么?
答:是的,Linux系统上使用命令行保护时参数后面需要加"",则参数功能才会生效。
2.命令行对资源文件保护时使用"*"文件,则默认保护哪些文件?
普通apk,默认保护assets和res/layout目录下的资源;
普通aab,默认保护base/assets目录下的资源;
Unity apk,默认保护assets目录下的资源;
Unity aab,默认保护base/assets目录下的资源。
3.加壳工具不支持Android资源文件读取视频的方式包括有?
1)使用了系统 自带的media player服务播放的音频 2)自己解析apk读取的资源