13 KiB
13 KiB
name, description, capabilities
| name | description | capabilities | |
|---|---|---|---|
| re-mobile-pack | Android 加固脱壳专项:乐固/360/梆梆/爱加密、DEX 恢复。 触发词:脱壳、Android加固、DEX脱壳、乐固、梆梆、360加固、爱加密 |
|
Android 加固脱壳(DEX 恢复)
何时使用 / 何时不用
- 用:拿到 Android 加固(乐固/360/梆梆/爱加密等)App,需要还原真实 DEX 继续静态分析
- 用:re-apk 已识别出加固,需要选脱壳路径
- 用:脱壳产物方法体空壳 / 指令抽取,需要修复
- 不用:未确认加固——先 re-apk 静态确认;普通 App 直接 jadx 即可
- 不用:VMP 虚拟化为主的强壳——转 re-anti-analysis(re-unpack-advanced 思路)
- 不用:需要运行时 hook / 绕过检测(那是 re-frida)
工具准备
动态脱壳默认在受控设备 / 模拟器快照内执行(re-analyze/platform-tips 最高原则——默认沙箱)。所有工具先验证再使用。
frida + frida-dexdump —— 运行脱壳主力
- frida-tools: 全平台
pip install frida-tools(Python 3.8+;建议 venv);frida-server 版本必须与主机一致并推送设备(安装与反检测完整流程见 re-frida 工具准备) - frida-dexdump: 全平台
pip install frida-dexdump(Python 3)——运行时搜索内存中的 DEX 魔数并 dump - 验证:
frida --version;frida-dexdump -h(能看到-U/-f/-d参数) - 用法:
frida-dexdump -U -f <包名>(spawn 起步脱壳)、frida-dexdump -U <pid>(attach)、frida-dexdump -U -f <包名> -d(深度搜索,覆盖多 DEX / 部分抽取)
BlackDex —— 静态脱壳机(免 frida,普通加固首选替代)
- 安装: GitHub release 下载 APK——
https://github.com/CodingGay/BlackDex/releases;32 位与 64 位是两个独立 APK(目标 App 不出现在列表就换另一个架构版本) - 环境: 普通 Android 手机或模拟器,Android 5.0~12,无需 root / 定制环境
- 能力: 覆盖落地加载 / 内存加载 / 指令抽取三类壳;深度模式回填指令抽取的方法体(实验性,可能耗时数分钟或失败)
- 产物:
hook_*.dex(hook 系统 API 得到)与cookie_*.dex(DexFile cookie 技术) - 验证: 安装后能列出目标 App 并完成脱壳
Youpk —— 主动调用脱壳机(抽取加固最强路径)
- 源码/ROM:
https://github.com/Youlor/Youpk——基于 Android 7.1.2_r33 二次开发,仅支持 Google Pixel 1:Android Studio 构建后flash-all.sh刷入定制 ROM - 用法:
adb shell "echo <包名> >> /data/local/tmp/unpacker.config"→ 启动目标 App 自动主动调用脱壳(日志见 "unpack end")→adb pull /data/data/<包名>/unpacker - 修复:
java -jar dexfixer.jar ./unpacker ./out(配套 DEX 修复,回填方法指令) - 验证:
adb shell ls /data/data/<包名>/unpacker能看到 dex/method 产物
jadx —— 脱壳后反编译(复用 re-apk)
- 跨 OS 安装与验证见 re-apk 工具准备;jadx 支持多 DEX 直接分析,避免手工合并
adb —— 设备交互
- Android SDK platform-tools 自带;验证
adb --version;模拟器场景adb shell即可 - dexdump: Android SDK build-tools 自带(步骤 4 DEX 完整性检查用);验证
dexdump -h
内存转储(re-memdump 思路)
- frida/objection
memory dump或按 re-memdump 从转储 grep DEX 魔数dex\n0xx提取——frida-dexdump 不可用时的兜底路径
操作步骤
按顺序执行,每步产物(DEX 路径 + sha256)存档(见 re-triage)。
-
加固识别(先确认再动手):
- 类名特征: jadx 反编译只见壳类——
com.stub.StubApp(爱加密)、com.secneo.apkwrapper/com.bangcle.*(梆梆)等;入口 Application 被替换成壳类 - 壳 so 特征:
ls out/lib/——libjiagu.so/libprotectClass.so(360 加固)、libDexHelper.so/libexec.so(爱加密)、libsecexe.so/libsecmain.so(梆梆) - DEX 体积:
ls -la out/classes*.dex——真实 DEX 加密存放(assets/ 或运行时解密),壳内 classes.dex 体积异常小 - 记录识别出的壳名决定路径: 常规整体/抽取加固 → 本技能;虚拟化为主 → re-anti-analysis
- 类名特征: jadx 反编译只见壳类——
-
运行脱壳(frida-dexdump,默认路径):
adb shell monkey -p <包名> 1 # 先启动 App,让壳把真 dex 加载进内存 frida-dexdump -U -f <包名> # 或 spawn 起步 frida-dexdump -U <pid> # 已运行 attach frida-dexdump -U -f <包名> -d # 深度搜索(多 DEX / 部分抽取场景)产物在当前目录
<包名>/<时间戳>/*.dex。时机:等 App 进到业务页面再 dump(re-analyze/platform-tips 关键经验——转储时机),一启动就 dump 拿到的是壳初始状态。 -
静态脱壳(BlackDex / Youpk,frida 被检测时的替代路径):
- BlackDex: 安装对应架构 APK → 选择目标 App → 脱壳(普通壳几秒;抽取壳开深度模式,数分钟且有失败风险)→ 导出产物
- Youpk(抽取加固优先): 刷 Pixel 1 ROM → 写包名配置 → 启动 App 等待自动脱壳 → pull
unpacker/目录 →java -jar dexfixer.jar ./unpacker ./out - 交叉验证: 两条路径产物对比(同一方法体应一致),不一致取完整者
-
DEX 修复与完整性检查:
file out/*.dex # 应见 "Dalvik dex file version 035"(magic: dex\n035\0) dexdump out/classes.dex 2>/dev/null | head -30 jadx -d java-out out/ # 反编译验证:业务类是否齐全- 方法体空壳(CodeItem 全 nop / 直接 throw)→ 指令抽取壳未回填:用 dexfixer(Youpk 产物配套)或 BlackDex 深度模式重脱;仍不行 → 主动调用触发方法执行后再转储(re-memdump 思路)
- 多 DEX: 检查 classes.dex / classes2.dex / ... 是否齐全;frida-dexdump
-d深度搜索兜底;jadx 多 DEX 直接分析 - 修复后必须反编译抽检再进业务分析(见坑 3)
-
脱壳后分析(走 re-apk 全流程):
- manifest 入口/权限 → jadx 反编译业务代码 → 定位目标逻辑(密钥/协议/校验)
- 需要改行为 → smali 补丁 + 重打包签名(re-apk 步骤 4)
- 原生 so(壳 so / JNI 业务 so)→ re-binary-core(re-format-elf + re-ghidra);壳自身反调试/校验对抗 → re-anti-analysis
跨域联合
- re-mobile: 工作流第 5 步加固分支固定调用本技能(re-apk 识别后转入)
- re-apk: 加固识别(步骤 5)与脱壳后静态分析(manifest / jadx / smali)
- re-frida: 运行脱壳执行环境 + 反 frida 检测对抗(改名 / 换端口 / gadget)
- re-memdump: 内存 DEX 提取思路(dump 时机、magic 扫描、多 DEX 兜底)
- re-anti-analysis: VMP / 虚拟化加固对抗(抽取+虚拟化组合壳转强壳流程)
- re-binary-core: 壳 so / JNI 原生逻辑分析(re-format-elf / re-ghidra)
- re-analyze/platform-tips: 默认沙箱(模拟器快照)、转储时机关键经验
- 本技能被 re-analyze 的 triage「移动 App 分析」路径引用(re-mobile → re-apk 识别加固 → re-mobile-pack)
常见坑与陷阱
- VMP 级加固(抽取+指令虚拟化)脱壳难度大:现象——frida-dexdump / BlackDex 出 DEX 后方法体大量 nop / 空壳,部分方法逻辑在 dex 里永远找不到;原因——壳除抽取指令外把关键方法虚拟化进 so(自定义 VM 解释执行),DEX 层还原不出这部分;对策——识别为抽取+虚拟化组合时:抽取部分用 Youpk 主动调用修复,虚拟化部分放弃 DEX 还原、改为动态 re-frida hook 观察输入输出,或还原 VM 解释器(成本高,标注范围并转 re-anti-analysis 强壳思路)
- 反 frida 检测:现象——spawn 即闪退、frida-dexdump 连不上或 dump 出空结果;原因——壳检测 frida-server 端口 27042 / 路径 / 特征线程(gum-js-loop)等指纹;对策——按 re-frida 反检测章节改名 + 换端口;仍被检测 → 换 BlackDex / Youpk(不依赖 frida)或 frida-gadget 注入
- DEX 修复不完整(方法体空壳):现象——jadx 打开脱壳 DEX,半数方法无反编译内容或直接 throw;原因——指令抽取壳的 CodeItem 未回填(dump 时机早于方法执行 / 修复器未处理);对策——dexfixer 修复(Youpk 产物配套)或 BlackDex 深度模式重脱;主动调用触发方法执行后再 re-memdump 转储;修复后 dexdump 抽查 + jadx 反编译验证再进分析
- 多 DEX 合并/丢失:现象——只 dump 到单个 classes.dex,jadx 报类缺失 / 引用不存在;原因——加固后多 DEX 由壳运行时加载,frida-dexdump 默认搜索可能漏;对策——
-d深度搜索、hook ClassLoader 枚举已加载 dex(re-frida 枚举)、内存转储全部提取;jadx 直接加载全部 dex 分析 - 转储时机过早:现象——dump 出的 DEX 解不开 / 是壳初始数据;原因——真 dex 尚未解密加载;对策——等 App 进入业务页面再 dump(re-analyze/platform-tips 转储时机关键经验,与"解密数据看到立刻保存"相反的另一端)
- PairIP(Google Play 自动保护)三道门:现象——JADX 拉开关键方法只剩
VMRunner.invoke("...")空壳,模拟器上跑几秒就退;原因——Play 上架自动套的加固三件套:①代码虚拟化:逻辑抽进加密 VM blob(assets 随机名无扩展名文件,\x00IAP头为解密判据)+ native 解释器libpairipcore.so(executeVM等符号名运行时从 XOR 表解码,strings 搜不到);②TEE 密钥:blob 是 AES/GCM 密文,wrapping key 存在设备 TEE(AndroidKeyStore),Play 经importWrappedKey(SecureKeyWrapper ASN.1)下发——三个硬前提:Play 安装(gpdekusplit 载体)、过 Play Integrity、有登录 Google 账号,缺一即 Finsky 日志 FAILURE → 本地伪造isEncryptionKeyPresent()也没用;③运行时反篡改:dl_iterate_phdr/opendir 扫 maps 发现注入 so → 故意给 std::vector 喂非法 length →std::__throw_length_errorabort(tombstone 指纹length_error was thrown in -fno-exceptions mode)→ abort 被中和则执行流落 abort 下一条指令踩内存 SIGSEGV +SIG_DFL复位——信号层 hook 拦不住,根因在检测端(maps 不露脸);对策——先过 Integrity(三绿真机或 PlayIntegrityFix)+ 清掉可见注入模块(Zygisk disable 后重启) - PairIP 脱明文:调用而非 hook:现象——hook
VMRunner任何方法(getVmByteCode/executeVM/readByteCode)进程立刻自毁;原因——PairIP 盯 ArtMethod 完整性:frida hook 改写entry_point_from_quick_compiled_code即命中检测;对策——反射直接调用解密函数(getVmByteCode是 private static,frida 反射可调;blob 名带不带assets/前缀版本间不一致,两种都试),零 hook 零 ArtMethod 改动即可解出全部 blob 明文——脱 PairIP 不需要内核级隐身,只有必须动态跟解释器时才需要 - 加固 APK 直接重打包 → 真机黑屏:现象——对加固 APK 走 apktool 重打包,签名安装后真机黑屏(进程存活、无崩溃),同一 APK 在模拟器上却「看起来正常」;原因——重打包从 smali 重建 DEX,破坏壳的布局与自校验假设,壳定位/验证不了加密载荷 → 不解密 → 真实 DEX 里平台通道 handler 全部抛 MissingPluginException → 未捕获异常拆掉渲染;模拟器上壳校验被放松,「模拟器能跑」不是证据;对策——重打包前先做加固检测(assets 里壳运行时 so(
lib*sec*/lib*shell*风格)、动态 DEX loader so、壳 stub 入口类、单一超大 classes.dex 且无业务字符串、smali→dex 往返拆出多个空 stub DEX);确认加固即放弃 apktool 重打包;转储内存必须卡解密窗口——壳瞬态自卸载,/proc/self/maps里可能都看不到壳,过早/过晚都拿不到解密 DEX;若应用自身还自检「壳是否存在」,脱壳需一并中和该检查(来源:reverse-skills(inliver233),MIT) - 加固目标交付路径:脱壳重打包 / 免重打包注入 / 常驻 gadget:现象——带壳目标直接脱壳重打包后运行异常,或不知选哪条修改交付路径;原因——脱壳重打包后壳工件未清干净,壳运行时与明文 DEX 冲突;对策——按目标状态选:路径 a 脱壳重打包(保真度高):blackdex / FART / frida-dexdump 在解密窗口从活进程取回真实 DEX 再重打包(壳已不需要),重打包前清掉全部壳工件(壳运行时 so、壳目录、DEX loader);路径 b 免重打包注入(不重装 DEX,壳与自校验完全不动,对壳风险低,优先):原位替换 libapp.so + 用 LSPatch 类工具注入 Java hook,注意目标可能检测注入框架本身(检测字符串常见),属需一并处理的完整性信号;路径 c 常驻 gadget(零文件改动):注入 frida-gadget + 开机自启脚本做运行时签名适配与 libapp 内存 patch,注意 gadget 可被检测、运行时翻转检查耦合标志可能反噬;不推荐逆向壳校验逻辑硬过 apktool 重打包——难度高收益低(来源:reverse-skills(inliver233),MIT)