
クロスプラットフォームのAPK/DEXメソッドファインダー:コールチェーントレーシング、ProGuard難読化解除、および隠しAPI検出機能
ウェブサイト: junelegency.github.io/dexfinder
クロスプラットフォームのAPK/DEXメソッド・フィールド参照ファインダーで、コールチェーントレース、ProGuard/R8の難読化解除、Android隠しAPI検出を備えています。
Androidのveridexツールに触発され、Goで再実装され、拡張機能(より高速なリフレクション検出、コールチェーントレース(veridexは1レベルのみ表示)、柔軟な出力形式)を備えています。
--fail-on blocked 制限付きAPIが見つかると非ゼロで終了.dexfinder.yaml、CLIフラグで上書きHomebrew (macOS / Linux):```bash brew install junelegency/tap/dexfinder
**スクリプト** (OS/アーキテクチャを自動検出):```bash
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash
Go install:```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はそれらを自動検出して変換します。
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"
## 出力制御
3つの独立した軸、自由に組み合わせ可能:```
--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--layout (used with --trace)| 値 | 説明 |
|---|---|
tree | マージツリー — 共有呼び出しパスを1つのツリーにまとめたもの (デフォルト) |
list | フラットリスト — 各ユニークな呼び出しチェーンを独立したスタックとして表示 |
--style| 値 | 例 | 使用例 |
|---|---|---|
java | com.example.Foo.method(Foo.java) | 人間可読 (デフォルト) |
dex | Foo.method(Ljava/lang/String;)V | 正確なシグネチャ解析 |
--scope (search scope)検索対象の参照の種類を制御します。結果を理解する上で重要です。
callee と caller の理解:``` 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マッチ)。インデント行は呼び出し元。 |
| `[FIELD]` | クエリに一致する**アクセスされている**フィールド。インデント行はアクセス元。 |
| `[CALLER→]` | クエリに一致する**呼び出し元メソッド**。インデント行は呼び出しているAPIを示します。 |
| `[STRING]` | コード内の文字列定数がクエリに一致。インデント行はその使用箇所。 |
| `[STRING_TABLE]` | 文字列はDEX文字列テーブルに存在するが、コード内に`const-string`参照がない(アノテーション内、R8による最適化などが原因)。 |
## 使用例
### 1. APK統計のスキャン```bash
dexfinder --dex-file app.apk --stats
Loaded 31 DEX file(s): 183913 classes, 1250566 method refs
Method references: 680610
Field references: 625572
String constants: 654353
Referenced types: 192586
Time: 3.9s
dexfinder --dex-file app.apk --query "requestLocationUpdates"
[METHOD] Landroid/location/LocationManager;->requestLocationUpdates(Ljava/lang/String;JFLandroid/location/LocationListener;)V (3 ref) Lcom/example/TestEntry;->init(Landroid/content/Context;)V (2 occurrences) Lcom/example/service/LocationService;->onStartCommand(Landroid/content/Intent;II)I
### 3. 呼び出しチェーンの追跡 — ツリービュー```bash
dexfinder --dex-file app.apk \
--query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;" \
--trace --depth 5
android.telephony.TelephonyManager.getDeviceId()
└── com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java)
├── com.example.session.PhoneInfo.getImei(PhoneInfo.java)
├── com.example.logging.ClientIdHelper.initClientId(ClientIdHelper.java)
│ └── com.example.logging.ContextInfo.<init>(ContextInfo.java)
│ ├── com.example.logging.LogStrategyManager.getInstance(LogStrategyManager.java)
│ └── com.example.logging.LogContextImpl.<init>(LogContextImpl.java)
├── com.example.msp.DeviceInfo.k(DeviceInfo.java)
│ └── com.example.msp.DeviceInfo.<init>(DeviceInfo.java)
│ └── com.example.msp.DeviceInfo.getInstance(DeviceInfo.java)
│ ├── com.example.msp.TidHelper.getIMEI(TidHelper.java)
│ ├── com.example.msp.TidHelper.getIMSI(TidHelper.java)
│ └── com.example.msp.DeviceCollector.collectData(DeviceCollector.java)
└── com.example.weex.WXEnvironment.getDevId(WXEnvironment.java)
└── com.example.weex.WXEnvironment.<clinit>(WXEnvironment.java)
dexfinder --dex-file app.apk
--query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;"
--trace --depth 5 --layout list
--- Call chain #1 for android.telephony.TelephonyManager.getDeviceId() --- at com.example.session.PhoneInfo.getImei(PhoneInfo.java) at com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java) at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)
--- Call chain #2 for android.telephony.TelephonyManager.getDeviceId() --- at com.example.logging.LogStrategyManager.getInstance(LogStrategyManager.java) at com.example.logging.ContextInfo.(ContextInfo.java) at com.example.logging.ClientIdHelper.initClientId(ClientIdHelper.java) at com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java) at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)
### 5. DEX署名スタイルでトレース```bash
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 3 --style dex
Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;
└── TelephonyManager.getDeviceId(Landroid/telephony/TelephonyManager;)Ljava/lang/String;
├── PhoneInfo.getImei(Landroid/content/Context;)Ljava/lang/String;
├── ClientIdHelper.initClientId(Landroid/content/Context;)Ljava/lang/String;
└── DeviceInfo.k(Landroid/content/Context;)V
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 2 --format json
```json
{
"targets": [{
"api": "android.telephony.TelephonyManager.getDeviceId()",
"tree": {
"method": "android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)",
"callers": [
{ "method": "com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java)",
"callers": [
{ "method": "com.example.session.PhoneInfo.getImei(PhoneInfo.java)" },
{ "method": "com.example.logging.ClientIdHelper.initClientId(ClientIdHelper.java)" }
]}
]
}
}]
}
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 2 --format json --layout list
```json
{
"targets": [{
"api": "android.telephony.TelephonyManager.getDeviceId()",
"chains": [
["com.example.session.PhoneInfo.getImei(PhoneInfo.java)",
"com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java)",
"android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)"],
["com.example.logging.ClientIdHelper.initClientId(ClientIdHelper.java)",
"com.example.aopsdk.TelephonyManager.getDeviceId(TelephonyManager.java)",
"android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)"]
]
}]
}
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format model | jq '.call_chains[0]'
```json
{
"target": "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;",
"chain": [
{ "method": { "dex_signature": "...", "class": "...", "name": "getImei",
"param_types": ["Landroid/content/Context;"], "return_type": "Ljava/lang/String;",
"java_readable": "com.example.session.PhoneInfo.getImei(...)" }},
{ "method": { "dex_signature": "...", "java_readable": "...TelephonyManager.getDeviceId(...)" }},
{ "method": { "dex_signature": "...", "java_readable": "...TelephonyManager.getDeviceId(...)" }}
],
"depth": 2
}
--mapping を使用すると、入力 と 出力 の両方で元の(難読化前の)名前をサポートします。
元の名前でクエリ → DEX検索用に難読化された名前に自動変換:```bash
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt
dexfinder --dex-file app.apk --query "com.example.app.utils.Helper" --mapping mapping.txt
dexfinder --dex-file app.apk --query "LJ7;" --mapping mapping.txt
**トレース内の難読化解除された名前を出力:**```bash
# Tree trace with deobfuscated names
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --depth 3
com.example.kotlin.KotlinCases$$ExternalSyntheticLambda1.<init>(int)
└── com.example.TestEntry.runAllTests(TestEntry.java)
└── com.example.MainActivity.onCreate(MainActivity.java)
難読化された名前と元の名前の両方を表示:```bash dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace
com.example.kotlin.KotlinCases.fetchLocationAsync(KotlinCases.java) └── com.example.kotlin.KotlinCases$testCoroutines$3.invokeSuspend(KotlinCases.java) [obf: G7.e] └── com.example.kotlin.KotlinCases$testCoroutines$3.create(KotlinCases.java) [obf: G7.b]
**他のフラグとのすべての組み合わせ:**```bash
# Original name + trace as flat list
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --layout list
# Original name + DEX signature style
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --style dex
# Original name + JSON tree + show-obf
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace --format json
# Original name + reverse direction (what does this class call?)
dexfinder --dex-file app.apk --query "com.example.kotlin.KotlinCases" --mapping mapping.txt --scope caller
入力 × 出力マトリクス:
curl -o hiddenapi-flags.csv
https://dl.google.com/developers/android/baklava/non-sdk/hiddenapi-flags.csv
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv
#1: Linking unsupported Lsun/misc/Unsafe;->allocateInstance(Ljava/lang/Class;)Ljava/lang/Object; use(s): Lcom/google/gson/internal/UnsafeAllocator;->create()Lcom/google/gson/internal/UnsafeAllocator;
#2: Reflection blocked Landroid/location/ILocationManager;->getCurrentLocation potential use(s): Lcom/example/monitor/LocationMonitor;->hookSystemLocationManager(Landroid/content/Context;)V
### 11. 検索文字列定数(content:// URI、APIキーなど)```bash
# Find content:// URIs in code
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope string
# Include strings only in DEX table (optimized out by R8, annotations, etc.)
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope everything
[STRING] "content://com.android.contacts/" (1 ref)
Lcom/example/imageloader/BaseImageDownloader;->getStreamFromContent(Ljava/lang/String;)Ljava/io/InputStream;
[STRING_TABLE] "content://com.android.contacts" (in DEX string table, no code reference found)
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/"
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/,Lcom/mylib/"
### 13. すべてを組み合わせる```bash
# Deobfuscated JSON tree of location API usage, filtered to your code
dexfinder --dex-file app.apk \
--query "android.location.LocationManager#requestLocationUpdates" \
--trace --depth 8 \
--format json --layout tree --style java \
--mapping mapping.txt --show-obf \
--class-filter "Lcom/mycompany/"
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format html --output report.html
任意のブラウザで開けます — 折りたたみ可能なコールツリー、検索バー、ダークテーマ。
### 15. SARIF for GitHub Code Scanning```bash
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --format sarif > results.sarif
# Upload to GitHub:
# gh api repos/OWNER/REPO/code-scanning/sarifs -f "[email protected]"
dexfinder --dex-file new.apk --diff old.apk --query "getDeviceId"
Summary: +1 added, -1 removed, ~0 changed
### 17. --fail-on による CI ゲート```bash
# Fail CI if any blocked hidden APIs are used
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --fail-on blocked
# Exit code: 0 = clean, 2 = violations found
Apple Mシリーズ、シングルスレッドでベンチマーク:
同じ ~300MB APK での veridex (C++, 非正確モード) との比較:
プロジェクトルートに .dexfinder.yaml を作成してデフォルトを設定:```yaml
mapping: ./build/outputs/mapping.txt
class-filter: "Lcom/mycompany/"
api-flags: ./hiddenapi-flags.csv
style: java
depth: 8
color: auto
CLIフラグは常に設定ファイルの値を上書きします。
## ソースからビルド```bash
git clone https://github.com/JuneLeGency/dexfinder.git
cd dexfinder
go build -o dexfinder ./cmd/dexfinder/
go test ./...
Apache License 2.0
クロスプラットフォーム APK/DEX メソッド・フィールド参照検索ツール。コールチェーントレース、ProGuard/R8 難読化解除、Android Hidden API 検出をサポート。
Android veridex の原理に基づき、Go で再実装・強化:より高速なリフレクション検出、多層コールチェーントレース(veridex は1層のみ)、柔軟な出力形式。
--fail-on blocked で制限API検出時にゼロ以外の終了コードを返す.dexfinder.yaml プロジェクトデフォルト設定、コマンドライン引数で上書きHomebrew (macOS / Linux):```bash brew install junelegency/tap/dexfinder
**脚本安装** (自动检测系统):```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
# 查看 APK 概况
dexfinder --dex-file app.apk --stats
# 查找所有 getDeviceId 调用(获取 IMEI)
dexfinder --dex-file app.apk --query "getDeviceId"
# 追踪调用链(合并树形视图)
dexfinder --dex-file app.apk --query "getDeviceId" --trace
# 追踪调用链(展开为独立调用栈)
dexfinder --dex-file app.apk --query "getDeviceId" --trace --layout list
# 用精确 JNI 签名查询
dexfinder --dex-file app.apk \
--query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;" \
--trace --depth 8
--query)3つの独立した次元で、自由に組み合わせ可能:``` --format (text / json / model / html / sarif) 输出什么 --layout (tree / list) 怎么排列调用链 --style (java / dex) 怎么显示名称 --color (auto / always / never) 终端着色
### `--layout` 比較(`--trace` 併用)
**tree** — 共通パスを統合し、1つのツリーで全体像を表示:```
android.telephony.TelephonyManager.getDeviceId()
└── ...aopsdk...TelephonyManager.getDeviceId(TelephonyManager.java)
├── PhoneInfo.getImei(PhoneInfo.java)
├── ClientIdHelper.initClientId(ClientIdHelper.java)
│ └── ContextInfo.<init>(ContextInfo.java)
└── DeviceInfo.k(DeviceInfo.java)
└── DeviceInfo.getInstance(DeviceInfo.java)
├── TidHelper.getIMEI(TidHelper.java)
└── DeviceCollector.collectData(DeviceCollector.java)
list — 各チェーンを独立して表示(Java crash スタイル):``` --- Call chain #1 --- at PhoneInfo.getImei(PhoneInfo.java) at ...aopsdk...TelephonyManager.getDeviceId(TelephonyManager.java) at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)
--- Call chain #2 --- at ContextInfo.(ContextInfo.java) at ClientIdHelper.initClientId(ClientIdHelper.java) at ...aopsdk...TelephonyManager.getDeviceId(TelephonyManager.java) at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java)
### `--style` 比較
**java** (デフォルト): `com.example.Foo.method(Foo.java)`
**dex**: `Foo.method(Ljava/lang/String;)V`
### JSON 出力```bash
# JSON 树
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format json
# JSON 列表
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format json --layout list
--scope 検索範囲クエリがどの参照タイプに一致するかを制御します。このパラメータを理解することは、結果を正しく解釈するために重要です。
callee vs caller の違い:``` scope=callee: "谁调了 finish()?" onCreate ──调用──→ finish() ← 显示这些调用者 onResume ──调用──→ finish()
scope=caller: "finish() 内部调了什么?" finish() ──调用──→ Log.i() ← 显示这些被调用者 finish() ──调用──→ super.finish()
`--scope=all`(デフォルト)= `callee` + `string` です。`caller` 方向は、全く異なる質問に答えるため、デフォルトから意図的に除外されています。必要な場合は `--scope=caller` または `--scope=everything` を使用して明示的に有効にします。
**出力ラベルの意味:**
| ラベル | 意味 |
|---|---|
| `[METHOD]` | 検索したメソッドが**他のコードから呼び出されています**。インデント行は呼び出し元です。 |
| `[FIELD]` | 検索したフィールドが**他のコードからアクセスされています**。インデント行はアクセス元です。 |
| `[CALLER→]` | 検索したメソッド名が何らかの**呼び出し元**に現れています。インデント行はその呼び出し元がどのAPIを呼び出しているかを示します。 |
| `[STRING]` | コード内の文字列定数がマッチしました。インデント行はその文字列を使用しているメソッドです。 |
| `[STRING_TABLE]` | 文字列がDEX文字列テーブルにのみ存在し、コード内に `const-string` 参照がありません(アノテーション内にある、R8によって最適化された等の可能性があります)。 |
## その他の使い方
### 難読化解除(--mapping)
`--mapping` を読み込むと、**入力と出力**の両方で元の(難読化されていない)名前がサポートされます。
**元の名前でクエリ → 自動的に難読化された名前に変換してDEXを検索:**```bash
# 用原始简短类名查(mapping 内部将 "KotlinCases" 转为 "LJ7;")
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt
# 用原始 Java 全名查
dexfinder --dex-file app.apk --query "com.example.app.utils.Helper" --mapping mapping.txt
# 用混淆名查也正常工作
dexfinder --dex-file app.apk --query "LJ7;" --mapping mapping.txt
出力難読化解除名:```bash
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace
**難読化名と元の名前を同時に表示:**```bash
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace
com.example.KotlinCases.fetchLocationAsync(KotlinCases.java)
└── com.example.KotlinCases$testCoroutines$3.invokeSuspend(KotlinCases.java) [obf: G7.e]
他のパラメータと自由に組み合わせ可能:```bash
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --layout list
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --style dex
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace --format json
dexfinder --dex-file app.apk --query "com.example.KotlinCases" --mapping mapping.txt --scope caller
**入力×出力行列:**
| クエリ入力 | マッピングなし | `--mapping` | `--mapping --show-obf` |
|---|---|---|---|
| 難読化名 `LJ7;` | ✓ 難読化出力 | ✓ 難読化解除出力 | ✓ 両者併記 |
| 元の短い名前 `KotlinCases` | ✗ 見つからない | ✓ 自動変換 + 難読化解除出力 | ✓ 自動変換 + 両者併記 |
| 元の完全修飾名 `com.example...` | ✗ 見つからない | ✓ 自動変換 + 難読化解除出力 | ✓ 自動変換 + 両者併記 |
### Hidden API 検出```bash
# 下载 CSV(一次性)
curl -o hiddenapi-flags.csv \
https://dl.google.com/developers/android/baklava/non-sdk/hiddenapi-flags.csv
# 全量检测(直接链接 + 反射检测)
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope string
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope everything
### パッケージ名でフィルタリング```bash
# 只扫描自己的代码
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/"
dexfinder --dex-file app.apk
--query "android.location.LocationManager#requestLocationUpdates"
--trace --depth 8
--format json --layout tree --style java
--mapping mapping.txt --show-obf
--class-filter "Lcom/mycompany/"
### HTML レポート```bash
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format html --output report.html
ブラウザで開いてすぐに使用可能 — 折りたたみ可能なコールツリー、検索バー、ダークテーマ。
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --format sarif > results.sarif
### APK バージョン比較```bash
dexfinder --dex-file new.apk --diff old.apk --query "getDeviceId"
+ 1 added method(s)
+ Lcom/new/Feature;->trackDevice()V
- 1 removed method(s)
- Lcom/old/Legacy;->getIMEI()V
Summary: +1 added, -1 removed, ~0 changed
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --fail-on blocked
## パフォーマンス
Apple M シリーズチップ、シングルスレッド:
| APK サイズ | DEX 数 | クラス数 | メソッド参照 | スキャン | 隠しAPI |
|---|---|---|---|---|---|
| ~1 MB | 1 | ~2K | ~18K | **24ms** | — |
| ~10 MB | 2 | ~25K | ~100K | **335ms** | — |
| ~300 MB | 30+ | ~180K | ~1.2M | **3.9s** | **5.4s** |
veridex (C++) と同一の ~300MB APK での比較:
- veridex precise: **27s**(Binder/AIDL リフレクションを追跡不可)
- veridex imprecise: **>32 分**(デカルト積爆発により強制終了)
- **dexfinder: 5.4s**(逆インデックス最適化)
## 全パラメーター
| パラメーター | 説明 | デフォルト値 |
|---|---|---|
| `--dex-file` | APK/DEX/JAR ファイルパス **(必須)** | — |
| `--query` | 検索キーワード(Java / DEX/JNI / 簡易名) | — |
| `--trace` | 呼び出しチェーントレースを有効化(`--query`と併用) | `false` |
| `--depth` | 呼び出しチェーンの最大深度 | `5` |
| `--layout` | トレースレイアウト: `tree`(統合ツリー)または `list`(展開リスト) | `tree` |
| `--style` | 命名スタイル: `java`(可読)または `dex`(JNI 署名) | `java` |
| `--format` | 出力フォーマット: `text`、`json`、`model`、`html`、`sarif` | `text` |
| `--output` | ファイルに出力(stdout の代わり) | — |
| `--color` | 色モード: `auto`、`always`、`never` | `auto` |
| `--mapping` | ProGuard/R8 mapping.txt のパス | — |
| `--show-obf` | 難読化名と難読化解除名を同時表示 | `false` |
| `--api-flags` | hiddenapi-flags.csv のパス | — |
| `--class-filter` | クラス記述子プレフィックスフィルター(カンマ区切り) | — |
| `--exclude-api-lists` | 除外する API レベル | — |
| `--scope` | 検索範囲: `all`、`callee`、`caller`、`string`、`string-table`、`everything` | `all` |
| `--diff` | 別の APK/DEX と比較し、API 差分を表示 | — |
| `--fail-on` | 指定されたレベルの API を検出した場合にゼロ以外の終了コードを返す(CI 用) | — |
| `--stats` | 統計サマリーのみ表示 | `false` |
| `--version` | バージョンを表示 | `false` |
### 設定ファイル
プロジェクトルートに `.dexfinder.yaml` を作成してデフォルト値を設定してください:```yaml
mapping: ./build/outputs/mapping.txt
class-filter: "Lcom/mycompany/"
api-flags: ./hiddenapi-flags.csv
style: java
depth: 8
color: auto
コマンドライン引数は常に設定ファイルを上書きします。
git clone https://github.com/JuneLeGency/dexfinder.git cd dexfinder go build -o dexfinder ./cmd/dexfinder/ go test ./...
## 许可证
Apache License 2.0
| 形式 | 例 | 動作 |
|---|
| 単純な名前 | getDeviceId | すべてのAPIにおけるあいまい部分文字列一致 |
| Javaクラス | android.telephony.TelephonyManager | そのクラスのすべてのメソッド/フィールド |
| Javaクラス#メソッド | android.telephony.TelephonyManager#getDeviceId | そのメソッドのすべてのオーバーロード |
| Java完全シグネチャ | ...TelephonyManager#getDeviceId() | 完全一致 + オーバーロードフォールバック |
| DEX/JNIシグネチャ | Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String; | 完全一致のみ |
| 値 | 説明 |
|---|
text | 色付きタグ付きのプレーンテキスト出力 (デフォルト) |
json | JSON — スキャン結果またはトレースをツリー/リストレイアウトで出力 |
model | 完全なMethodInfo/FieldInfo型を含む構造化JSON (IDE/CI向け) |
html | 折りたたみ可能なツリーと検索機能を備えた自己完結型HTMLレポート |
sarif | SARIF 2.1.0 静的解析形式 (GitHub / VS Code) |
| 値 | 検索対象 | 答えられる質問 | 出力タグ |
|---|
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 | 上記すべての組み合わせ | 完全な全体像 | すべてのタグ |
| クエリ入力 | マッピングなし | --mapping | --mapping --show-obf |
|---|
難読化: LJ7; | ✓ 難読化された出力 | ✓ 難読化解除された出力 | ✓ 両方の名前 |
オリジナルの単純名: KotlinCases | ✗ 見つかりません | ✓ 自動変換、難読化解除出力 | ✓ 自動変換、両方の名前 |
オリジナルの完全名: com.example...KotlinCases | ✗ 見つかりません | ✓ 自動変換、難読化解除出力 | ✓ 自動変換、両方の名前 |
| APK Size | DEX Files | Classes | Method Refs | Scan | Hidden API |
|---|
| ~1 MB | 1 | ~2K | ~18K | 24ms | — |
| ~10 MB | 2 | ~25K | ~100K | 335ms | — |
| ~300 MB | 30+ | ~180K | ~1.2M | 3.9s | 5.4s |
| フラグ | 説明 | デフォルト |
|---|
--dex-file | 解析する APK/DEX/JAR ファイル (必須) | — |
--query | 検索キーワード (Java、DEX/JNI、またはシンプル名) | — |
--trace | コールチェーン追跡を有効化 (--query 必須) | false |
--depth | 最大コールチェーン深さ | 5 |
--layout | トレースレイアウト: tree または list | tree |
--style | 名前スタイル: java または dex | java |
--format | 出力形式: text, json, model, html, sarif | text |
--output | 出力をファイルに書き込む (stdout の代わり) | — |
--color | カラーモード: auto, always, never | auto |
--mapping | ProGuard/R8 mapping.txt のパス | — |
--show-obf | 難読化解除名とともに難読化名を表示 | false |
--api-flags | hiddenapi-flags.csv のパス | — |
--class-filter | カンマ区切りのクラス記述子プレフィックス | — |
--exclude-api-lists | レポートから除外する API リスト | — |
--scope | 検索範囲: all, callee, caller, string, string-table, everything | all |
--diff | 別の APK/DEX と比較し API 差分を表示 | — |
--fail-on | 指定レベルの隠れAPIが見つかった場合に非ゼロ終了 (CIゲート) | — |
--stats | サマリー統計のみ表示 | false |
--version | バージョンを表示 | false |
| 形式 | 例 | 動作 |
|---|
| 単純な名前 | getDeviceId | 曖昧な部分文字列マッチ |
| Javaクラス名 | android.telephony.TelephonyManager | そのクラスのすべてのメソッドにマッチ |
| Javaクラス名#メソッド | ...TelephonyManager#getDeviceId | そのメソッドのすべてのオーバーロードにマッチ |
| Java完全シグネチャ | ...#getDeviceId() | 完全マッチ+オーバーロードフォールバック |
| DEX/JNI シグネチャ | Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String; | 完全マッチ |
| 値 | 検索内容 | 回答される質問 | 出力ラベル |
|---|
all | 呼び出されたAPI + フィールド + コード文字列 | "このメソッドを誰が呼び出しているか?"(デフォルト) | [METHOD] [FIELD] [STRING] |
callee | invoke-* / get/put 命令のターゲットシグネチャのみ | "この特定のメソッド/フィールドを誰が呼び出しているか?" | [METHOD] [FIELD] |
caller | 呼び出し元メソッドのシグネチャのみ | "このメソッドは内部で何を呼び出しているか?" | [CALLER→] |
string | const-string 命令の文字列定数 | "この文字列はコードのどこで使用されているか?" | [STRING] |
string-table | コード文字列 + DEXの完全な文字列テーブル | "この文字列はDEXに存在するか?"(アノテーション、デッドコードを含む) | [STRING] [STRING_TABLE] |
everything | 上記すべて | 完全なビュー | すべてのラベル |