Android逆向工具链安装配置:apktool、dex2jar与jd-gui全链路避坑
发布时间:2026/10/31 1:08:34 锦皓数字建站

简介Android逆向助手面向Android开发者、安全审计人员与逆向工程学习者围绕APK反编译、源码查看和重签名等需求整合反编译、自动签名、DEX转Java及图形化代码浏览等组件适用于应用结构解析、功能逻辑分析、安全漏洞排查和性能优化对具备一定Android基础的中级学习者较为友好。压缩包共69个文件约15.21MB以Java工具包、可执行程序、批处理与Shell脚本为主体辅以说明文档并包含签名相关配置材料便于在Windows或类Unix环境下按需调用。已有145人学习说明其在逆向入门与工具整合方面具有一定参考价值。包内将反编译、字节码转换、代码浏览和自动签名等环节集中组织读者可据此搭建较完整的分析流程理解APK资源与字节码结构并在合法合规前提下开展安全评估、功能拆解和防护研究。1. 装 android 逆向助手最常出错的地方三个包互相冲突不是工具难找装 android 逆向助手这类工具链最容易卡住的地方不是找不到 apktool、dex2jar、jd-gui 这三个包而是把它们放进同一个 shell 之后互相冲突——apktool 在 Java 17 下跑得好好的dex2jar 一上手就抛Unsupported class file major versionjd-gui 双击之后毫无反应连报错都不给。android apktool dex2jar jd-gui 反编译这条链路看着是三个独立小工具实际共享同一个 JVM 底座JDK 选错一次后面每个环节都得重新排查一遍。它适合需要看别人 APK 里资源怎么组织、smali 怎么改、第三方 SDK 合了哪些包的开发者也适合给自家应用做体积和兼容性排查的人。装不好最典型的后果就两句话能解包但读不懂 Java能读懂 Java 但回编译出来的包装不上。这篇按我实际装机的顺序走一遍环境、脚本、参数、故障处理都写清楚。2. 环境准备JDK 版本与工作目录先定好2.1 JDK 版本怎么选8、11、17 的实际差别这套工具链的第一个分歧点就在 JDK 上。apktool 2.x 要求 Java 8 及以上跑在 11 或 17 上没问题jd-gui 现在也基本跟得上新版本 JDK真正挑版本的是 dex2jar——它内部依赖较老的字节码处理库遇到高版本 JDK 编译出来的 class 文件或者高版本 JVM容易出现InvocationTargetException或者干脆解不出东西。所以我的做法是机器上留两个 JDK一个 8 专门喂给 dex2jar 兜底一个 11 或 17 给 apktool 和 jd-gui 用。不要指望一个版本通吃这是这类逆向工具链和普通 Java 项目最大的区别。先确认机器上现在有哪些# 看当前默认 java 是哪一个、什么版本 java -version javac -version # Linux 下看已安装的 JDK 列表Debian/Ubuntu 系 ls /usr/lib/jvm/ # macOS 下看 /usr/libexec/java_home -Vjava -version输出里第一行的引号内容就是实际生效的版本比如11.0.20。如果机器上只装了一个 JDK建议先把 JDK 8 装上后面 dex2jar 那一步会用到。Windows 上装 JDK 时注意别选带空格的安装路径C:\Program Files\Java\...这种路径在批处理脚本里很容易因为引号漏写而翻车。提示不需要卸载现有的高版本 JDK靠环境变量和脚本里的绝对路径切换就行装两套 JDK 在这类场景里是常规操作而不是脏做法。2.2 目录结构与环境变量一次配好后面脚本都靠它我不喜欢把工具散落在下载目录里因为过两周就找不到哪个 jar 是哪个版本。固定一个工具根目录把 apktool、dex2jar、jd-gui 各自放一个子目录脚本里全部用绝对路径引用这样无论从哪个目录执行都不会出问题。# 统一工具根目录路径里不要有中文和空格 sudo mkdir -p /opt/retools/{apktool,dex2jar,jd-gui,work} # JDK 路径按自己机器实际情况改 export JAVA8_HOME/usr/lib/jvm/java-8-openjdk-amd64 export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 # 把 wrapper 脚本目录加进 PATH而不是把 jar 加进去 export PATH$JAVA_HOME/bin:/opt/retools/bin:$PATH # 反编译过程中经常要确认编码统一成 UTF-8 export JAVA_TOOL_OPTIONS-Dfile.encodingUTF-8这段配置里有三个点值得说明。第一JAVA_HOME指向 11是因为 apktool 和 jd-gui 是日常高频使用的让默认java命令落在 11 上最省事JDK 8 单独用JAVA8_HOME记着需要时在命令前临时覆盖。第二PATH里加的是/opt/retools/bin也就是后面放 wrapper 脚本的地方不是 jar 所在目录——jar 不能直接当命令用必须有个壳。第三JAVA_TOOL_OPTIONS会影响这台机器上所有 JVM 进程如果同一台机器还跑着别的 Java 服务、且那些服务依赖平台默认编码就别设成全局的改成在具体脚本里加-Dfile.encodingUTF-8更稳妥。Windows 上对应的是系统环境变量面板配置完要新开一个 cmd 窗口才生效这是很多人改完变量发现java -version没变的原因。目录结构建议同样是D:\retools\apktool、D:\retools\dex2jar这种短路径后续批处理脚本里写%~dp0引用同目录文件会很方便。3. apktool 安装wrapper 脚本和 framework 缓存这两步别省3.1 获取 jar 包并做首次版本自检apktool 的发行方式很简单官方发布页给一个 jar重命名成固定名字就行。注意不要用java -jar apktool.jar这种一次性命令当日常用法一旦你需要从别的目录执行就会不停地在cd和cd -之间来回切。cd /opt/retools/apktool # 把下载到的 apktool_x.y.z.jar 放进当前目录统一改名 mv apktool_*.jar apktool.jar # 自检能打印出版本号说明 jar 完整且 JDK 可用 java -jar apktool.jar --version # 看完整参数列表确认 d(ecode) 和 b(uild) 子命令都在 java -jar apktool.jar -h--version这一行输出同时验证了两件事jar 没下坏、当前 JDK 能加载它。如果这一步就报Invalid or corrupt jarfile基本是下载中断重新下一次如果报UnsupportedClassVersionError是 JDK 版本太低换成 11 或 17 再试。这两类错误长得像但处理方向完全相反先看报错里的关键词再动手。3.2 写一个不依赖当前目录的 wrapperwrapper 的作用是把 java 调用、内存参数、jar 路径三样东西固定下来。Linux/macOS 下用 shell 脚本Windows 下用 bat两边思路一样。#!/usr/bin/env bash # /opt/retools/bin/apktool # 把 jar 路径写死这样在任何目录下执行 apktool 都能找到本体 APKTOOL_JAR/opt/retools/apktool/apktool.jar # -Xmx2g 是解大 APK尤其是带大量资源的包时的经验值默认堆容易 OOM exec java -Xmx2g -Dfile.encodingUTF-8 -jar $APKTOOL_JAR $echo off rem D:\retools\bin\apktool.bat rem %~dp0 表示脚本自身所在目录避免写死盘符后换机器就失效 java -Xmx2g -Dfile.encodingUTF-8 -jar %~dp0..\apktool\apktool.jar %*shell 版里exec的作用是用 java 进程替换掉当前 shell 进程这样 CtrlC 能直接把 java 干掉$会把用户传的所有参数原样透传给 jar少写这个的话apktool d app.apk里的d和app.apk就丢了。bat 版里%~dp0是批处理里最容易写错的东西它带尾部反斜杠所以拼路径时是%~dp0..\apktool\apktool.jar而不是%~dp0\..\...。另外-Xmx2g不是越大越好解一个几十 MB 的普通 APK2G 绰绰有余设到 8G 反而会让 GC 行为变得不直观出问题时更难判断。脚本放好之后记得给执行权限并且确认PATH里/opt/retools/bin在前面chmod x /opt/retools/bin/apktool which apktool apktool --versionwhich输出的路径应该是/opt/retools/bin/apktool如果指向别的地方说明 PATH 里有同名旧脚本先清理再继续。3.3 framework 缓存与 apktool.yml 的关键字段apktool 第一次解带系统资源引用的 APK 时会需要 framework 资源才能正确解析android:style/...这类引用。常见做法是提前把目标设备或目标系统版本对应的framework-res.apk拉下来注册成一个带标签的 framework。# 把系统 framework 注册成一个自定义标签避免覆盖默认的 1.apk apktool if framework-res.apk -t myfw # 解包时显式指定用哪个 framework apktool d -t myfw -f -o ./out app.apkif是 install-framework 的缩写-t myfw给这套 framework 打标签标签会体现在 apktool 的缓存目录里。-f表示目标目录已存在时强制覆盖——这个参数我基本每次解包都带因为反复调试时out目录几乎总是存在的不带它会直接报错退出。-o指定输出目录比默认的app目录名更可控。解完之后重点看输出目录里的apktool.yml里面几个字段决定了后面能不能顺利回编译字段含义回编译时的注意点version生成该目录的 apktool 版本换版本重编前建议重新解一次不要跨版本混用目录apkFileName原始 APK 文件名回编译时不读它但排查来源时有用sdkInfo.minSdkVersion清单里解析出的最低 SDK改动后可能与实际行为不符谨慎手改sdkInfo.targetSdkVersion目标 SDK影响签名方案选择低版本可能不校验 v2 签名doNotCompress不参与压缩的资源后缀手改这个列表容易导致装包后资源读不到doNotCompress是最容易出问题的一项。有人为了让包变小往这个列表里加了一堆后缀结果装上去之后应用启动即崩日志里是资源找不到。原因是部分资源必须保持未压缩状态才能被Resources直接映射这类字段的正确做法是保持解包时的原样不要凭感觉删改。4. dex2jar 与 jd-gui 串联把 classes.dex 变成能读的 Java4.1 dex2jar 的执行权限与 JDK 归属apktool 负责资源和 smalidex2jar 负责把classes.dex转成.jarjd-gui 负责把.jar里的 class 显示成 Java 源码。三者串起来才是一条完整的链路缺一环都只能看到半截东西。先把 dex 文件从 APK 里挑出来。APK 就是个 zip多 dex 的应用会有classes.dex、classes2.dex、classes3.dex这样一串mkdir -p /opt/retools/work/demo/dex # 引号必须加否则 shell 会尝试展开通配符找不到文件时会把字面量传给 unzip unzip -o -q app.apk classes*.dex -d /opt/retools/work/demo/dex ls -lh /opt/retools/work/demo/dex-o覆盖已有文件-q静默-d指定解压目录。这里最容易犯的错是没加引号导致unzip收不到匹配模式、什么也没解出来后面 dex2jar 报「文件不存在」时还以为是工具问题。接着跑转换。dex2jar 的发行包解开后是一堆.sh和.batLinux 下必须补执行权限尤其是它内部调用的d2j_invoke.shcd /opt/retools/dex2jar # 整个目录的脚本都补上执行权限漏掉 d2j_invoke.sh 会报 Permission denied chmod x *.sh # 显式用 JDK 8 跑避免高版本 JVM 下的字节码兼容问题 JAVA_HOME/opt/jdk8 ./d2j-dex2jar.sh \ /opt/retools/work/demo/dex/classes.dex \ -o /opt/retools/work/demo/jar/classes.jar参数说明-o指定输出 jar 路径父目录要提前建好dex2jar 不会自动创建-f强制覆盖已有输出--force在部分版本里等价。命令前面那个JAVA_HOME...是临时覆盖只对这一条命令生效不影响当前 shell——这正是同时装两个 JDK 的意义所在切换成本只有一行前缀。如果转换过程中打出大量WARN但最后有Done并且 jar 文件大小正常一般不用管真正要停下来的信号是Exception in thread main或者生成的 jar 只有几百字节。Windows 下用d2j-dex2jar.bat逻辑一样只是把JAVA_HOME换成set JAVA_HOMED:\jdk8再执行。批处理里临时变量不会污染全局关掉窗口就没了。4.2 jd-gui 的启动参数编码、内存、多开jd-gui 有安装包和 jar 两种形态运维场景我优先用 jar 版因为不需要装也没有卸载残留。但直接双击 jar 版会遇到两个经典问题中文注释显示成方块、打开大 jar 时界面卡死。# 关键参数编码固定 UTF-8堆给到 2G避免打开大 jar 时卡在索引阶段 java -Dfile.encodingUTF-8 -Xmx2g \ -jar /opt/retools/jd-gui/jd-gui.jar \ /opt/retools/work/demo/jar/classes.jar-Dfile.encodingUTF-8解决的是源码里中文变成乱码的问题这个参数必须在-jar之前写在后面 JVM 不认。-Xmx2g决定能打开多大的 jar超过堆上限会直接 OOM 而不是变慢所以看到「打开就闪退」先怀疑内存而不是文件损坏。最后那个 jar 路径是作为参数传给 jd-gui 的让它启动后直接加载省掉一次手动 Open File。macOS 上如果你用的是.app形态这些参数没法从命令行传需要改Contents/Info.plist里的VMOptions数组把-Dfile.encodingUTF-8和-Xmx2g各加一条。改之前先备份 plist改坏之后应用会直接打不开而且不报任何错属于典型的黑匣子故障。4.3 串成一条流水线一次解开一个 APK手工敲上面这些命令解一个包要切四五次目录。我一般会写一个小脚本把解包、抽 dex、转 jar 三步固定下来输出目录按 APK 名分开避免互相覆盖。#!/usr/bin/env bash # /opt/retools/bin/unpack-apk set -euo pipefail APK$1 NAME$(basename $APK .apk) WORK/opt/retools/work/$NAME mkdir -p $WORK/{apktool,dex,jar} # 第一步apktool 解资源与 smali apktool d -f -o $WORK/apktool $APK # 第二步抽出所有 classes*.dex多 dex 应用会一次全拿到 unzip -o -q $APK classes*.dex -d $WORK/dex # 第三步逐个 dex 转 jar按原文件名区分 for d in $WORK/dex/classes*.dex; do base$(basename $d .dex) JAVA_HOME${JAVA8_HOME:-$JAVA_HOME} \ /opt/retools/dex2jar/d2j-dex2jar.sh -f $d -o $WORK/jar/$base.jar done echo 产物目录: $WORKset -euo pipefail是这类流水线脚本必须加的三件套-e让任何一步失败就整体退出不至于带着半成品继续往下跑-u让引用未定义变量时报错防止$NAME拼错却静默生成一个空目录pipefail让管道中任一环节失败都能被捕获。循环里${JAVA8_HOME:-$JAVA_HOME}是带默认值的写法机器上没配 JDK 8 时退回当前 JDK虽然可能失败但至少会给出明确报错。脚本执行完apktool/目录看资源和 smalijar/目录里的文件直接丢进 jd-gui 就能读。5. 常见问题排查五条实际踩坑记录5.1 启动阶段的两个假故障现象apktool d app.apk报Input file (app.apk) was not found or was not readable但ls明明能看到文件。原因路径里有空格或中文参数没加引号被 shell 拆成了两段apktool 只收到了前半截。解决给路径加引号apktool d -f -o ./out ./某 目录/app.apk。长期办法是把工作目录固定在不含空格和中文的路径下我统一放在/opt/retools/workWindows 上放D:\retools\work从源头避免这类问题。现象d2j-dex2jar 报./d2j_invoke.sh: Permission denied。原因只给d2j-dex2jar.sh加了执行权限没给被它调用的d2j_invoke.sh加。发行包解压后默认权限丢失两个脚本都需要可执行。解决进 dex2jar 目录执行chmod x *.sh不要只针对单个文件。换机器、重新解压发行包之后都要重做一次属于每次部署的固定步骤。5.2 产物不对的两个原因现象dex2jar 转换成功jd-gui 打开后大量类显示// INTERNAL ERROR //源码读不出来。原因JDK 版本过高dex2jar 内部老版本字节码库解析不了高版本 class 文件或者被转换的 APK 用了较新的编译优化。解决改用 JDK 8 重跑 dex2jar命令前加JAVA_HOME/opt/jdk8。如果换 JDK 8 之后仍然大面积报错换一条链路——现在很多人直接用 jadx 把 dex 反编译成 Java它对高版本字节码的兼容性更好jd-gui 更适合用来交叉核对单个类。两条链路并存不冲突谁先出结果用谁。现象apktool 解包时报Could not decode arsc file。原因apktool 版本比目标 APK 的编译工具链旧resources.arsc的新格式解析不了。解决换更新版本的 apktool jar重命名覆盖apktool.jar后重跑。这类错误不要试图靠改参数绕过是解析能力问题不是配置问题。换版本之后建议把旧的解包目录删掉重新解跨版本混用目录会在回编译阶段报一堆莫名其妙的资源 ID 错误。5.3 回编译与签名环节的一条现象apktool b回编译成功但安装时报INSTALL_PARSE_FAILED_NO_CERTIFICATES或App not installed。原因重新打包出来的 APK 没有签名或者只用了 v1 签名而目标系统要求 v2/v3另外先签名后对齐也会破坏签名。解决顺序必须是回编译 → zipalign → 签名一步都不能颠倒。# 1. 回编译 apktool b ./out -o unsigned.apk # 2. 对齐必须在签名之前做签名后再对齐会把签名搞坏 zipalign -f -p 4 unsigned.apk aligned.apk # 3. 签名用自己生成的调试 keystore 就够 apksigner sign --ks ~/.android/debug.keystore \ --ks-pass pass:android --out signed.apk aligned.apk # 4. 验证签名是否真的生效 apksigner verify --verbose signed.apkzipalign的-p表示按页对齐、4是 4 字节边界这两个参数在绝大多数场景下是固定值。apksigner和zipalign都在 Android SDK 的 build-tools 目录下不在 PATH 里就写全路径。最后那条verify是我强制自己加的一步不做的话装不上时你根本分不清是签名没生效还是别的环节出了问题。6. 装完怎么验证拿一份自己打的 APK 走完整链路验证这套环境不能靠「命令没报错」来判断必须有一个能闭环的样本。我固定用一份自己编译的测试 APK里面故意放了中文资源、一个多 dex 分包、一个第三方 SDK。装完之后按下面这张表逐项过任何一项对不上就说明环境还没真正跑通。检查项命令期望结果JDK 可用java -version输出与JAVA_HOME一致的版本apktool 可执行which apktool apktool --version指向/opt/retools/bin/apktool并打印版本framework 已注册apktool if framework-res.apk -t myfw无异常缓存目录出现对应标签解包完整apktool d -t myfw -f -o ./out test.apk生成AndroidManifest.xml、res/、smali/、apktool.ymldex 抽取unzip -l test.apk | grep classes列出至少一个classes*.dexdex 转 jard2j-dex2jar.sh classes.dex -o classes.jarjar 大小与 dex 同量级非几百字节Java 可读jd-gui 打开 classes.jar能看到类结构且中文注释不乱码回编译通过apktool b ./out -o unsigned.apk无资源 ID 报错签名有效apksigner verify --verbose signed.apk输出 v1/v2 校验通过这张表里最容易被跳过的是「中文不乱码」和「jar 大小同量级」这两项。前者不验证的话等到真正去看业务代码时才发现注释全是方块得重新查编码链路后者不验证的话一个只有 300 字节的空 jar 也能让 dex2jar 返回 0看着成功实际什么都没转出来。我习惯在转完之后直接unzip -l classes.jar | head看一眼条目数量几秒钟的事比后面打开 jd-gui 发现空空如也再回头排查省太多时间。最后一步是端到端复现把解包目录里某个字符串资源改掉重新回编译、对齐、签名、装到测试机上看改动是否生效。这一步能同时验证 apktool 的资源重建能力、zipalign 的对齐结果和签名链的完整性是整套环境唯一的全链路体检。只做解包不做回编译等于只验证了一半很多资源编译期的问题会一直藏着。从那以后我每次在新机器上装这套工具链都会强制先跑一遍「改字符串再装回去」的闭环不跑通就不往下做业务分析。工具装没装上看版本号环境好不好用得看回编译能不能装上机器——这两件事差得很远。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。