简介:面向安卓应用逆向分析与安全评估的工具合集,整合了apktool、dex2jar、jd-gui、autosign等社区常用组件,覆盖APK资源反编译、DEX字节码转换、Java源码查看和自动重签名等典型场景。压缩包共69个文件,以18个jar工具库、17个bat、14个sh脚本及8个exe可执行程序为主,附带txt说明与签名证书文件,整体仅15.21MB,便于快速部署。借助这套工具,读者可完整走通“APK反解→dex2jar转码→JD-GUI阅读→autosign重新签名”的流程,既能学习他人代码实现、排查问题,也能在合规前提下开展安全审计与加固验证。已有144人学习下载,适合有一定Java/Android基础、希望深入理解应用内部结构的开发者和安全爱好者。
1. android逆向助手:别一把梭,先把三个工具的主次分清
拿到一个 APK 想做点分析,很多人第一反应是把 apktool、dex2jar、jd-gui 全装一遍,然后对着同一份文件轮流试,试不出来就换下一个。这种做法其实是在浪费时间,因为这三个工具根本不是平级关系,而是同一套流水线上不同环节的机器。apktool 负责拆壳和打包,dex2jar 负责把 DEX 字节码转成 Java 可读的 Jar,jd-gui 负责让你像看源码一样翻代码。各有各的用途,也各有各的边界,连起来用才是完整的 android 逆向链路,拆开单用往往卡在中间某一步。这篇就把这套链路的搭建顺序、工具选择依据和容易翻车的细节一次讲清楚,给两类人看:一是刚开始学反编译、想知道从哪入手的,二是已经碰过这几个工具、但总在某些环节踩坑的老手。前者能照着步骤走完一遍拿到可用的代码,后者能明白失败时该往哪个方向查。
2. 搭建反编译链路:apktool 拆壳、dex2jar 转换、jd-gui 读码
2.1 先拆资源包:apktool 的拆解与回编译
apktool 在这套链路口干的是最粗的活:把一个 APK 当成 zip 解开,把二进制 XML 转成明文 XML,把资源文件按原始目录结构摆出来。它不负责还原 Java 代码,它还原的是应用的骨架和脸面。
最常见的用法是解码整个 APK:
# target.apk 是要分析的样本,out_dir 是输出目录 apktool d target.apk -o out_dird代表 decode,-o指定输出目录。跑完后 out_dir 里会出现 AndroidManifest.xml(明文版)、smali 目录(DEX 反汇编后的汇编代码)、res 资源目录和 apktool.yml。
这里要强调一件事:apktool 的d模式默认输出的是 smali,不是 Java。很多人误以为用了 apktool 就能看到 Java 源码,看到一屏的 smali 就懵了。smali 是寄存器和指令级的中间表示,能读懂它属于进阶技能,新手阶段不需要硬啃,直接把它当「DEX 的可读备份」就好。真正要读 Java 逻辑,走 dex2jar 那条路。
与之相对的是回编译,也就是b模式:
# 修改过 out_dir 里的资源或 smali 后,重新打包成 APK apktool b out_dir -o rebuilt.apk回编译最典型的用途是做二次修改,比如改应用名、换图标、改某个 smali 里的判断逻辑。但回编译对环境的依赖比拆解大得多,它依赖系统里安装的框架资源版本,后面避坑章节会专门说这个问题。如果你只是想做阅读分析,拆解 + 转换两条命令就够了,不用碰回编译。
2.2 DEX 转 Jar:dex2jar 的两种常见入口
dex2jar 做的事一句话概括:把 APK 里的 classes.dex(可能有多个)转成 .jar 文件,让 Java 世界里那些现成的反编译器能读进去。它是连接字节码和可读源码的桥梁。
常用命令有两种入口。第一种针对单独的 dex 文件:
# 先解压 APK 取出 classes.dex,或者直接用 apktool 输出的文件 unzip target.apk -d apk_unziped # 转换单个 dex d2j-dex2jar.sh apk_unziped/classes.dex -o output.jar第二种更省事,直接对整个 APK 操作:
# dex2jar 自己会处理 APK 里的 dex 文件 d2j-dex2jar.sh target.apk -o output.jar两种方式的区别在于:如果你只有一个 dex 文件,方式一够用;如果 APK 里有多个 dex(比如 multidex 分包),方式二会自动识别全部并合并输出到一个 jar,省去手动多次调用。
需要注意-o参数指定输出文件名,不写的话 dex2jar 会按输入文件同名生成一个 .jar。从实践看,我一般建议每次都用-o显式命名,否则输出文件容易和原始文件混在一个目录里,后面 jd-gui 打开时容易拿错文件。
转换完成后,output.jar 里就是 class 文件。到这一步,离 Java 源码只差一个反编译器。这个 jar 也可以直接用 jd-gui 打开,也可以丢给其他 Java 反编译工具,但整条链路里 jd-gui 和 dex2jar 的配合最顺滑,因为两者对同一套类文件格式的理解是一致的,换别的工具偶尔会遇到类解析不一致导致的空白类。
2.3 jd-gui 读码:阅读还原后代码的正确姿势
jd-gui 是这条链路最后一步的阅读器。它把 class 文件反汇编成接近原始 Java 源码的样子,显示在图形界面里。到这步才算真正「看到代码」。
打开 jd-gui 之后,直接把上一步输出的 output.jar 拖进去即可。左侧是包结构和类列表,右侧是源码。我一般会先做三件事:第一,看 AndroidManifest 里注册的组件,理清入口;第二,搜关键字符串,比如接口地址、密钥相关字段;第三,看 BuildConfig 或者 Application 子类的 onCreate,找全局逻辑。
jd-gui 也有一些短板,代码里用到混淆后的短类名时,文件名和类名对不上,跳转容易错乱;部分复杂泛型或 switch 语句反编译后会变成诡异的写法,但逻辑通常能看懂。它不适合做大规模代码搜索,因为打开大文件时会有卡顿,定位逻辑更推荐用命令行 grep 配合源码文本,后面第 6 章会单独给出一套可抄的搜索技巧。
这里补充一个常见误区:有人拿到 jar 后不看 jd-gui,而是直接解压 jar 看 .class 文件,再用 javap 看字节码。javap 给的是 JVM 指令级信息,和 smali 一个层级,适合排查具体方法的字节码行为,不适合通读业务逻辑。通读用 jd-gui,深挖单点用 javap,两者不是替代关系。这条链路默认走 jd-gui,只有在 jd-gui 反编译出错、某段代码完全不可读时才降级看 javap 或 smali。
整条链路搭起来就这么三步:apktool 拆出资源和清单,dex2jar 把 DEX 转成 Jar,jd-gui 把 Jar 还原成 Java。工具的先后顺序是硬性的,不能换,但选型时有几个细节会影响最终效果,下一章做逐项对比。
3. 三个工具逐项对比:从还原度、效率、容错看差距
3.1 反编译还原度对比:谁更能还原真实逻辑
还原度是选型时最容易产生错觉的维度。很多接触 android 逆向不久的人以为 apktool 还原的是资源,dex2jar 还原的是 Java,jd-gui 只是查看器,所以还原度应该由 dex2jar 单方面承担。实际不是这样,三个工具各自管一段,还原度要分三段看,谁拖后腿都不行。
| 环节 | 工具 | 输出产物 | 还原目标 | 常见还原失败表现 |
|---|---|---|---|---|
| 清单/资源 | apktool | XML + res | 结构完整可读 | XML 乱码、资源缺失 |
| 字节码转换 | dex2jar | Jar/class | 类结构完整 | 类缺失、方法体为空 |
| 类反编译 | jd-gui | Java 源码 | 逻辑可读 | 变量名丢失、泛型错乱 |
apktool 的还原度问题主要出现在资源上。老版本 APK 或用了资源混淆方案的应用,资源 ID 会被改得面目全非,apktool 拆解后 res 目录里会出现大量 unnamed 文件,能看结构但不知道具体用途。这个不算工具失败,是对方故意加了混淆,后面避坑章节会说怎么处理。
dex2jar 的还原度受 DEX 版本和指令集影响。新版 Android 平台对应的 DEX 格式较新,老版本 dex2jar 偶尔不识别某些新指令,转换后个别类直接丢失。遇到这种情况,换更新的 dex2jar 版本,或者用--debug参数跑一遍看日志,看是哪个类转换失败。
jd-gui 的还原度最直观影响阅读体验。同一个 class 文件,jd-gui 能还原出 80% 可读代码,换用另一款反编译器可能只有 60%,但局部逻辑和继承关系反而不如 jd-gui 清晰。从我的使用经验看,jd-gui 对变量名保留程度高,自动生成的 else/if 结构相对稳定,适合通读业务;它的弱项是 Lambda 表达式和枚举类,还原出来的代码偶尔会让你怀疑是不是原开发者写得太抽象。
3.2 操作效率对比:上手难度与批量处理
效率维度要看两个场景:单文件分析和批量分析。
单文件分析,apktool 是命令行,一条命令拆完;dex2jar 也是命令行,一条命令转完;jd-gui 是图形界面,打开 jar、点开类就能看。三者里 jd-gui 效率最高,因为它把代码浏览、字符串搜索、类跳转都做成了可视化操作。命令行两个工具适合脚本化,不适合交互式阅读。
批量处理是命令行工具的强项。比如一批样本都要做清单排查,写个循环调 apktool 就完事:
# 对同一目录下所有 APK 执行解码,输出到各自目录 for apk in samples/*.apk; do apktool d "$apk" -o "out_$(basename "$apk" .apk)" done这段循环对文件名不带空格、不带特殊字符的情况没问题。如果文件名里有空格,$apk加了引号也能正确处理,推荐写脚本时统一加引号,否则文件路径一有空格就当场报错,这种问题排查起来很浪费时间。
双手操作习惯上,我一般把 apktool 的命令行窗口固定在一个工作目录,把 dex2jar 的脚本路径加到 PATH 里,这样拆解和转换都不用敲绝对路径。jd-gui 则保持默认配置,不做多余设置。整套链路从拿到 APK 到打开 jd-gui 看到代码,熟练后一分钟内能完成,大部分时间花在等命令跑完上。
3.3 对混淆和加固的处理:三类工具各自的极限
混淆和加固是 android 逆向绕不开的坎,也是选型分水岭。先说混淆,常见混淆工具会把类名、方法名改成 a、b、c 这种短名,字符串也可能被加密。apktool 拆解后,smali 里的类名已经是混淆名,资源文件名还算正常;dex2jar 转换后,jd-gui 里看到的类名全部变短,跳转逻辑基本靠包结构和调用关系摸索。
对纯混淆的应用,三个工具都能正常工作,只是阅读体验差。真正让工具失效的是加固方案。加固应用的特征是:APK 里真实的 classes.dex 被抽空或加密,运行时由壳的 loader 加载真正的 dex。流行业务里大多数商业应用都会做这一步。
这种情况下,apktool 能拆出壳相关的资源和清单,但 dex2jar 转出来的 jar 里只有壳的逻辑,看不到业务代码;jd-gui 打开后是空的或者只有壳的方法。很多人卡在这步以为工具坏了,其实是样本加了保护,需要先脱壳才能回到正常的反编译流程。脱壳不在本篇选型范围内,但要知道判断标准:dex2jar 输出的 jar 里类数量远小于正常水平,jd-gui 打开后大面积空白,基本可以断定是加固了。
针对加固和混淆并存的恶劣样本,我的建议是不要指望某个工具单打独斗。apktool 先拆出清单看应用有没有壳的特征,再用 dex2jar 验证类完整性,最后 jd-gui 阅读时配合混淆映射关系做人工还原。三个工具都有极限,组合起来覆盖面更大。
4. 选型结论:学习分析、源码审计分别该用哪套
4.1 学习与简单分析选哪套:apktool + jd-gui 双组合
如果你的目的是学习某个应用的实现思路,或者只是分析某个功能点怎么写的,不需要改动打包,那不用完整走三件套。apktool 负责拆资源和看清单,dex2jar 转 jar,jd-gui 读代码。这套组合是学习分析场景的标准答案。
为什么推荐 apktool 而不是直接解压 APK?因为 APK 本质是 zip,直接解压看到的 AndroidManifest.xml 是二进制格式,编辑器打开是乱码,资源文件虽然在但目录结构不如 apktool 整理得直观。apktool 把这些都处理成了可读文本,还附带了 apktool.yml 记录原包信息,方便后续操作。
学习分析场景里 smali 也不是完全不用看。遇到 jd-gui 还原不出来的方法,或者你想理解某个加密算法在寄存器层面的具体计算过程,还是要切到 smali 目录里对着看。所以这条路径的实际学习曲线是:先 jd-gui 通读业务,再按需回 smali 抠细节。
如果只是临时看一下某个 APK 里有没有某个字符串,甚至可以不装三件套,直接用 grep 扫二进制:
# 不拆包直接搜索二进制内容里的关键字符串 grep -a "http://" target.apk | head -20这个技巧对初学者很有用,能快速判断一个应用是否包含某个接口或域名,但不是完整方案,因为混淆后的字符串往往加密了,搜不到不代表没有。它适合做初步情报收集,不适合做源码级分析。
4.2 源码审计与二次开发怎么选:链路完整优先
源码审计场景,比如分析某个应用的数据采集行为、排查敏感权限调用,或者想基于某应用做二次开发,要求的是链路完整和可回编译。这时候三件套缺一不可,而且要额外注意版本匹配。
审计场景里我一般会先完整走一遍三件套:apktool 拆包确认清单和权限声明,dex2jar 转 jar 确认类齐全,jd-gui 通读可疑逻辑。如果发现某个类在 jd-gui 里空白,马上回 apktool 的 smali 目录里读对应方法的实现,不能跳过去,否则审计结论不完整。
二次开发场景则更依赖 apktool 的回编译能力。改 smali、改资源后重新打包,需要系统里有对应 Android 版本的框架资源。这里有个经验:如果目标应用本身是低版本 targetSdk 编译的,回编译时用低版本框架成功率更高,高版本框架会把新的资源 ID 强行映射进去,导致改完的包行为异常。选型时不能只看工具的版本号,还要看目标应用的 targetSdk 版本,两者对齐才稳定。
至于 jar 层面做二次开发的情况,比如往反编译出的 jar 里注入类再重新转成 dex 塞回 APK,这套操作 dex2jar 和 jd-gui 都不擅长。它们只是转换和查看,真正的字节码注入要用其他工具链,不在这篇讨论范围。记住一条:凡是要改字节码,核心工作围绕 apktool 的 smali 做,dex2jar 转出的 jar 不参与回编译流程,只是给人看的。
4.3 临时救急场景:只用一个工具时怎么选
有时候你只有五分钟,就想知道这个 APK 是什么公司做的、包名叫什么、入口 Activity 是哪个,三件套全跑一遍反而浪费时间。这种救急场景,单个 apktool 就够。
# 只拆解,但只保留清单文件用于快速查看 apktool d target.apk -o out_dir # 直接读清单 cat out_dir/AndroidManifest.xmlapktool 拆出来的 AndroidManifest.xml 里能找到包名、声明权限、入口 Activity、第三方 SDK 的组件注册等信息。这些内容足够应付「这个应用靠什么起家」「它集成了哪些外部服务」这类初步判断。
如果救急目标是确认某个类是否存在、某个字符串在不在代码里,那就用 dex2jar 转 jar 后对 jar 做 unzip 再 grep:
# 先把 jar 解开 unzip output.jar -d jar_classes # 再在 class 文件里搜字符串,注意 class 文件是二进制 grep -rl "目标字符串" jar_classes这里输出的结果是一堆 .class 文件的路径,说明目标字符串出现在这些类里,具体上下文还得靠 jd-gui 打开对应类看。之所以不直接用 jd-gui 全包搜索,是因为大 jar 在 jd-gui 里全量搜索一次很慢,命令行 grep 秒出结果,定位到类之后再用 jd-gui 精读,效率高一个量级。
单工具选型有个底线:调试用 jd-gui,改动用 apktool,验证用 dex2jar。任何场景都不要指望一把锤子敲完所有钉子。
5. 避坑与排查:四个高频翻车点及处理
5.1 apktool 回编译失败:资源 ID 与系统框架版本
现象:apktool d 拆解一切正常,一旦执行 apktool b 回编译,立刻报错,错误信息里出现 aapt 相关字段,提示某个资源属性找不到,或者直接抛出「brut.androlib.AndrolibException」。
原因:APK 的反编译环境缺少目标系统版本的框架资源。apktool 在回编译时要参照框架资源来校验资源 ID,本地没有对应版本就挂了。另外,部分应用使用了自定义资源 ID 或做了资源混淆,拆解后的资源本身就不完整,回编译自然过不去。
解决:先安装对应版本的框架资源,命令是apktool if framework.apk,其中 framework.apk 是从设备或模拟器里拿到的对应系统版本框架包。如果还失败,检查是否改了 res 目录里的文件却没同步更新 public.xml。我自己的习惯是回编译前先备份一份刚拆解出来的原始状态,一旦改动出问题直接恢复,不从头重拆。还有一种情况是改 smali 时少加了.locals声明,这类错误属于编写问题,用文本编辑器检查修改区域的寄存器声明数量即可。
5.2 dex2jar 转 jar 报错:DEX 版本与内存参数
现象:d2j-dex2jar.sh 执行后,控制台输出一堆异常堆栈,常见的是java.lang.RuntimeException: IndexOutOfBounds或java.lang.ArrayIndexOutOfBoundsException,最终生成的 jar 里类不完整,甚至只生成了几 KB 的空壳。
原因:两个因素叠加。一是 APK 里的 DEX 用了比较新的指令或特性,旧版 dex2jar 解析不了;二是样本 dex 体积较大,转换时 JVM 默认内存不够用,中途内存溢出导致类丢失。
解决:换新版 dex2jar,或者手动加大 JVM 堆内存:
# 显式指定 JVM 内存,1g 适用于大多数样本,超大 dex 可以调 2g java -Xmx1g -jar dex2jar.jar target.apk -o output.jar如果加了内存还是失败,把报错信息里提到的类名记下来,单独从 dex 里提取这个类用 javap 看一眼,确认是不是指令不兼容。极少数情况下 DEX 被特殊处理过,比如加了自定义指令扩展,这时 dex2jar 无解,只能回到 smali 层面硬读。这条排查路径能覆盖 95% 的转换失败情况,剩下 5% 靠换工具版本解决。
5.3 jd-gui 打开卡死或乱码:混淆类名与中文注释
现象:jd-gui 打开一个较大的 jar 后,UI 卡顿明显,点某个类时长时间转圈;或者打开后类名是a.class、b.class这种短名,使用体验很差;还有一类是源码里中文注释变成乱码,读起来费劲。
原因:jar 体积大、类数量多,jd-gui 索引全部类要一定时间,这属于性能瓶颈。混淆类名是样本本身被混淆过,jd-gui 无能为力。乱码则是编码识别问题,jd-gui 默认按 UTF-8 读取,遇到 GBK 编码的注释文件就糊了。
解决:大 jar 打开后别急着点类,等左下角进度条跑完再做跳转。卡得特别严重时,用命令行先按第 6 章的技巧定位到具体类,再在 jd-gui 里用类名跳转过去,比在树状列表里翻快很多。混淆类名的问题解决不了,只能靠搜索关键字符串锁定目标类,再顺着调用关系逆推。乱码问题倒是可以改:jd-gui 的配置文件里调整默认编码,或者把源码文本复制出来用文本编辑器转换编码后再看。
5.4 遇到加固应用:先脱壳再谈反编译
现象:apktool 拆解正常,但 dex2jar 转换后 jar 里的类数量特别少,jd-gui 打开后看不到业务代码,只有一些初始化类。同时 AndroidManifest.xml 里能看到可疑的 Application 类,类名带有壳特征,比如「StubApp」「ProxyApplication」之类。
原因:应用接入了商业加固方案或自定义加壳。真实 dex 被加密存放在 assets 或其他位置,运行时才解密加载。普通反编译链路解析的是壳的代理 dex,自然看不到业务逻辑。
解决:先做加固识别,看 Application 类名特征和 assets 目录下的可疑数据文件。确认加固后,用对应脱壳工具或动态调试手段把真实 dex dump 出来,再对 dump 出的 dex 走 dex2jar + jd-gui 链路。脱壳这一步依赖具体加固方案,没有通用命令,但有个通用的判断标准:dump 出的 dex 如果能被 dex2jar 正常转换、类数量恢复到合理水平,就说明脱壳成功。如果 dump 后转换还是失败,检查是否还需要修复导入表和字符串加密,那属于另一个层面。
加固应用排查还有一个常见误判:有人看到 jd-gui 里全是空类就以为是 jd-gui 坏了,换版本、调参数折腾一圈,最后发现是样本加固。我自己的流程是:apktool 拆解后先看一眼 AndroidManifest,发现壳特征就不再浪费时间走常规链路,直接进脱壳流程。
6. 一个能直接抄的技巧:三分钟定位入口与核心逻辑
6.1 最快定位入口 Activity
拿到干净样本,第一步永远是找入口 Activity。apktool 拆解后,直接用 grep 在 AndroidManifest.xml 里查:
# 找到带有 MAIN 和 LAUNCHER 的 activity grep -n "MAIN\|LAUNCHER" out_dir/AndroidManifest.xml输出里会指向某个 activity 名称。这个类就是应用启动后第一个加载的界面,顺着它的 onCreate 方法能摸到应用的初始化逻辑和主流程。入口类在 jd-gui 里打开后,优先看 onCreate 里调用了哪些方法,一般是初始化 SDK、绑定服务、加载数据,整条线就有了。
6.2 定位关键逻辑先用搜索
入口找到后,要看具体业务逻辑,先在 jd-gui 里用搜索功能直接搜特征字符串。比如要找网络请求地址,搜http;要找密钥相关,搜api_key、secret;要找加密逻辑,搜encrypt、Cipher。
搜索结果的批量筛选效率不高,我会先用命令行把 jar 里的类路径 grep 一遍,再在 jd-gui 里精读:
# 先解压 jar unzip output.jar -d jar_classes # grep 出包含目标字符串的 class 文件路径 grep -rl "encrypt" jar_classes拿到类路径后手动跳转,避免 jd-gui 全包搜索的卡顿。这个方法对新手特别友好,不需要理解太多原理就能定位。
6.3 把结论记录成可复用笔记
分析完一个样本后,把入口类名、关键逻辑位置、加密算法入口、可疑接口地址记成笔记。下次再遇到同一厂商或同一加固方案的应用,直接按笔记里的路径切入,省掉重新摸索的时间。从我开始坚持这个习惯后,分析同类样本的速度明显提升,以前每次都要从入口摸一遍,现在直接跳到可疑类验证。
这套三分钟技巧的核心不是工具用的多花哨,而是顺序对:清单 → 入口 → 搜索 → 精读。从那以后我每次拿到 APK 都强制走一遍这个顺序,不跳步,不随机点类,效率稳定提升。希望帮到你。
本文还有配套的精品资源,点击获取