当前位置:首页>安卓APP>安卓逆向系列 06:砸壳全攻略——从整体加密到函数抽取

安卓逆向系列 06:砸壳全攻略——从整体加密到函数抽取

  • 2026-08-27 22:13:34
安卓逆向系列 06:砸壳全攻略——从整体加密到函数抽取

本系列文章仅供安全研究与学习使用,请在合法授权环境下操作,切勿用于非法用途。


一、什么是加固,为什么需要砸壳

1.1 加固的本质

发布到应用市场的 APK,开发者通常会对其进行加固(加壳)处理。加固的本质是在原始 DEX 文件外面套一层"保护壳",让逆向分析者无法直接用 jadx 等工具看到真实的业务代码。

加固后的 APK 运行流程大致如下:

  1. 系统启动 APK,先执行壳代码(Application 或 ContentProvider)

  2. 壳代码在内存中解密/解压原始 DEX

  3. 将解密后的 DEX 加载进虚拟机(DexClassLoader)

  4. 原始业务代码正式运行

因此,APK 静态分析时看到的只是壳代码,真正的逻辑藏在加密 DEX 里。砸壳就是把内存中已解密的 DEX 转储(dump)出来,还原为可分析的代码。

1.2 为什么逆向分析必须先砸壳

场景不砸壳的后果
jadx 打开 APK只看到壳代码,关键类几乎为空
Frida Hook 业务类类名/方法名不存在,脚本报错
静态搜索关键字符串搜不到,字符串也被加密存储
分析签名算法真正的加密逻辑完全不可见

二、主流加固厂商与技术原理对比

2.1 加固技术分类

市场上的加固技术主要分三个层次:

技术层级原理保护强度代表厂商
整体加密将整个 DEX 加密,运行时解密后加载★★☆娜迦(Nagapt)早期版本、部分小厂
函数抽取将方法体(指令)从 DEX 中抽空,运行时填回★★★梆梆企业版、腾讯御安全
VMP/VDEX将 Java 字节码转换为自定义虚拟机指令★★★★网易易盾、阿里聚安全

2.2 主流厂商详细对比

厂商产品名称主要技术特征标识砸壳难度
梆梆安全BangBang Shield整体加密 + 函数抽取bangcle、secapk中
腾讯御安全Tencent Shield函数抽取 + VMPlegu、tencent. 前缀高
阿里聚安全Ali Shield整体加密 + VMPaliprotect、walling高
网易易盾NetEase Shield整体加密 + VMPnetease、yidun高
爱加密iJiami整体加密 + 函数抽取ijiami、com.ijm中
几维安全Jiwei Shield整体加密 + Native保护kiwisec中高
通付盾Tongfudun整体加密payegis低
娜迦安全Nagapt整体加密naga、nagaprotect低

2.3 各技术原理深入解析

整体加密型:

APK 安装 → Application.attachBaseContext() → 解密 classes.dex → 替换 ClassLoader

优点是实现简单,缺点是 DEX 整体在内存中必然存在,一次性可以全部 dump。

函数抽取型:

DEX 中方法体被清空(nop填充) → 运行时在方法被调用前填入真实指令

这种方式 dump 整个 DEX 是无效的,需要借助 ART 的 dex2oat 回调在每个方法执行时单独 dump。

VMP 型:

Java 字节码 → 自定义虚拟机指令(opcode混淆) → 专属解释器执行

最难分析,通常只能分析自定义解释器的行为,完全还原成本极高。


三、APKiD 识别加固类型

在砸壳前,先用 APKiD 识别目标 APK 使用了哪种加固,针对性选择方案。

3.1 安装 APKiD

pip install apkid# 或者使用 Docker(推荐,依赖更完整)docker pull rednaga/apkiddocker run -it--rm-v$(pwd):/apks rednaga/apkid /apks/target.apk

3.2 基本用法

# 分析单个 APKapkid target.apk# 输出 JSON 格式apkid -j target.apk > result.json# 分析并显示详细信息apkid -v target.apk

3.3 典型输出解读

[INFO] APKiD 2.1.3 :: from RedNaga Security[INFO] Processing target.apktarget.apk!classes.dex |-> anti_disassembly : dalvik byte order |-> compiler : dexlib 2.xtarget.apk!assets/libjiagu_64.so |-> protector : Bangcle/SecNeotarget.apk |-> anti_vm : Build.FINGERPRINT check

关键标识对照:

APKiD 输出对应加固推荐砸壳方案
Bangcle/SecNeo梆梆加固frida-dexdump
Qihoo 360360加固FART / frida-dexdump
Tencent Legu腾讯御安全FART + 函数抽取修复
Ali/Alibaba阿里聚安全frida-dexdump
iJiami爱加密BlackDex / frida-dexdump
NetEase网易易盾FART

四、方案一:frida-dexdump

frida-dexdump 是基于 Frida 的通用 DEX dump 工具,适合整体加密类加固,成功率较高。

4.1 环境要求

  • 已 Root 的 Android 设备(或模拟器)

  • Frida Server 已在设备运行(版本需与 PC 端一致)

  • Python 3.6+

4.2 安装

pip install frida-dexdump# 验证安装frida-dexdump --version

4.3 启动 Frida Server

# PC 端adb push frida-server /data/local/tmp/adb shell "chmod +x /data/local/tmp/frida-server"adb shell "su -c '/data/local/tmp/frida-server &'"# 验证连接frida-ps -U

4.4 执行砸壳

# 方式一:先启动 App,再 dump(推荐)# 1. 手机上手动打开目标 App,等待启动完成# 2. 执行 dumpfrida-dexdump -U-f com.target.app# 方式二:spawn 模式(App 冷启动时 dump)frida-dexdump -U-f com.target.app --spawn# 方式三:指定输出目录frida-dexdump -U-f com.target.app -o /tmp/dex_output/# 方式四:深度搜索(搜索内存中所有 DEX 魔数)frida-dexdump -U-f com.target.app --deep-search

4.5 输出结果

[*] Found DEX file, loading...[*] Dump 0x71a3400000 to /tmp/dex_output/classes.dex (4.2 MB)[*] Dump 0x71a8c00000 to /tmp/dex_output/classes2.dex (1.1 MB)[*] Done! 2 DEX file(s) dumped.

4.6 核心原理(简化版脚本)

frida-dexdump 的核心是在内存中搜索 DEX 魔数 64 65 78 0a(dex\n),找到后按照 DEX 文件头中的 file_size 字段读取完整数据:

# 简化版原理示例importfridadefdump_dex(pid):session = frida.get_usb_device().attach(pid)script = session.create_script("""    // 搜索内存中所有 DEX 文件    Process.enumerateRanges('r--').forEach(function(range) {        try {            var magic = Memory.readByteArray(range.base, 4);            var bytes = new Uint8Array(magic);            // DEX magic: 64 65 78 0a (dex\n)            if (bytes[0] == 0x64 && bytes[1] == 0x65 &&                 bytes[2] == 0x78 && bytes[3] == 0x0a) {                // 读取文件大小(offset 0x20)                var fileSize = Memory.readU32(range.base.add(0x20));                var dexData = Memory.readByteArray(range.base, fileSize);                send({type: 'dex', base: range.base.toString()}, dexData);            }        } catch(e) {}    });    """)# ... 保存处理逻辑

五、方案二:BlackDex(免 Root 方案)

BlackDex 是一款无需 Root 的 Android 端图形化砸壳工具,适合没有 Root 设备的场景。

5.1 原理

BlackDex 利用 Android 的多用户机制和 VirtualApp 技术,在独立的用户空间中运行目标 App,通过监控 DexClassLoader 的调用时机来 dump DEX,无需系统 Root 权限。

5.2 下载与安装

  1. 从 GitHub 下载最新版本:https://github.com/CodingGay/BlackDex

  2. 手机安装 BlackDex-arm64.apk(或 BlackDex-arm32.apk,取决于设备架构)

  3. 授予必要权限(存储权限)

5.3 操作步骤

Step 1:安装目标 APK

目标 App 需要先安装在手机上(或直接提供 APK 路径)。

Step 2:打开 BlackDex

BlackDex 主界面 → 选择要砸壳的 App → 点击"开始提取"

Step 3:等待完成

BlackDex 会在后台启动目标 App,监控 DEX 加载事件并 dump。过程通常需要 30-120 秒。

Step 4:获取结果

# dump 结果保存路径/sdcard/BlackDex/包名/# 使用 adb 拉取adb pull /sdcard/BlackDex/com.target.app/ ./dex_output/

5.4 BlackDex 的局限性

限制说明
函数抽取类dump 出的方法体仍为空,需配合 FART
VMP 保护无法还原虚拟机指令,仅能 dump DEX 框架
部分加固检测 VirtualApp可能导致 App 闪退或触发反调试
Android 12+ 兼容性部分 ROM 上运行不稳定

六、方案三:FART 定制 ROM(函数抽取专杀)

FART(Function ARTificially)是专门针对函数抽取类加固的最强工具,需要刷入定制 ROM。

6.1 FART 原理

函数抽取加固的 DEX 在磁盘上方法体是空的,只在执行时才填回真实指令。FART 的思路是:

  1. 修改 ART 虚拟机源码,在每个方法首次执行时记录方法的 code_item

  2. 主动调用 App 中所有可访问的方法,触发方法体填充

  3. 将 DEX 文件 + 每个方法的真实 code_item 合并,还原完整 DEX

6.2 获取 FART 镜像

# FART 支持的设备(Google 原生系统)# Pixel 系列:Pixel 1/2/3(Android 7/8/9/10)# 下载地址:https://github.com/hanbinglengyue/FART# 刷入方式(以 Pixel 2 为例)adb reboot bootloaderfastboot flash boot fart_boot.imgfastboot reboot

6.3 FART 砸壳步骤

方式一:通过 am 命令触发

# 1. 在设备上执行 FART dumpadb shell am start-n com.target.app/.MainActivity# 2. 触发 FART dump(通过特殊 Activity)adb shell am start-a android.intent.action.FART -n com.target.app/.MainActivity# 3. 等待 dump 完成(约 1-3 分钟)# 4. 拉取结果adb pull /sdcard/fart/com.target.app/ ./fart_output/

方式二:通过 API 主动调用

# Frida 脚本配合 FART ROM 主动 dumpimportfridascript_code = """Java.perform(function() {    // 枚举所有已加载的类    Java.enumerateLoadedClasses({        onMatch: function(className) {            try {                var clz = Java.use(className);                // 获取所有方法并主动调用(触发 FART 记录)                var methods = clz.class.getDeclaredMethods();                methods.forEach(function(method) {                    // FART ROM 会自动记录每个方法的真实 code_item                });            } catch(e) {}        },        onComplete: function() {            console.log('[*] 所有类遍历完成,FART dump 触发');        }    });});"""

6.4 FART 输出目录结构

/sdcard/fart/com.target.app/├── classes.dex          # 原始(方法体为空的)DEX├── classes_fart.dex     # FART 填充后的完整 DEX├── codeitems/           # 每个方法 code_item 的二进制记录│   ├── Lcom/target/LoginManager;->login.bin│   └── ...└── dump_log.txt         # dump 日志

七、砸壳流程图

流程说明:

  1. APKiD 扫描 → 识别加固类型(整体加密/函数抽取/VMP)

  2. 选择方案:

    • 整体加密 → frida-dexdump 或 BlackDex

    • 函数抽取 → FART 定制 ROM

    • VMP → 需要逆向自定义解释器(高难度)

  3. 执行 dump → 获取原始 DEX 文件

  4. dex修复 → 使用 dexfixer 修复可能损坏的结构

  5. jadx 验证 → 确认代码可读性


八、dex 修复:dexfixer 用法

dump 出的 DEX 文件可能因为内存对齐、校验和等问题无法直接被 jadx 识别,需要先修复。

8.1 常见问题

问题现象原因工具
jadx 报 DEX checksum mismatch文件校验和未更新dexfixer / baksmali
unexpected magic valueDEX 头部损坏手动修复或重新 dump
方法体显示为 nop函数抽取未还原FART 重新 dump
类缺失、方法缺失dump 时机不对spawn 模式或延迟 dump

8.2 dexfixer 安装与使用

# 下载 dexfixer# https://github.com/F8LEFT/ART-dex-fixer# 编译(需要 Android NDK)cd dexfixerndk-build# 或直接使用预编译版本# 放入 PATH# 修复单个 DEXdexfixer input.dex output.dex# 批量修复for f in dex_output/*.dex; do    dexfixer "$f""fixed_$(basename $f)"done

8.3 使用 baksmali + smali 修复

# 方法一:重新计算校验和# 安装工具pip install androguardpython3 << 'EOF'from androguard.core.bytecodes.dvm import DalvikVMFormatimport hashlib, structwith open('dump.dex', 'rb') as f:    data = bytearray(f.read())# 重新计算 checksum(Adler-32)import zlibchecksum = zlib.adler32(bytes(data[12:])) & 0xffffffffstruct.pack_into('<I', data, 8, checksum)# 重新计算 SHA-1sha1 = hashlib.sha1(bytes(data[32:])).digest()data[12:32] = sha1with open('fixed.dex', 'wb') as f:    f.write(data)print('修复完成')EOF# 方法二:baksmali 重组java -jar baksmali.jar d dump.dex -o smali_output/java -jar smali.jar a smali_output/ -o rebuilt.dex

九、砸壳后验证:jadx 打开测试

9.1 jadx 基本验证

# 打开修复后的 DEXjadx -d output_dir/ fixed.dex# 检查输出ls output_dir/sources/

9.2 验证清单

# 1. 检查类数量grep-r"class " output_dir/sources/ | wc-l# 2. 检查关键类是否存在grep-r"LoginManager\|SignatureUtil\|encrypt" output_dir/sources/# 3. 检查方法体是否为空# 如果看到大量这样的代码,说明函数抽取未还原:# public void someMethod() {#     // 空方法体或仅有 return# }# 4. 用 jadx-gui 直观检查jadx-gui fixed.dex

9.3 质量评估标准

指标正常砸壳函数抽取未修复
类总数正常(数百到数千)数量正常
方法可读性有实际逻辑代码方法体为空/仅 return
字符串可见性明文字符串可见部分/全部加密
继承关系完整的类继承树完整

十、常见失败原因与对策

失败现象可能原因解决方案
frida-dexdump 无输出App 还未完全启动等待 5-10s 再执行 dump
DEX 文件大小为 0dump 时机过早使用 --spawn + 延迟钩子
jadx 打开报错DEX 结构损坏dexfixer 修复后重试
方法体全为 nop函数抽取加固改用 FART 方案
BlackDex 闪退App 检测了 VirtualApp改用 frida-dexdump
FART 设备不支持非 Pixel 机型找对应机型的 FART 移植版
壳检测 frida反调试机制先用第 09 篇的反检测方案
dump 出多个 DEX多 dex 架构合并或逐个分析
代码混淆严重ProGuard/R8 混淆参考第 02 篇反混淆技巧

10.1 多 DEX 合并技巧

# 如果 dump 出多个 DEX,可以合并后统一分析# 工具:dex-toolsjava -jar d2j-dex-recompute-checksum.jar classes.dexjava -jar d2j-dex2jar.jar classes.dex -o classes.jar# 将多个 jar 合并# 然后用 jadx 打开合并后的 jar

10.2 Spawn 模式延迟 Hook

对于在 Application 极早期就完成解密的加固,需要延迟 dump 时机:

# frida-dexdump 延迟 dump 技巧importfrida, timedefon_message(message, data):print(message)device = frida.get_usb_device()# spawn 启动,暂停在入口pid = device.spawn(['com.target.app'])session = device.attach(pid)# 注入等待脚本,等 Application.onCreate 完成后再 dumpscript = session.create_script("""var Application = Java.use('android.app.Application');Application.onCreate.implementation = function() {    this.onCreate();    // Application 初始化完成,发信号 dump    send('ready_to_dump');};""")script.on('message', on_message)script.load()# 恢复执行device.resume(pid)time.sleep(2)# 此时 Application 已初始化,DEX 已解密,执行 dump

小结

砸壳是安卓逆向的必经之路,核心思路是在正确的时机,从内存中捞出已解密的代码。

  • 整体加密:frida-dexdump 或 BlackDex,成功率高

  • 函数抽取:必须用 FART,其他方案无效

  • VMP:难度极高,需要专门的 VMP 逆向研究

下一篇我们将进入网络层,学习如何绕过 SSL Pinning,实现 HTTPS 抓包。


文章持续更新,欢迎关注。转载请注明出处。

最新文章

随机文章