简介这套工具面向Android开发、安全测试和逆向学习人员将apktool、dex2jar、jd-gui、autosign等常用组件整合为一体化逆向助手能够完成APK反编译、DEX转JAR、Java代码查看、重签名等核心操作帮助使用者快速分析应用结构、定位关键逻辑并开展安全评估。压缩包共69个文件大小15.21MB包含18个jar库文件、8个exe工具、17个bat脚本、14个sh脚本以及签名密钥和原生库等jar是逆向分析的核心组件exe提供Windows下的可视化执行bat/sh则方便在Windows和Linux环境中自动调用整体覆盖从解包、转换到签名加固的典型流程。目前已有144人学习下载适合希望免去手动装配环境的开发者直接入门。借由这套整合包读者可省去逐一下载和配置工具的麻烦直接对目标APK进行反编译阅读Java逻辑也可修改资源后一键重签名并安装调试同时包内的说明文档和脚本注释还能辅助理解每一步的原理适合逆向入门和日常分析使用。1. android逆向助手能拆到什么程度先跑通apktool、dex2jar、jd-gui这条链路拿到一个没有源码的APK想改个包名发到自己渠道或者想搞清楚某个接口的参数怎么拼android逆向助手这类整合包的价值就出来了。它把apktool、dex2jar、jd-gui搭成一条可执行的链路apktool负责解包和回编译dex2jar负责把dex字节码转成jarjd-gui负责把jar读成近似Java的伪代码。这三段串起来是日常反编译最常用的组合适合没有源码但要定位逻辑、修改资源、重签名安装的从业者。要注意边界这套链路是静态分析能看到的是资源、smali、伪代码不是原始源码遇到加固或so混淆刚才说的三个环节会变得不可用或明显失真。接下来的内容按“解包→转jar→读码→回编译→签名→安装验证”展开把每段的参数、坑和验证方式写清楚。新手可以按章节顺序走熟手直接跳去第5章看避坑也能省下不少时间。2. 三件套的分工与边界为什么中间要转一道dex2jar2.1 apktool负责“解包与回编译”保住资源和smali先说apktool。APK本质上是一个zip压缩包但是里面的AndroidManifest.xml和资源文件都用二进制格式编码过直接用普通解压工具打开之后是一堆不可读的乱码。apktool干的事情就是把这种二进制布局还原成人能看懂的明文它会把AndroidManifest.xml解码成标准XML把res目录下的资源还原成可编辑的文件同时把dex文件反汇编成smali目录。smali是什么它是Dalvik字节码的助记符形式每一条指令对应一个human-readable的文本行。解包完的工程目录里常见结构是res/放资源smali/放dex反汇编出来的smali代码多dex会分成smali_classes2/等目录根目录则是解出来的AndroidManifest.xml、apktool.yml这类元数据文件。这里要理解一个关键点Android应用跑的不是class字节码而是dex字节码所以apktool第一步只负责把apk“摊开”并不负责把dex还原成Java语法。它给出的smali已经是能修改的代码级产物只不过很多人在smali里改逻辑觉得吃力才需要后面两个工具做进一步还原。我一般会先用apktool解包确认资源、Manifest、smali都正常再做下一步。解包这一步如果连报错都没有说明这个包没有做严重加固后面dextojar才有戏如果解包时就提示无法解析dex那基本可以判断这包有壳后面两件套大概率拿不到有效产出。2.2 dex2jar负责“翻译dex字节码”JDK版本很敏感dex2jar的定位是一个翻译器把Dalvik字节码翻译成JVM class字节码然后打包成jar文件。为什么要中转这一道因为jd-gui这类工具只能读class/jar格式它不理解dex字节码。所以apk里的classes.dex必须先变成jarjd-gui才能打开并把每个class进一步还原成近似Java的伪代码。这套工具的整合包里dex2jar通常提供的是shell脚本或者bat脚本对应Linux/macOS和Windows两种环境。脚本名常见为d2j-dex2jar.sh和d2j-dex2jar.bat直接执行时需要注意可执行权限。Windows下最容易踩的坑是路径中的空格和中文脚本内部对路径处理得比较脆弱遇到这类路径经常直接报错、或者生成一个空的jar文件。还有一个非常容易卡住人的点dex2jar对JDK版本极度敏感。老版本dex2jar是在JDK 8时代发布的放在JDK 11、JDK 17环境下经常会报Unsupported class file version花几分钟去查错误代码结果发现只是JAVA_HOME指错了环境。遇到这个问题时最省事的方案不是去换新版的dex2jar而是把JDK临时切到8。多版本JDK共存时我会在脚本执行前单独设置JAVA_HOME不污染全局变量。另外要注意现在的应用大多是多dex结构有classes.dex、classes2.dex、classes3.dex。d2j-dex2jar脚本直接喂apk或者把多个dex分别喂进去都能得到jar但产出物的命名和数量会不同。喂单个dex时输出是单jar喂整个apk时有些版本会整理成一个jar有些版本会按dex顺序生成多个jar这个差异在后面的阅读阶段要心里有数。2.3 jd-gui负责“把jar变成人读的Java伪代码”以及链路边界jd-gui的定位是可视化阅读器。它打开jar之后会按包结构展示类每个类里的方法会以近似Java的语法呈现。但必须有一个预期管理它展示的是“反编译后的伪代码”不是源码。变量名、方法名如果是混淆过的这里只会看到a、b、c这种短名字符串常量还在但注释和原始结构基本全丢。因此真正常见的定位方式是先在jd-gui里确认类名、方法名、关键字符串再到smali里去改具体逻辑。不要指望jd-gui像读IDE源码一样把所有调用关系和类型都还原出来。它最适合干的事情是快速找到“这个App在登录请求里拼接了什么参数”“这个点击事件绑定了哪个方法”定位之后真正动手的位置大概率在apktool解出来的smali里。这套三件套的边界也比较清楚不处理加固后的壳包里有壳时apktool解出来的dex往往只是一层壳的加载代码真正的业务逻辑被加密存放在了so或某份加密资源里这时候dextojar转出来的东西毫无业务价值。不处理so层逻辑底层算法在so里面时需要另开反汇编工具而不是这三件套。很多android逆向助手整合包里还会额外带上jadx和签名工具jadx可以直接从apk一步还原成伪代码省掉dextojar的中转这在第6章会展开讲先不抢戏。3. 反编译实操从拿到APK到在jd-gui里定位目标逻辑3.1 解包apktool d 和几个值得改的参数实战第一步永远是解包。假设拿到一个app.apk我习惯的完整命令是apktool d app.apk -o app_src -f这条命令的意思是把app.apk解包到app_src目录-f表示如果目录已存在就强制覆盖。不加-f时遇到同名输出目录apktool会停下来问你是否覆盖在脚本化操作里很容易因为没人回答而卡住所以自动化处理时一定要带-f。解包完成后目录里最值得关注的有三个位置AndroidManifest.xml、res/、smali/。AndroidManifest.xml是明文XML能直接看到权限、Activity、Service、Application类名res/里是资源文件strings、layout、图片都在这里smali/是后续改逻辑的主要战场。如果只是临时想看某个资源长什么样而不是改逻辑其实不必用apktool直接把apk后缀改成zip解压再单独处理二进制XML的编码问题即可。这里有个小经验解包时报错如果出现在“Could not decode arsc file”这类资源相关的提示多半是apktool版本和APK的编译版本不兼容。常见做法是优先用新版本apktool如果必须用旧版本那就先去安装framework资源。安装命令是apktool if framework-res.apkframework-res.apk可以从设备/system/framework路径拉出来也可以从系统ROM包里拿。这个步骤在深度定制的ROM上尤其重要因为厂商改过系统资源IDapktool不认识时回编译必然失败。3.2 转jardex文件、jar文件与class文件的关系解包完成之后业务dex已经在app_src/目录下等着了。现在把它交给dex2jard2j-dex2jar.sh app.apk -o app.jar直接喂apk文件也支持脚本会自动定位apk内的dex文件。但我个人更推荐先解包再针对dex目录逐个转命令是这样d2j-dex2jar.sh app_src/classes.dex -o classes.jar两种写法产出的jar行为不完全一样。喂apk时它一次处理包里所有dex多dex场景下输出粒度取决于版本有的把多个dex合并到一个jar有的输出多个jar喂单个dex则更可控你明确知道自己转的是哪段代码排查问题也方便。这个阶段经常拿到的产出物是classes-dex2jar.jar这类名字。名字不重要关键是确认jar里有东西。我会用jar命令快速看一眼里面包结构jar tf classes.jar | head -50如果输出是空或者解出来的class寥寥几个先别急着让jd-gui背锅回过去检查dex2jar的JDK环境。另外有些加固应用会在dex里加入特殊指令dex2jar转换时偶尔会中断提示某些opcode无法处理。遇到这种情况可以尝试用jadx直接读apkjadx的容错性要更好。Windows环境记得用bat版本并且尽量把路径放到纯英文目录。之前有一次我把apk放在“下载/测试包/”这种目录里d2j-dex2jar.bat直接连报三次路径不存在改到D:\work\以后一次通过。这不是工具脆弱是它内部拼接路径时对非ASCII字符处理确实激进。3.3 读代码从AndroidManifest入口往下追别在smali里硬读jar到手jd-gui开起来jd-gui classes.jar打开后看到的是反编译后的Java伪代码。很多新手第一屏就懵了类名全是a/b/c不知道该看哪里。正确顺序是先回到apktool解出来的明文AndroidManifest.xml找到入口Activity。入口Activity在Manifest标签里是这样的activity android:namecom.demo.app.MainActivity intent-filter action android:nameandroid.intent.action.MAIN / category android:nameandroid.intent.category.LAUNCHER / /intent-filter /activity拿到入口类名之后再去jd-gui里按这个名字找到类从onCreate方法一路往下读。这样读代码的效率远高于在smali里一行行看汇编。jd-gui里还有个实用功能是“Save All Sources”可以把所有反编译出来的java文件打包导出# 导出后用命令行检索关键字比在GUI里一屏一屏翻快得多 grep -rl password /path/to/saved_src | head -20grep命中的文件列表会给你一张“哪些类跟目标逻辑相关”的地图之后回到jd-gui里针对性地精读。这步在大型项目里极其好用盲目乱点会浪费很多时间。4. 回编译与重签名改完之后怎么让APK重新跑起来4.1 apktool b 回编译--use-aapt2 与 framework 对齐在apktool解包后的目录里做的所有修改最后都要通过回编译重新打包成APK。回编译命令非常短apktool b app_src -o new.apk --use-aapt2输出new.apkapp_src是解包目录这点不要搞反。参数--use-aapt2是让apktool使用新版资源编译器aapt2如果解包时的resources.arsc比较新、或者目标App使用了较新的资源编译特性加上这个参数能减少很多资源相关的回编译失败。老版本apktool默认走的是aapt1两者对资源的处理逻辑有差异遇到资源报错时可以先把--use-aapt2去掉再试一次两边的报错信息往往不同哪个给的信息更明确就顺着哪个查。回编译常见的失败现场有两种。第一种是编码问题报错信息里如果出现乱码符号或提示字符集错误基本是编辑器保存时用了GBK而apktool按UTF-8读文件导致的。解决办法是把所有改动文件统一转成UTF-8无BOM格式Windows下的CMD窗口可以先执行chcp 65001切到UTF-8代码页再操作。第二种是framework资源缺失报错会指向某个resource ID无法解析常见做法是先执行apktool if framework-res.apk把系统框架装进本地静态资源库再重新回编译。4.2 keytool、zipalign、apksigner重签名的完整命令链回编译出来的new.apk是一个“脱过签名”的包里面原始的签名信息已经被apktool清掉了必须重新签名才能安装到设备上。先生成一个自己的签名密钥keytool -genkey -v -keystore my.keystore -alias myalias -keyalg RSA -keysize 2048 -validity 3650-keyalg RSA指定算法-keysize 2048是RSA的推荐长度-validity 3650表示有效期10年。签名这件事最忌讳临时起意生成一个只有30天有效期的密钥后面你会反复用它给多个重新打包的APK签名过期之后所有已安装的包全都得重新签一遍。生成密钥之后正式的签名链是先对齐再签名zipalign -f 4 new.apk aligned.apk apksigner sign --ks my.keystore --ks-key-alias myalias --out signed.apk aligned.apk apksigner verify --verbose signed.apkzipalign的4表示4字节对齐目的是让APK内的资源文件在运行时可以直接映射到内存减少读取时的内存拷贝。顺序很关键先zipalign、后apksigner。如果先签名再对齐签名校验是能过但APK包内的数据对齐信息会被破坏运行时资源读取性能下降部分设备甚至会在解析阶段出问题。apksigner默认会根据minSdkVersion自动决定启用哪些签名方案但为了兼容Android 6.0及以下的设备需要手动把v1签名打开这是apksigner命令行比较容易忽略的点apksigner sign --ks my.keystore --ks-key-alias myalias --v1-signing-enabled true --out signed.apk aligned.apkv2和v3签名方案是Android 7.0和9.0以后引入的老旧设备只认v1。apksigner与传统的jarsigner相比最大的优势是同时支持v1/v2/v3三种签名方案的生成和验证不需要为不同系统版本分别处理。最后一步apksigner verify用于确认签名结果输出里会列出当前包使用的所有签名方案和证书信息这是安装失败时排查问题的第一道证据。4.3 adb安装验证与logcat抓崩溃签名后的signed.apk拿到真机上验证最标准的命令是一组adb install -r signed.apk adb logcat -s AndroidRuntime:E-r表示覆盖安装如果之前已经装过同包名但不同签名的包adb install会直接报出INSTALL_FAILED_UPDATE_INCOMPATIBLE提示你签名不匹配。这时候先卸载旧包再安装adb uninstall com.demo.app adb install signed.apk覆盖安装成功但应用启动后立刻闪退的情况观察logcat时优先过滤AndroidRuntime标签。崩溃堆栈如果停在某个类加载位置通常是改动后的代码里引用了不存在的字段或方法如果堆栈本身是正常的业务代码但退出前出现SecurityException或者PackageManager相关错误那多半是应用自身做了签名校验这在第5章会专门说。正常跑起来的验证流程是安装完成后手动打开App先看首页是否正常再点开你改过逻辑的那个功能最后用logcat的包名进程过滤确认有没有非预期异常adb logcat --pid$(adb shell pidof com.demo.app)这比全量logcat清爽很多一眼能看到当前进程自己的输出。5. 常见问题与避坑排查五个高频翻车点5.1 dex2jar在JDK新版上报Unsupported class file version现象d2j-dex2jar.sh执行后很快就退出终端打印出一长串异常开头是Unsupported class file version或者提示无法读取某个class文件的major version。原因dex2jar的编译目标停留在JDK 8时代JDK 11及以上的class文件版本号它不认。如果你系统里的java命令指向的是新版本JDK工具一启动就会在读class阶段挂掉。解决临时切换到JDK 8再跑dex2jar。我是这样做的export JAVA_HOME/path/to/jdk8 export PATH$JAVA_HOME/bin:$PATH切换后再执行一遍d2j-dex2jar.sh就能顺畅跑完。如果机器上没装JDK 8装一个专门给这类工具用不要动系统默认的JDK。这个坑最大的迷惑性在于错误信息没有直接提dex2jar而是以Java异常的形式出现不熟悉的人容易去查“如何升级dex2jar版本”走很多弯路。5.2 apktool回编译失败编码问题与framework缺失现象apktool b回编译时报错信息里出现invalid resource name或一串疑似乱码的资源名又或者提示某个resource ID对应不上。Windows环境下尤其频繁。原因这里聚集了两个常见根因。第一个是终端编码Windows的CMD默认GBK代码页而apktool强依赖UTF-8解包出来的资源文件大部分是UTF-8编码命令行输出和文件解析互相干扰第二个是framework缺失深度定制的ROM或者较新的Android版本会修改系统资源ID定义apktool本地没有对应的framework-res.apk缓存回编译时无法解析系统引用。解决先切代码页再执行回编译chcp 65001 apktool b app_src -o new.apk --use-aapt2如果切完编码还是报资源ID问题就把framework装上apktool if framework-res.apk装完后再回编译。注意framework-res.apk要从目标Android版本对应的设备或ROM里拉版本不匹配时装了也白装。5.3 安装成功但启动崩溃签名校验与完整性校验现象adb install成功点开App后瞬间退出logcat在崩溃前打印出签名相关异常有时会看到SecurityException: Invalid signature。有的App更隐蔽App本身能启动但关键页面打不开退出不崩溃但功能压制。原因目标App在代码或so层做了签名校验运行期读取当前APK的签名信息和自己内置的合法签名做比对发现不一致就直接拒绝运行。这是很多商业App的自我保护手段。不是签名步骤没做对而是你用了自己的证书App不认识。解决先确认自己重签名后的证书信息apksigner verify --print-certs signed.apk再把原始APK的证书也打印出来对比apksigner verify --print-certs original.apk两个证书的SHA-256完全不同说明App确实在对比签名。想要让测试跑通常见的本地测试做法是找到App内置的合法签名hash把自己新签名的hash替换进去或者用Hook方案绕过校验。但这里要说清楚绕过别人的签名校验涉及突破应用保护只建议在自己有权测试的范围内做本地验证。更稳妥的思路是重新评估这次改动的目标——如果只是想看某个界面的交互逻辑静态分析配合动态调试也能完成不一定非要在原包上重签名。5.4 手改AndroidManifest导致解析失败现象安装时直接提示“解析包出现问题”或者adb install返回INSTALL_PARSE_FAILED。原因最常见的操作是直接编辑解包后的AndroidManifest.xml改包名、改权限但改坏了XML结构比如标签不闭合、属性值没有转义、把一个activity节点删掉了一半。还有一种情况是把包名改了之后没有同步改Application类、Provider的authority等需要保持一致的属性。解决改完Manifest后先做一次静态校验用aapt2自带的能力aapt2 dump badging new.apk | head -30如果aapt2能正常输出包名、版本、启动Activity说明Manifest结构没问题。如果这里就报错回到XML里逐行检查改动位置。另外提醒一个老生常谈的点Provider的authority往往是全局唯一的很多App内部用ContentProvider跨进程通信只改主包名不改authority装上之后照样能解析成功但运行时provider找不到功能明显异常。5.5 回编译后中文乱码或资源丢失现象回编译安装后界面上的中文变成乱码或者原本应该显示的图标、文案直接消失。重新解包检查res目录发现某些字符串文件内容还在但显示不对。原因编辑资源时保存的编码不是UTF-8。最常见的场景是在Windows上用记事本编辑strings.xml默认保存为ANSI/GBKapktool回编译按UTF-8读取字符就错乱。资源丢失则不一样它多半是你解包时用了自定义参数比如在解包命令里加了-r或-s这类限制参数导致部分资源没有被完整还原回编译时自然缺料。解决所有编辑器统一设置UTF-8无BOM格式避免在资源文件里夹带中文之外的编码字符。修改前先确认解包时用的参数看apktool.yml里有没有特殊配置如果你不确定当初怎么解的包重新用完整模式解一遍再改apktool d app.apk -o app_src_clean -f解包参数这种东西很容易在调试时顺手加一个然后忘掉后面回编译出了问题完全没有任何头绪。遇到过几次这种疑似玄学的资源丢失之后我现在每次解包前都会把完整命令贴到终端显眼处强制自己全程盯着参数跑。6. 进阶验证技巧用jadx对照和smali插桩交叉验证反编译器本质上是个概率工具它输出的“Java代码”是基于字节码反推的近似结果。变量名丢了、控制流被改写、部分调用被内联这些都是常态。如果只凭jd-gui的输出就动手改smali很容易把逻辑改反。更稳妥的做法是引入第二个反编译结果做对照。在android逆向助手的整合包里通常会放着jadx的命令行工具。jadx可以直接从APK一步还原出伪代码而且容错率比“apktooldex2jarjd-gui”的串联链路更高。我一般会在jd-gui定位到目标类之后再用jadx把同一个APK完整导出一份做对照jadx -d jadx_out app.apk对比一下两个工具对同一个类的还原结果。如果jd-gui说某个分支条件是等于0jadx里却显示不等于0那说明这段逻辑还原不可信需要结合smali手工确认。双击一份smali代码从头看到尾比争执哪个工具对更快const/4 v0, 0x0 if-eqz v0, :cond_a在smali层面if-eqz就是“等于零跳转”对应Java里的if (x 0)。两个反编译器如果在这里打架smali会给你最终答案。多一个工具不是端架子是真能拦住冲动改错。确认逻辑之后动态验证一样有价值。经典做法是在smali的目标方法入口插入一条日志调用const-string v0, TraceTag invoke-static {v0, v1}, Landroid/util/Log;-i(Ljava/lang/String;Ljava/lang/String;)I假定v1寄存器里是你要观察的参数值插入后重新回编译、签名、安装然后在logcat里只过滤自己的Tagadb logcat -s TraceTag:D这样做一次你就能确认静态分析得出的结论和运行时真实数据是否一致。我见过太多人改完代码只看界面效果不看日志结果界面是正常的但数据流完全不是他想的那样。那次我在一个登录逻辑里只凭jd-gui的结果改了一个跳转条件回编译、签名、安装都没问题App也能正常启动但登录成功后页面跳去错误的地方。后来插桩打日志一看那个条件判断的寄存器值跟我理解的完全是两个来源。从那以后我每次改完smali都会强制把反编译、回编译、安装验证、日志观察全流程走一遍确认每个阶段的输出是稳定的而不是侥幸通过。希望帮到你。本文还有配套的精品资源点击获取