Python 绑定,通过 JPype 连接 JADX。在 Python 中反编译 Android APK 和 DEX 文件为 Java 源代码。
from pyjadx import Jadx
with Jadx("app.apk") as jadx:
for cls in jadx.classes:
print(cls.full_name)
print(cls.code)
JADX 是领先的开源 Android 反编译器——它能从 Dalvik 字节码生成干净的 Java/Kotlin 源代码,保留类层次结构、泛型、异常处理和注解。pyjadx 通过 JPype 将 JADX 集成到 Python 中,无需子进程开销:JADX 在进程中运行。
pip install pyjadx
要求: JDK 11+(JADX JAR 在首次使用时自动下载)。
from pyjadx import Jadx
with Jadx("app.apk") as jadx:
# 所有顶层类(内部类通过 cls.inner_classes 访问)
for cls in jadx.classes:
print(cls.full_name, len(cls.methods), "methods")
# 按完全限定名搜索
main = jadx.search_class("com.example.MainActivity")
if main:
print(main.code)
# 方法级反编译
for method in main.methods:
print(f"{method.name}: {method.code}")
# 交叉引用
for method in main.methods:
print(f"{method.name} called by: {[c.name for c in method.callers]}")
# 包导航
for pkg in jadx.packages:
print(pkg.name, len(pkg.classes), "classes")
| 格式 | 示例 |
|---|---|
| APK | Jadx("app.apk") |
| DEX | Jadx("classes.dex") |
| 多 DEX APK | 透明处理——所有类合并 |
Jadx(path, *, threads=None, mode="auto", code_cache=False)主入口。建议作为上下文管理器使用,或手动调用 load() / close()。
| 参数 | 描述 |
|---|---|
path | APK 或 DEX 文件路径 |
threads | JADX 线程池大小(None = CPU 核数) |
mode | "auto"、"restructure"、"simple" 或 "fallback" |
code_cache | False = 内存缓存(默认),True = 磁盘缓存 |
属性:
| 属性 | 类型 | 描述 |
|---|---|---|
classes | list[JavaClass] | 所有 DEX 文件中的顶层类 |
packages | list[JavaPackage] | 包级导航 |
class_count | int | 顶层类数量 |
java | JObject | 底层 jadx.api.JadxDecompiler 的逃生出口 |
方法:
| 方法 | 描述 |
|---|---|
load() | 加载并解析类(由 __enter__ 调用) |
close() | 释放资源(由 __exit__ 调用) |
decompile_all() | 急切地反编译所有类 |
search_class(name) | 通过完全限定名查找类 |
JavaClass| 属性 | 类型 | 描述 |
|---|---|---|
name | str | 简称("MainActivity") |
full_name | str | 完全限定名("com.example.MainActivity") |
package | str | 包名 |
code | str | 反编译的 Java 源代码(惰性,已缓存) |
smali | str | Smali 反汇编(惰性,已缓存) |
methods | list[JavaMethod] | 该类中的方法 |
fields | list[JavaField] | 该类中的字段 |
inner_classes | list[JavaClass] | 内部/匿名类 |
declaring_class | JavaClass | None | 父类(如果是内部类) |
top_class | JavaClass | 最外层封闭类 |
dependencies | list[JavaClass] | 该类依赖的类 |
is_inner | bool | 是否为内部类 |
java | JObject | jadx.api.JavaClass 的逃生出口 |
JavaMethod| 属性 | 类型 | 描述 |
|---|---|---|
name | str | 方法名 |
full_name | str | 完全限定名(含类名) |
code | str | 反编译的源代码(惰性,已缓存) |
callers | list[JavaMethod] | 调用此方法的方法(惰性,已缓存) |
callees | list[JavaMethod] | 此方法调用的方法(惰性,已缓存) |
override_related | list[JavaMethod] | 双向重写链 |
declaring_class | JavaClass | 该方法所属的类 |
java | JObject | jadx.api.JavaMethod 的逃生出口 |
JavaField| 属性 | 类型 | 描述 |
|---|---|---|
name | str | 字段名 |
full_name | str | 完全限定名(含类名) |
type | str | 字段类型(字符串形式) |
callers | list[JavaMethod] | 引用该字段的方法(惰性,已缓存) |
declaring_class | JavaClass | 该字段所属的类 |
java | JObject | jadx.api.JavaField 的逃生出口 |
JavaPackage| 属性 | 类型 | 描述 |
|---|---|---|
name | str | 完整包名 |
classes | list[JavaClass] | 该包中的类 |
sub_packages | list[JavaPackage] | 子包 |
java | JObject | jadx.api.JavaPackage 的逃生出口 |
每个包装器都通过 .java 暴露其底层的 JADX Java 对象。这允许你调用我们尚未包装的任何 JADX API:
with Jadx("app.apk") as jadx:
cls = jadx.search_class("com.example.Foo")
# 直接调用 JADX Java API
code_info = cls.java.getCodeInfo()
pyjadx 能够与同一进程中的其他 JPype 使用者(例如 PyGhidra)共存。如果 JVM 已在运行,pyjadx.start() 会将 JADX JAR 添加到现有类路径中。如果尚未运行,则会启动一个。
import pyghidra
pyghidra.start() # 为 Ghidra 启动 JVM
import pyjadx
pyjadx.start() # 将 JADX JAR 添加到现有 JVM — 无冲突
自定义 JADX 安装:
# 通过环境变量
# export JADX_HOME=/opt/jadx
# 或在运行时
import pyjadx
pyjadx.start(jadx_home="/opt/jadx")
JAR 缓存: JADX JAR 在首次使用时自动从 Maven Central 下载,并缓存到 ~/.pyjadx/jars/<version>/。
MIT