
DEX → Rust로 구현된 Java 디컴파일러 — 빠르고 점진적인 분석, 이중 언어 CLI
English | 简体中文
ddc는 Android DEX 바이트코드를 읽을 수 있는 Java로 다시 디컴파일합니다 —
실제 앱 규모에서, 데이터베이스처럼 쿼리 가능하게, 그리고 javac로 검증됩니다:
일곱 개의 실제 APK에서 생성한 909,689개 파일 전부가 깨끗하게 파싱됩니다.
javac를
통과합니다; 대소문자만 다른 이름 쌍(X/Cua vs X/cua)의 모든 클래스가
마지막 하나가 조용히 덮어쓰는 대신 각자의 파일로 보존됩니다.(a) -> …, Cls::name, a + b).v12 대신 jadx 스타일의 지역 이름(str,
getName() → name, Kotlin Intrinsics 파라미터 문자열); IntDef 리터럴이
기본적으로 상수로 렌더링됩니다(setVisibility(8) → View.GONE;
내장 android-37 도메인 테이블, --symbols로 재정의); Kotlin null 검사
노이즈는 제거되고 합성 access$NNN 브리지는 호출 지점에서 인라인됩니다.DDC_LANG=zh|en으로 강제; 영어 폴백).jdc-core 위에 구축되었습니다.macOS (Homebrew):
brew install ejfkdev/tap/ddc
Windows (Scoop) — 버킷을 한 번 추가한 뒤 이름으로 설치하세요 (scoop은
user/repo/app 형태를 그대로 해석하지 않습니다 — 이슈 #3):
scoop bucket add ejfkdev https://github.com/ejfkdev/scoop-bucket
scoop install ddc
# 또는 버킷 없이 매니페스트 URL에서 바로 설치:
scoop install https://raw.githubusercontent.com/ejfkdev/scoop-bucket/main/bucket/ddc.json
cargo-binstall (모든 플랫폼 — 컴파일 대신 미리 빌드된 릴리스 바이너리를 가져옵니다):
cargo binstall ddc-cli
바이너리: 모든 릴리스는
linux-amd64, linux-arm64, windows-amd64, windows-arm64,
macos-amd64, macos-arm64용 원시 바이너리(아카이브 없음)를 제공합니다 —
비 macOS 빌드는 UPX로 압축됩니다.
소스에서 (Rust stable):
git clone https://github.com/ejfkdev/ddc && cd ddc
cargo build --release
ddc app.apk # 전체 디컴파일 → app-out/
ddc app.apk -c com.example.Foo # 한 클래스를 stdout으로
ddc app.apk -o - | less # 전부 stdout으로
ddc info app.apk # 앱 컨텍스트 (arsc를 통한 label, package,
# version, md5) + dex별 카운트
ddc mainactivity app.apk # 진입점: package + launcher
ddc findrefs app.apk string token # 모든 const-string "token" 위치
ddc getmethod app.apk Foo.toString # 한 메서드, 모든 오버로드
ddc pkg app.apk --app -o own/ # 앱 자체 코드만
전체 옵션과 예제: ddc --help (워크플로별로 그룹화된 서브커맨드 메뉴).
완전한 레퍼런스 — 모든 옵션의 의미, 모든 서브커맨드의 출력 형식과 동작 —
는 docs/cli.md에 있습니다 (中文).
일곱 개의 실제 APK, 릴리스 빌드, 3회 실행 평균 (Apple Silicon, 6P+12E). 39개 APK 검증 코퍼스(4.08M 디컴파일 파일, APK별 wall time / peak RSS / javac 파싱 게이트)는 docs/validation.md에 있습니다 (中文).
| APK | 크기 | 전체 디컴파일 | Peak RSS |
|---|---|---|---|
| reqable | 34 MB | 0.25s | 139 MB |
| Telegram | 62 MB | 5.64s | 1479 MB |
| 139 MB | 5.87s (99,277 파일 — 대소문자 변형 클래스 쌍 모두 보존) | 1116 MB | |
| 226 MB | 5.03s | 1172 MB | |
| weixin | 268 MB | 11.61s | 1339 MB |
| lark | 398 MB | 5.52s | 1831 MB |
| 374 MB | 15.92s | 2459 MB |
같은 APK에 대한 쿼리 서브커맨드 (셀: 시간 / peak RSS;
strings -f <package> --with-locations, 패키지 문자열과 메서드 onCreate에
대한 findrefs, 각 앱의 launcher 클래스에 대한
hierarchy/disasm/getclass):
| Command | reqable | Telegram | weixin | lark | |||
|---|---|---|---|---|---|---|---|
info | 0.12s / 40MB | 0.21s / 88MB | 0.42s / 305MB | 0.65s / 610MB | 0.79s / 550MB | 1.10s / 907MB | 1.08s / 1240MB |
listclasses | 0.04s / 21MB | 0.06s / 84MB | 0.08s / 93MB | 0.13s / 396MB | 0.21s / 417MB | 0.20s / 299MB | 0.27s / 391MB |
manifest | 0.03s / 7MB | 0.03s / 14MB | 0.02s / 20MB | 0.03s / 43MB | 0.04s / 31MB | 0.03s / 28MB | 0.03s / 47MB |
mainactivity | 0.04s / 24MB | 0.06s / 86MB | 0.08s / 224MB | 0.10s / 358MB | 0.13s / 371MB | 0.14s / 421MB | 0.21s / 554MB |
res | 0.02s / 7MB | 0.03s / 15MB | 0.03s / 22MB | 0.05s / 60MB | 0.04s / 32MB | 0.04s / 31MB | 0.05s / 53MB |
largest | 0.05s / 29MB | 0.08s / 78MB | 0.15s / 236MB | 0.31s / 500MB | 0.32s / 500MB | 0.46s / 676MB | 0.66s / 810MB |
strings | 0.05s / 24MB | 0.10s / 85MB | 0.21s / 222MB | 0.39s / 354MB | 0.45s / 395MB | 0.52s / 431MB | 0.81s / 551MB |
findrefs-string | 0.04s / 26MB | 0.05s / 70MB | 0.06s / 214MB | 0.10s / 403MB | 0.12s / 446MB | 0.07s / 335MB | 0.14s / 871MB |
findrefs-method | 0.05s / 26MB | 0.07s / 70MB | 0.07s / 219MB | 0.09s / 410MB | 0.10s / 458MB | 0.10s / 620MB | 0.15s / 896MB |
members | 0.07s / 23MB | 0.21s / 86MB | 0.62s / 222MB | 1.32s / 366MB | 1.17s / 381MB | 1.64s / 443MB | 2.66s / 572MB |
hierarchy | 0.04s / 24MB | 0.05s / 86MB | 0.09s / 212MB | 0.12s / 396MB | 0.14s / 386MB | 0.17s / 429MB | 0.22s / 548MB |
disasm | 0.04s / 23MB | 0.07s / 88MB | 0.09s / 214MB | 0.12s / 371MB | 0.13s / 392MB | 0.16s / 422MB | 0.20s / 533MB |
getclass | 0.05s / 34MB | 0.28s / 182MB | 0.14s / 357MB | 0.33s / 740MB | 0.37s / 942MB | 0.50s / 1235MB | 0.76s / 1651MB |
| 아키텍처 | 크레이트, lift/structure/emit 파이프라인, DEX 버전, invoke-custom (中文) |
| CLI 레퍼런스 | 모든 옵션과 서브커맨드 상세 (中文) |
| 서브커맨드 | 점진적 분석 레퍼런스 (中文) |
| 벤치마크 | 타이밍, 메모리, 방법론, ASC 비교 (中文) |
| 성능 엔지니어링 | 5분 → 6초: 여섯 라운드, 측정된 막다른 길 (中文) |
| 코퍼스 검증 | 실제 APK 39개, 4.08M 파일, javac 파싱 클린, 발견 및 수정된 버그 (中文) |
소거된 타입 (DEX에는 Signature가 없음); d8-desugared -$$Lambda$ 클래스는
별도 파일로 유지됨; 일부 R8 몬스터 메서드는 타임아웃으로 성능이 저하됨
(그리고 데드라인으로 잘린 소수의 메서드는 실행마다 달라질 수 있음);
pattern-switch는 desugared 디스패치 체인으로 렌더링됨. 위의 javac 게이트는
SYNTAX 게이트입니다 — 시맨틱 진단(Android 클래스패스 누락, 그리고 드물게
레지스터가 많은 몬스터 메서드에서 타입이 혼동된 지역 변수)은 출력에 남습니다.
자세한 내용: 아키텍처.
cargo test # 56 tests
MIT © ejfkdev