
크로스 플랫폼 APK/DEX 메서드 파인더: 호출 체인 추적, ProGuard 난독 해제 및 숨겨진 API 탐지 기능
크로스 플랫폼 APK/DEX 메서드 및 필드 참조 파인더로, 호출 체인 추적, ProGuard/R8 디오브퓨스케이션, Android 숨은 API 탐지를 지원합니다.
Android의 veridex 도구에서 영감을 받아 Go로 재구현되었으며, 향상된 기능을 제공합니다: 더 빠른 리플렉션 탐지, 호출 체인 추적(veridex는 한 단계만 표시), 유연한 출력 형식.
--fail-on blocked 플래그로 제한된 API가 발견되면 0이 아닌 종료 코드 반환..dexfinder.yaml, CLI 플래그로 재정의 가능.Homebrew (macOS / Linux):```bash brew install junelegency/tap/dexfinder
**스크립트** (auto-detects OS/arch):```bash
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash
Go 설치:```bash go install github.com/JuneLeGency/dexfinder/cmd/dexfinder@latest
**바이너리**: [Releases](https://github.com/JuneLeGency/dexfinder/releases)에서 다운로드하세요.
## 빠른 시작```bash
# Show APK overview
dexfinder --dex-file app.apk --stats
# Find all calls to getDeviceId (IMEI)
dexfinder --dex-file app.apk --query "getDeviceId"
# Trace call chains as merged tree
dexfinder --dex-file app.apk --query "getDeviceId" --trace
# Trace as flat call stacks (Java crash style)
dexfinder --dex-file app.apk --query "getDeviceId" --trace --layout list
# Exact JNI signature query
dexfinder --dex-file app.apk \
--query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;" \
--trace --depth 8
# Hidden API detection
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv
--query 플래그는 여러 입력 스타일을 허용합니다. dexfinder는 이들 간을 자동 감지 및 변환합니다.
| 형식 | 예시 | 동작 |
|---|---|---|
| 간단한 이름 | getDeviceId | 모든 API에서 퍼지 부분 문자열 일치 |
| Java 클래스 | android.telephony.TelephonyManager | 해당 클래스의 모든 메서드/필드 |
| Java 클래스#메서드 | android.telephony.TelephonyManager#getDeviceId | 해당 메서드의 모든 오버로드 |
| Java 전체 시그니처 | ...TelephonyManager#getDeviceId() | 정확한 일치 + 오버로드 폴백 |
| DEX/JNI 시그니처 | Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String; | 정확한 일치만 |
dexfinder --dex-file app.apk --query "requestLocationUpdates" dexfinder --dex-file app.apk --query "android.location.LocationManager#requestLocationUpdates" dexfinder --dex-file app.apk --query "Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V"
## 출력 제어
세 개의 독립적인 축, 자유롭게 조합 가능:```
--format (text / json / model / html / sarif) what to output
--layout (tree / list) how to arrange traces
--style (java / dex) how to display names
--color (auto / always / never) terminal colors
--format| 값 | 설명 |
|---|---|
text | 색상 태그가 포함된 일반 텍스트 출력 (기본값) |
json | JSON — 트리/리스트 레이아웃으로 스캔 결과 또는 추적 |
model | MethodInfo/FieldInfo 타입이 포함된 구조화된 JSON (IDE/CI용) |
html | 접을 수 있는 트리와 검색 기능이 포함된 독립형 HTML 보고서 |
sarif | SARIF 2.1.0 정적 분석 형식 (GitHub / VS Code) |
--layout (--trace와 함께 사용)| 값 | 설명 |
|---|---|
tree | 병합된 트리 — 공유 호출 경로가 하나의 트리로 축소됨 (기본값) |
list | 플랫 리스트 — 각 고유 호출 체인이 독립적인 스택으로 표시됨 |
--style| 값 | 예제 | 사용 사례 |
|---|---|---|
java | com.example.Foo.method(Foo.java) | 사람이 읽기 쉬운 (기본값) |
dex | Foo.method(Ljava/lang/String;)V | 정확한 서명 분석 |
--scope (검색 범위)쿼리가 어떤 종류의 참조와 일치하는지 제어합니다. 결과를 이해하는 데 중요합니다.
| 값 | 검색 대상 | 답변하는 질문 | 출력 태그 |
|---|---|---|---|
all | 호출 대상 API + 필드 + 코드 문자열 | "이 API를 호출하는 곳은?" (기본값) | [METHOD] [FIELD] [STRING] |
callee | invoke-* / get/put 명령어의 대상 API 서명만 | "이 특정 메서드/필드를 호출하는 곳은?" | [METHOD] [FIELD] |
caller | 호출 메서드의 서명만 | "이 메서드가 내부적으로 호출하는 것은?" | [CALLER→] |
string | const-string 명령어의 문자열 상수 | "이 문자열이 코드에서 사용된 위치는?" | [STRING] |
string-table | 코드 문자열 + 전체 DEX 문자열 테이블 | "이 문자열이 DEX 내 어디에 존재하는가?" (주석, 죽은 코드 포함) | [STRING] [STRING_TABLE] |
everything | 위의 모든 항목 결합 | 전체 그림 | 모든 태그 |
호출 대상과 호출자 이해하기:``` scope=callee: "Who calls finish()?" onCreate ──calls──→ finish() ← these callers are shown onResume ──calls──→ finish()
scope=caller: "What does finish() call internally?" finish() ──calls──→ Log.i() ← these callees are shown finish() ──calls──→ super.finish()
`--scope=all` (기본값) = `callee` + `string`. `caller` 방향은 기본적으로 제외됩니다. 이는 근본적으로 다른 질문에 답하기 때문입니다. 필요할 때는 명시적으로 `--scope=caller` 또는 `--scope=everything`을 사용하세요.
**출력 태그 이해:**
| 태그 | 의미 |
|---|---|
| `[METHOD]` | 쿼리와 일치하는 **호출되는** 메서드 (callee 일치). 들여쓰기된 줄은 호출자(caller)입니다. |
| `[FIELD]` | 쿼리와 일치하는 **접근되는** 필드. 들여쓰기된 줄은 접근자(accessor)입니다. |
| `[CALLER→]` | 쿼리와 일치하는 **호출하는 메서드**. 들여쓰기된 줄은 호출하는 API를 보여줍니다. |
| `[STRING]` | 코드의 문자열 상수가 쿼리와 일치합니다. 들여쓰기된 줄은 사용된 위치입니다. |
| `[STRING_TABLE]` | DEX 문자열 테이블에 존재하지만 코드에 `const-string` 참조가 없는 문자열 (어노테이션에 있거나, R8에 의해 최적화 제거되었을 수 있음) |
## 예제