简介安卓逆向助手是一款面向Android应用开发者与安全研究人员的图形化逆向工具旨在降低APK反编译与分析的门槛让初学者也能快速理解应用内部结构。它把dex转jar、jar反编译Java、资源文件提取、Java视图转换等流程集成到统一界面用户拖入APK即可完成操作无需记忆DOS命令行。资源包共69个文件以jar、bat、sh、exe为主辅以txt说明、pem与pk8签名文件、so库及readme等涵盖反编译、签名、打包、对齐等常用组件压缩包约15.18MB结构紧凑便于随取随用。目前已有216人学习下载。借助它读者可查看XML布局、图片与字符串资源排查数据泄露、权限滥用等安全隐患并借助反混淆思路还原混淆代码适合安全审计、故障排查与Android学习实践。1. 安卓逆向助手从抓包到反编译一套能落地的分析链路做安卓安全分析的人迟早会碰到一个绕不开的场景手上只有一个 APK没有源码没有文档但你需要搞清楚它到底在干什么——请求了哪些接口、加密参数怎么生成的、有没有偷偷上传设备信息。这时候「安卓逆向助手」就不是一个工具的名字而是一整条分析链路的代称从 APK 解包、DEX 反编译、抓包定位到动态 Hook 验证每一步都需要趁手的工具和清晰的思路。这篇文章面向的是有基本 Android 开发或安全基础的工程师不管你是在做竞品分析、漏洞挖掘还是恶意样本研判这套链路都能直接复用。我不会只告诉你「用 jadx 打开就行」而是把每个环节的参数怎么调、什么情况下会翻车、怎么验证结论都拆开讲清楚。读完你应该能独立完成一个中等复杂度 APK 的静态动态分析并且知道哪些坑可以提前绕开。2. 静态分析起步APK 解包与 DEX 反编译的选型逻辑2.1 为什么先静态再动态分析顺序背后的成本账很多人拿到 APK 第一反应是直接上真机跑起来抓包这个顺序其实是反的。静态分析的成本远低于动态分析——你不需要 root 设备、不需要绕过反调试、不需要担心加固壳把 Frida 检测出来。一个 APK 用 jadx 打开几分钟内就能看到包结构、权限声明、主要 Activity 和网络请求框架这些信息能帮你快速判断这个 App 值不值得花时间做动态分析。我一般的流程是先apktool解包看AndroidManifest.xml和资源文件再用jadx反编译 DEX 看 Java 层逻辑如果发现关键逻辑在 native 层或者被加固了才转入动态分析。这个顺序能帮你省掉大量无效的动调时间。选型上apktool和jadx是目前最稳定的组合。apktool负责资源解码和 smali 反汇编jadx负责 DEX 到 Java 的反编译。两者互补apktool能还原出可读的 XML 和 smali适合改包重打包jadx的 Java 伪代码可读性更好适合快速理解逻辑。至于dex2jarjd-gui那套老组合在新版本 DEX 格式上经常出问题除非你有特殊需求否则不建议作为主力工具。2.2 用 apktool 解包命令参数与资源还原的边界先装好 apktool然后执行解包。这里有个细节apktool 的版本要和 APK 的 targetSdkVersion 大致匹配太老的版本解新包会报brut.androlib.AndrolibException错误。# 解包 APK 到指定目录-f 强制覆盖已有目录-o 指定输出路径 apktool d -f -o ./output_app target.apk # 如果只需要 smali 不需要资源加 -s 跳过资源解码速度更快 apktool d -f -s -o ./output_smali target.apk # 重新打包改完 smali 或资源后 apktool b ./output_app -o repacked.apk解包完成后重点看三个地方AndroidManifest.xml里的权限和组件声明、res/values/strings.xml里的硬编码字符串、smali/目录下的主逻辑。AndroidManifest.xml里如果看到android:debuggabletrue恭喜你动态调试的门槛直接降了一半。strings.xml里经常能找到 API 地址、密钥之类的硬编码信息这是最容易被忽略的情报点。参数说明-f强制覆盖避免残留旧文件导致混淆-s跳过资源解码在只关心代码时能省不少时间-r跳过资源反编译但保留原始资源文件适合资源文件损坏导致解包失败的场景。2.3 jadx 反编译批量导出与交叉引用检索apktool 给你的是 smali可读性差。jadx 直接把 DEX 转成 Java 伪代码效率高得多。命令行版本适合批量处理和自动化。# 基本反编译输出到目录 jadx -d ./jadx_output target.apk # 导出为 Gradle 项目结构方便用 IDE 打开 jadx -d ./jadx_project --export-gradle target.apk # 只反编译指定包减少输出量 jadx -d ./jadx_output --single-class com.example.network target.apk # 显示反编译过程中的错误信息便于判断哪些类失败了 jadx -d ./jadx_output --show-bad-code target.apk反编译完成后用 jadx-gui 打开输出目录重点用搜索功能定位关键逻辑。搜索关键词建议按这个优先级来okhttp、retrofit、HttpURLConnection定位网络层encrypt、sign、md5、aes定位加密逻辑getDeviceId、getImei、getMac定位设备信息采集。jadx-gui 的「查找用法」功能右键 → Find Usages能帮你快速追踪一个方法的调用链这是静态分析里最常用的操作。注意jadx 对混淆过的代码反编译质量会下降变量名变成a、b、c这时候需要结合 smali 和动态调试来还原逻辑。如果发现大量// decompilation failed说明代码被混淆或加固了直接转动态分析更划算。3. 动态抓包与 Hook让加密参数现出原形3.1 抓包方案的选型从 HTTP 到 HTTPS 的完整覆盖静态分析能看到代码逻辑但加密参数的具体值、请求的完整结构还是得靠抓包。安卓抓包的核心问题是证书信任Android 7.0 以后用户安装的 CA 证书默认不被 App 信任除非 App 主动配置了network_security_config。常见做法有三种一是用objection或Frida绕过 SSL Pinning二是把证书装到系统证书目录需要 root三是用mitmproxy配合Frida做透明代理。我一般先用mitmproxy起一个代理看能不能直接抓到明文如果 App 做了证书校验再上 Frida 脚本绕过。# 启动 mitmproxy监听 8080 端口-w 保存流量到文件 mitmproxy -p 8080 -w traffic.flow # 或者用 mitmdump 无界面模式适合长时间抓包 mitmdump -p 8080 -w traffic.flow --set block_globalfalse手机端设置代理指向你的机器 IP 和 8080 端口然后安装 mitmproxy 的 CA 证书。如果抓不到 HTTPS 流量先检查 App 是否使用了 SSL Pinning。用 Frida 挂载一个通用的绕过脚本// Frida 脚本绕过常见的 SSL Pinning 实现 Java.perform(function() { // 绕过 TrustManager 校验 var TrustManager Java.use(javax.net.ssl.X509TrustManager); var SSLContext Java.use(javax.net.ssl.SSLContext); // 替换 checkClientTrusted 和 checkServerTrusted 为空实现 var TrustManagerImpl Java.registerClass({ name: com.custom.TrustManager, implements: [TrustManager], methods: { checkClientTrusted: function(chain, authType) {}, checkServerTrusted: function(chain, authType) {}, getAcceptedIssuers: function() { return []; } } }); // Hook SSLContext.init 替换 TrustManager SSLContext.init.overload( [Ljavax.net.ssl.KeyManager;, [Ljavax.net.ssl.TrustManager;, java.security.SecureRandom ).implementation function(keyManager, trustManager, secureRandom) { this.init(keyManager, [TrustManagerImpl.$new()], secureRandom); }; });这段脚本的逻辑是创建一个自定义的 TrustManager把所有证书校验方法都改成空实现然后 HookSSLContext.init方法把原来的 TrustManager 替换掉。这样 App 在建立 HTTPS 连接时就不会校验证书mitmproxy 就能解密流量了。参数说明Java.perform确保在 Java 虚拟机加载完成后执行Java.registerClass动态注册一个类overload指定要 Hook 的方法签名。如果 App 用了 OkHttp 的CertificatePinner还需要额外 Hookokhttp3.CertificatePinner.check方法。3.2 Frida Hook 关键函数定位加密入口的实战方法抓包只能看到密文要搞清楚加密逻辑得用 Frida Hook 关键函数。最常见的场景是请求里有个sign参数你需要知道它是怎么算出来的。思路是先静态分析找到可疑的加密方法然后用 Frida 打印它的输入输出。比如你在 jadx 里看到一个nativeSign(String data)方法就可以这样 Hook// Hook 指定类的指定方法打印参数和返回值 Java.perform(function() { var TargetClass Java.use(com.example.security.SignUtil); // Hook 静态方法 TargetClass.nativeSign.overload(java.lang.String).implementation function(data) { console.log([*] nativeSign 输入: data); var result this.nativeSign(data); console.log([*] nativeSign 输出: result); return result; }; // Hook 实例方法 var NetworkHelper Java.use(com.example.network.NetworkHelper); NetworkHelper.buildParams.overload(java.util.Map).implementation function(params) { console.log([*] buildParams 输入: JSON.stringify(params)); var result this.buildParams(params); console.log([*] buildParams 输出: result); return result; }; });启动 Frida 的方式frida -U -f com.example.app -l hook.js --no-pause。-U指定 USB 设备-f启动 App 并挂起-l加载脚本--no-pause让 App 继续运行。如果方法被混淆了类名和方法名都是a、b可以换一种思路Hook 所有返回 String 且参数包含 String 的方法通过调用栈反推关键方法。这种「广撒网」的方式效率低但有效适合混淆严重的场景。// 广撒网Hook 所有 String 到 String 的方法打印调用栈 Java.perform(function() { var StringClass Java.use(java.lang.String); // 遍历所有已加载的类 Java.enumerateLoadedClasses({ onMatch: function(className) { if (className.indexOf(com.example) -1) return; try { var clazz Java.use(className); var methods clazz.class.getDeclaredMethods(); methods.forEach(function(method) { var name method.getName(); var returnType method.getReturnType().getName(); var paramTypes method.getParameterTypes(); // 筛选返回 String 且参数含 String 的方法 if (returnType java.lang.String paramTypes.length 0) { // 这里可以进一步 Hook但要注意性能开销 } }); } catch (e) {} }, onComplete: function() {} }); });注意广撒网 Hook 的性能开销很大容易导致 App 卡死或崩溃。建议先用Java.enumerateLoadedClasses列出所有类找到可疑的类名后再精确 Hook不要一上来就 Hook 所有方法。3.3 脱壳与反调试对抗加固场景下的应对策略如果 APK 被加固了比如 360 加固、腾讯乐固jadx 反编译出来的代码只有壳的加载逻辑真正的 DEX 在运行时才解密。这时候需要先脱壳。常见的脱壳方案有Frida-DEXDump、fart、youpk 等。Frida-DEXDump 的原理是在内存中搜索 DEX 文件头dex\n035或dex\n036然后把完整的 DEX dump 出来。# 使用 Frida-DEXDump 脱壳 # 先启动 App然后执行 frida -U -f com.example.app -l dexdump.js --no-pause # 或者用 Python 版本 python3 dexdump.py -u com.example.app脱壳的时机很关键太早 DEX 还没解密完太晚可能已经被卸载。一般建议在 App 启动后 3-5 秒执行脱壳或者 HookApplication.onCreate方法在回调里触发脱壳。反调试对抗方面常见的检测手段包括检测 Frida 端口、检测frida-server进程名、检测/proc/self/maps里的异常模块。对应的绕过方式修改frida-server的默认端口和进程名用magisk模块隐藏 root用Frida的--enable-jit选项绕过某些检测。提示脱壳和反调试对抗是猫鼠游戏没有一劳永逸的方案。建议先判断加固类型再选择对应的脱壳工具不要盲目上重型方案。4. 避坑与排查安卓逆向中那些让人翻车的细节4.1 反编译出来全是乱码或空方法现象jadx 打开 APK大部分类显示// decompilation failed或者方法体是空的。原因APK 被加固或用了高级混淆如控制流平坦化、字符串加密。加固壳会在运行时解密 DEX静态反编译只能看到壳代码。解决先用apktool解包看assets/目录下有没有可疑的.so或.dex文件判断加固类型。然后转动态脱壳用 Frida-DEXDump 或 fart 把内存中的 DEX dump 出来再用 jadx 反编译 dump 出来的 DEX。如果混淆严重结合 smali 和动态 Hook 还原逻辑。4.2 抓包只能看到 CONNECT 请求没有明文现象mitmproxy 里只看到CONNECT请求看不到具体的 HTTP 请求和响应。原因App 使用了 SSL Pinning或者客户端证书校验失败导致连接被拒绝。解决先确认 mitmproxy 的 CA 证书是否安装正确Android 7.0 需要装到系统证书目录。如果证书没问题用 Frida 绕过 SSL Pinning。如果 App 用了双向认证客户端证书需要从 APK 里提取客户端证书通常在res/raw/或assets/下导入到 mitmproxy 的客户端证书配置里。4.3 Frida 启动就崩溃或提示找不到进程现象frida -U -f com.example.app执行后App 闪退或者 Frida 报unable to find process。原因App 检测到了 Frida主动退出或者frida-server没有以 root 权限运行或者 App 用了多进程Frida 附加到了错误的进程。解决先确认frida-server是否在运行adb shell ps | grep frida端口是否被占用。如果 App 有反 Frida 检测用frida-server的--rename选项修改进程名或者用magisk模块隐藏。多进程场景下用frida -U -f com.example.app --no-pause启动后再用frida-ps -U找到目标进程名手动附加。4.4 Hook 到了方法但参数打印不出来现象Frida 脚本执行成功但console.log打印的参数是[object Object]或者乱码。原因参数类型不是基本类型而是自定义对象或数组直接console.log无法序列化。解决用JSON.stringify序列化对象或者用Java.use(java.lang.String).$new(param)转换。对于 byte 数组用Java.array(byte, param)转换后再打印。对于 Map 类型遍历entrySet逐个打印。4.5 重打包后 App 无法安装或闪退现象用 apktool 重新打包后adb install报INSTALL_FAILED_INVALID_APK或者安装成功但启动闪退。原因签名不一致、资源文件损坏、smali 修改引入了语法错误。解决重打包后必须重新签名用apksigner或jarsigner且签名要和原包一致如果 App 有签名校验。资源文件损坏的话用apktool b时加--use-aapt2选项。smali 语法错误的话用smali工具单独编译修改过的 smali 文件看报错信息定位问题。5. 进阶技巧用自动化脚本把重复劳动压缩到极致当你分析过十几个 APK 之后会发现很多步骤是重复的解包、反编译、搜索关键词、抓包、Hook。这些都可以用脚本自动化。我一般会写一个 Python 脚本把 apktool、jadx、grep 串起来一键完成初步分析。import subprocess import os import sys def analyze_apk(apk_path, output_dir): 自动化分析 APK解包、反编译、搜索关键词 if not os.path.exists(output_dir): os.makedirs(output_dir) # 1. apktool 解包 print([*] 解包中...) subprocess.run([apktool, d, -f, -o, os.path.join(output_dir, apktool_out), apk_path], capture_outputTrue) # 2. jadx 反编译 print([*] 反编译中...) subprocess.run([jadx, -d, os.path.join(output_dir, jadx_out), --show-bad-code, apk_path], capture_outputTrue) # 3. 搜索关键词 keywords [encrypt, sign, md5, aes, token, api, secret] jadx_dir os.path.join(output_dir, jadx_out) print([*] 搜索关键词...) for kw in keywords: result subprocess.run([grep, -r, -l, -i, kw, jadx_dir], capture_outputTrue, textTrue) if result.stdout: print(f [{kw}] 命中文件:) for line in result.stdout.strip().split(\n)[:5]: print(f {line}) # 4. 提取 AndroidManifest 关键信息 manifest os.path.join(output_dir, apktool_out, AndroidManifest.xml) if os.path.exists(manifest): print([*] AndroidManifest 权限:) with open(manifest, r, encodingutf-8) as f: content f.read() import re permissions re.findall(randroid:name(android\.permission\.[^]), content) for p in set(permissions): print(f {p}) if __name__ __main__: if len(sys.argv) 3: print(用法: python analyze.py apk_path output_dir) sys.exit(1) analyze_apk(sys.argv[1], sys.argv[2])这个脚本的逻辑很直接依次调用 apktool 和 jadx然后用 grep 搜索常见的关键词最后从 AndroidManifest 里提取权限列表。参数说明apk_path是目标 APK 路径output_dir是输出目录。关键词列表可以根据你的分析目标调整比如做恶意样本分析时加上sms、contact、location等。进阶用法是把 Frida Hook 也集成进去用frida-python库在脚本里启动 Frida自动加载 Hook 脚本把抓到的参数输出到文件。这样整个分析流程就是跑一遍脚本 → 看输出报告 → 针对可疑点手动深入。效率能提升好几倍。我自己的习惯是每分析一个新样本先把脚本跑一遍把输出结果存到一个以 APK 文件名命名的目录里。这样积累下来就是一个自己的样本分析库以后遇到类似的样本可以直接对比。这个习惯帮我省了很多重复劳动也希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?