尧图精选

零基础Android脱壳实战:用frida-dexdump一键还原加固App业务代码

🕒 发布时间:2026/10/1 3:46:00 📁 来源:尧图网络
最近有个朋友拿着一个套了360加固的App来找我问能不能把里面的业务逻辑还原出来看看。我说能但需要先脱壳他当时一脸懵脱壳是什么难不难会不会把手机搞坏我花了大概一个多小时从环境搭建到dump出dex带着他完整走了一遍全程没让他写一行代码最后他惊喜地发现业务类全都在。这篇文章就把这套完全可复制的流程写下来给所有零基础想做Android反编译、脱加固壳的人一条能走通的路。先说清楚这是一篇技术学习与安全研究方向的实操教程面向的目标是你自己写的测试App、已开源App、或者你有明确授权做安全评估的样本。不要拿它去搞未经授权的破解和分析技术工具没有原罪但使用边界必须自己守住。1. 先从根上理解加固和脱壳到底是怎么回事1.1 为什么用jadx打开加固App看不到业务代码正常情况下一个APK就算代码写得再烂你用jadx一拖基本能把Java层逻辑看个八九不离十。Activity、Fragment、网络请求封装、工具类清晰得很。但当你拖入一个套了360加固或者其他同类加固方案的APK时画风突变首页只有屈指可数的几个类application节点被换成了一个壳入口业务类一个都找不到。这不是jadx坏了而是加固的机制导致的。加固的本质是“加密存储 运行时解密”。开发者的真实dex会被加密成一个文件塞进assets目录或者so库里。App启动后壳代码先接管进程做一堆环境检测和安全校验然后才从加密文件里解密出真实的dex字节流再通过DexClassLoader、InMemoryDexClassLoader这类机制把真正的dex加载进ART虚拟机里执行。也就是说从磁盘上看这个App是“空心”的只有当它跑起来内存里才会出现完整的真实dex。所以静态反编译当然什么都看不到因为你看到的classes.dex只是壳的启动器真正的业务逻辑被锁在了壳后面。1.2 脱壳就是趁真实dex在内存里“活着”的时候抓住它理解了加固原理脱壳的思路就顺理成章了既然真实dex最终必须出现在内存里那我就在App运行期间把这段内存抓下来保存成dex文件再丢回jadx反编译。这就是俗称的脱壳。整个过程有三件事最核心找到真实dex加载的时机不能太早壳还没解密也不能太晚某些临时dex可能已经被回收定位dex在内存中的位置靠文件特征、内存段扫描、Hook关键类加载逻辑把内存字节完整保存下来并保证dex文件的完整性包括修复校验和等零基础路线最怕的就是第一关“时机”和第二关“定位”太玄学。好在社区已经有现成的工具把这两步做成了“一条命令”你要做的不是发明轮子而是学会正确使用轮子。2. 工具选型为什么零基础首选frida-dexdump2.1 主流的脱壳方案横向比个明白在没有现成工具的时代脱壳是件极其痛苦的事你得先反编译壳本身搞明白它的解密算法然后写脚本手动调DexClassLoader或者在IDA里动态调试so层逻辑。这对零基础无异于劝退。现在主流方案大概分三类基于Frida生态的工具代表是frida-dexdump。核心思路是用Frida把JS脚本注入目标进程然后扫描进程内存按dex文件的魔法头特征把所有疑似dex的内存段全部dump下来。优点是操作简单、对大多数加固有效、不需要定制系统缺点是对某些变种加固会失效且dump出来的文件会有冗余噪声。基于定制ROM的方案代表是FART、BlackDex。思路是在系统框架层做文章在ART虚拟机加载类的时候主动脱壳。优点是兼容性极强连很多VMP类加固都能扒出点东西缺点是要给模拟器刷定制系统光是环境搭建就可能劝退新手。基于静态分析硬破解的方案比如直接还原壳的解密算法。这种方案对分析者的逆向功底要求极高不推荐零基础尝试。对于“零基础 第一次脱壳”这个场景frida-dexdump是性价比最高的环境要求低模拟器就能跑命令简单一条命令搞定社区活跃度高遇到问题好搜答案。2.2 frida-dexdump的原理说人话版frida-dexdump的原理其实不复杂。dex文件有固定的文件头也就是我们常说的magic字节通常是dex\n035\0或更高版本。无论壳怎么加密磁盘上的文件只要它把dex解密后交给ART虚拟机执行内存里就一定有一块区域符合dex文件的特征。frida-dexdump做的事情就是通过Frida注入目标进程扫描进程的所有内存段寻找匹配dex文件头特征的内存区域对候选内存块做合法性校验比如dex文件头部字段是否合理、文件大小是否与头部声明匹配把验证通过的内存块原样保存成dex文件这就是为什么你会看到它有时候会dump出很多个dex其中一部分可能是系统框架的dex、壳自身的dex、还有你真正想要的业务dex。没关系都保存下来后面用jadx逐个看就行。理解这一步你后面排查问题就会容易得多比如dump出来的全是一些无关系统类你该知道是时机不对比如发现dex很小可能是dump到了不完整的dex碎片。3. 环境准备一张清单加几条命令3.1 你需要的东西一个都不能少工欲善其事必先利其器零基础脱壳的环境准备就四块电脑端工具、模拟器环境、客户端Frida、设备端frida-server。每一块都必不可少但它们都不难。实际操作前我建议你准备好这些一台Windows 10/11或macOS电脑内存别低于8GBGenymotion模拟器我强烈推荐用模拟器而不是真机原因很简单模拟器自带root不用解锁BL、不用为root权限提心吊胆adb命令行工具装Android Platform Tools即可Python 3.8以上环境Frida客户端、frida-tools、frida-dexdump全部通过pip安装与电脑端Frida版本严格一致的frida-server放进模拟器里运行这里有个重点frida-server的版本必须和电脑端Frida的版本一致。这是新手踩坑率最高的一步后面我会专门讲。3.2 安装过程详解每一步都给你说清楚第一步安装Python和pip。Windows用户去官网下载Python安装包安装时一定勾选Add Python to PATH。macOS可以用brew install python3。装完打开终端执行python --version和pip --version确认能跑。第二步安装Frida工具链。终端执行pip install frida frida-tools frida-dexdump装完以后执行frida --version记下版本号。比如我的结果是16.7.19后面下载frida-server就要找16.7.19版本。第三步安装Genymotion并创建一台Android 9的虚拟设备。下载安装Genymotion Desktop客户端的时候它会要求你安装VirtualBox这个是底层依赖按提示装就行。装好后启动设备等它完全开机。第四步验证adb连接。终端执行adb devices能看到设备就代表通信正常。如果看不到大概率是adb路径没配好或者Genymotion的adb bridge没启动。第五步下载frida-server。打开GitHub上frida官方仓库的releases页面找到和刚才版本号完全一致的tag下载android-x86_64的压缩包。Genymotion是x86架构所以选x86_64如果是真机一般是arm64别下错。第六步把frida-server推入模拟器并启动。依次执行adb push frida-server-16.7.19-android-x86_64 /data/local/tmp/frida-server adb shell chmod 755 /data/local/tmp/frida-server adb shell su -c /data/local/tmp/frida-server 如果提示Permission denied别急先adb shell进去输入id看自己是不是root用户。Genymotion不同镜像版本的su行为不太一样有些进去就是root有些必须su。如果su -c不行直接/data/local/tmp/frida-server 也许就成功了。第七步验证Frida连通。电脑终端执行frida-ps -U如果能看到模拟器里的进程列表说明Frida客户端和服务端通信正常环境全部就绪。4. 实操全流程一条命令把壳拔下来4.1 找到目标App的包名脱壳前先得让工具知道该操作哪个App。包名就是Android里每个应用唯一的身份标识比如com.example.app。获取方法有几种用aapt命令aapt dump badging xxx.apk | grep package用jadx打开APK看AndroidManifest.xml里的package属性或者最简单的模拟器里安装好App用frida-ps -U列出进程名找到自己目标顺带观察一个细节如果Manifest里application的name被换成了com.stub.StubApp这类带stub关键词的类基本可以确认这包确实加了加固而且这个类在后续分析里也是个重要线索。4.2 启动脱壳命令找到包名后在电脑终端执行frida-dexdump -U -f com.example.app -o dump这里解释一下参数含义-U表示连接通过USB/adb连接的目标设备-f表示spawn方式也就是由Frida来拉起这个App而不是去attach一个已经在跑的进程dump是输出文件夹名。执行后你会看到类似下面的输出Start: 15:30:00 Spawned com.example.app. PID: 2345 Dumping dex files... [INFO] Dumping 4 dex files ... Done: 15:30:05几秒钟到几十秒不等视App大小和dex数量而定。完成后当前目录会生成一个dump文件夹里面放了若干个dex文件。这些就是壳加载到内存里的所有dex原始数据。4.3 用jadx验证脱壳成果打开jadx把dump目录里的dex文件拖进去然后按包名路径找你的业务类。如果能看到com.example.app下的Activity、Fragment、网络请求类等恭喜脱壳成功。如果看到的全是壳类或系统类大概率是dump时机太早壳还没把真实dex解密加载完。我遇到这种情况的补救办法是先手动正常打开App等页面完全加载然后用attach模式重新来一次frida-dexdump -U -n com.example.app -o dump2-n参数指定的是进程名称。这种方法能覆盖到App运行中后期才按需加载的dex特别是那些用到某个功能才动态加载进来的模块。4.4 备选方案如果frida-dexdump收获寥寥frida-dexdump也不是万能的。某些加固方案做了更强的混淆和反调试或者dex在内存中不是连续完整存在而是分片加密、按方法动态解密执行这时候扫描整段内存就变得困难。遇到这种情况可以尝试进阶路线用Frida脚本主动遍历ClassLoader列表沿着ClassLoader对象里的pathList字段找到Element数组再从Element里拿DexFile对象反射调用相关方法把dex内容取出来。这个方案的本质是“通过ART虚拟机自身的加载信息来还原dex”对一部分frida-dexdump无能为力的加固有效。不过这个方案对新手并不友好需要你懂一点Java反射和Frida脚本的语法。第一次不建议碰它先把基础方案跑通再说。真要深入了后面可以单独写一篇进阶篇。5. 脱壳之后的三个坎你得提前知道5.1 第一坎dump出来的可能是odex/vdex不是标准dexAndroid 8.0以上ART虚拟机的运行时dex格式可能不是我们熟悉的classes.dex而是odex/vdex这些衍生格式。jadx虽然能解析一部分但偶尔会报错打不开。遇到这种情况思路是先把文件转换成标准dex。社区里常见的工具是vdexExtractor、oat2dex等。转换时要注意不同的工具对不同Android版本的兼容性不同Genymotion的Android 9和Android 7生成的文件格式有差异需要试错。不过大多数常规App在Android 9上dump出来的依然是可以直接解析的标准dex这个问题只在部分场景出现不用太焦虑。5.2 第二坎脱壳成功但代码被混淆过脱壳只是把“门”打开了但门后面还有一道“雾”。很多App在加固之前会先做ProGuard/R8混淆类名、方法名、变量名全变成a、b、c、d。你看到这种代码别以为脱壳失败了——脱壳解决的是“代码在不在内存里”的问题混淆解决的是“代码好不好读”的问题这是两个完全不同的层面。应对混淆代码我的经验是先把jadx里按包名排序肯定能找到一些没被混淆的工具类或三方库类再通过AndroidManifest里的入口Activity和Service找到那些必须保留名字的类这些类是手动梳理逻辑的锚点最后用jadx的导出源码功能把可读的Java源码导出来放到Android Studio或IDEA里做交叉搜索效率会高不少。5.3 第三坎字符串加密和动态加载有些App对关键字符串做了一层加密运行时会解密后拼接使用。你在静态反编译的代码里看到的是一堆类似new String(Base64.decode(xxx))的代码或者是一堆native方法调用。这类保护已经不属于加固脱壳的范畴更多是代码层面的对抗需要结合动态调试和hook工具去还原。对零基础读者来说这三个坎可以放一放先把脱壳这条主链路跑通再按需进阶。6. 常见问题与排查技巧实录6.1 问题速查表现象可能原因解决办法frida-ps -U 提示unable to connect电脑端Frida和frida-server版本不一致两边版本号必须严格一致重新下载frida-server并推入设备启动spawn后App秒退目标App存在Frida检测机制尝试attach模式-n参数或换一台更干净的设备环境adb devices列表是空的adb服务异常或模拟器未完全启动执行adb kill-server和adb start-server重启adb服务dump目录只有1个很小的dexdump时机太早壳还没来得及解密真实dex改用attach模式或先手动打开App让页面完全加载再脱壳jadx无法打开dump文件文件是odex/vdex等非标准dex格式用vdexExtractor等工具转换后再用jadx打开看到大量a、b、c类名加固之外还做了代码混淆这不算脱壳失败按混淆分析思路处理dump下来的dex有很多内部全是系统类扫描到了ART虚拟机的框架dex不奇怪逐个查看业务dex通常集中在和目标包名有关的路径下6.2 我踩过的三个坑希望你绕开第一个坑frida-server版本不匹配。这是新手最容易遇到的。我有一台电脑上Frida客户端更新到16.7版本模拟器里的frida-server还停留在16.6结果frida-ps直接报unable to connect。排查了十分钟才想到版本问题。解决方式就是重新下载16.7的frida-server推上去重启。强烈建议在环境配置完成后先在模拟器里跑一次frida-ps确认没问题再开始脱壳。第二个坑Genymotion的root权限在不同镜像上有差异。有些镜像进去就是root有些必须su -c。遇到Permission denied先别慌adb shell进去跑一下id看看当前用户再决定启动方式。如果su路径不统一也可以试试在Genymotion的shell里直接以root执行。第三个坑dump时机拿捏不准。加固App启动后壳代码要先解密、加载、校验真实dex进入内存是需要时间的。我第一次实操时App刚spawn完就立刻dump结果只得到一个壳的dex差点以为工具坏了。后来改成让App多跑几秒、甚至打开几个页面后再脱壳结果完全不一样。如果你也遇到这个问题优先考虑是不是时机没选对。7. 脱壳技能还能怎么用在真实场景里这部分算是给愿意深入的人一个方向提示。脱壳之外大多数安全分析和逆向流程里你会频繁遇到类似的手段抓包、Hook、动态调试、so层分析。脱壳解决的是“看见Java层代码”的问题但这只是第一步。你用frida-dexdump成功一次之后顺手可以试试frida自带的一些Hook能力比如hook一个方法看参数和返回值简单且收获感极强。还有一个很实际的应用场景App升级后你之前积累的分析笔记失效了。很多商业App每次发版都会重新加固、重新混淆但包名和核心类名不会大变。有了脱壳这条流水线你可以快速把新版本的dex导出来和自己之前的笔记做diff看看到底改了什么。这对做合规分析、版本对比、历史追溯都很有用。我自己在做一些App的隐私行为审查时标准流程就是脱壳 → 反编译 → 导出Java → 在IDE里全局搜索隐私相关API调用 → 模块级梳理行为路径。脱壳是这套流程里最前置、最有“破防感”的一步也是最容易让新人获得成就感的一步。说到底脱壳这件事真不难难的是环境偶尔抽风、时机不对、工具版本打架这类问题解决多了你的排查能力自然就长上来了。我个人的体会是第一次跑通frida-dexdump看到业务类出现的那一刻你会觉得前面所有的环境折腾都值了。后面如果你想继续深挖可以试着写自己的Frida脱壳脚本、研究不同加固厂商的加载时机差异甚至尝试对着FART源码理解系统层脱壳的原理。路很长但起点就是眼前这条命令。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →