
JADX용 Python 바인딩.
JADX를 위한 Python 바인딩 (JPype 기반). Android APK 및 DEX 파일을 Python에서 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는 서브프로세스 오버헤드 없이 이 기능을 Python에 제공합니다. JADX가 JPype를 통해 프로세스 내에서 실행됩니다.
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), "메서드")
# 정규화된 이름으로 검색
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} 호출자: {[c.name for c in method.callers]}")
# 패키지 탐색
for pkg in jadx.packages:
print(pkg.name, len(pkg.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() # 기존 JVM에 JADX JAR 추가 – 충돌 없음
사용자 정의 JADX 설치:
# 환경 변수 사용
# export JADX_HOME=/opt/jadx
# 또는 런타임 시
import pyjadx
pyjadx.start(jadx_home="/opt/jadx")
JAR 캐싱: JADX JAR은 최초 사용 시 Maven Central에서 자동 다운로드되며 ~/.pyjadx/jars/<version>/에 캐시됩니다.
MIT