
Cross-platform APK/DEX method finder with call chain tracing, ProGuard deobfuscation, and hidden API detection
Website: junelegency.github.io/dexfinder
Cross-platform APK/DEX method & field reference finder with call chain tracing, ProGuard/R8 deobfuscation, and Android hidden API detection.
Inspired by Android's veridex tool, reimplemented in Go with enhanced capabilities: faster reflection detection, call chain tracing (veridex only shows one level), and flexible output formats.
--fail-on blocked exits non-zero when restricted APIs are found.dexfinder.yaml for project defaults, CLI flags overrideHomebrew (macOS / Linux):
brew install junelegency/tap/dexfinder
Script (auto-detects OS/arch):
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash
Go install:
go install github.com/JuneLeGency/dexfinder/cmd/dexfinder@latest
Binary: download from Releases.
# 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
The --query flag accepts multiple input styles. dexfinder auto-detects and converts between them.
# All equivalent — find requestLocationUpdates in LocationManager:
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"
Three independent axes, freely combinable:
--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)| Value | Description |
|---|---|
tree | Merged tree — shared call paths collapsed into one tree (default) |
list | Flat list — each unique call chain shown as independent stack |
--style| Value | Example | Use case |
|---|---|---|
java | com.example.Foo.method(Foo.java) | Human-readable (default) |
dex | Foo.method(Ljava/lang/String;)V | Precise signature analysis |
--scope (search scope)Controls what kind of references the query matches against. This is critical for understanding results.
Understanding callee vs 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 (default) = callee + string. The caller direction is intentionally excluded from default because it answers a fundamentally different question. Use --scope=caller or --scope=everything explicitly when you need it.
Understanding output tags:
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
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.<init>(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)
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
{
"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
{
"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]'
{
"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
}
With --mapping, both input and output support original (unobfuscated) names.
Query by original name → auto-converts to obfuscated name for DEX search:
# Query with original simple class name (mapping converts "KotlinCases" → "LJ7;" internally)
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt
# Query with original Java full name
dexfinder --dex-file app.apk --query "com.example.app.utils.Helper" --mapping mapping.txt
# Query with obfuscated name still works
dexfinder --dex-file app.apk --query "LJ7;" --mapping mapping.txt
Output deobfuscated names in trace:
# 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)
Show both obfuscated and original names:
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]
All combinations with other flags:
# 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
Input × Output matrix:
# Download CSV (one-time)
curl -o hiddenapi-flags.csv \
https://dl.google.com/developers/android/baklava/non-sdk/hiddenapi-flags.csv
# Full scan — linking + reflection detection
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
# 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)
# Only scan classes in your own package
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/"
# Scan multiple packages
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/,Lcom/mylib/"
# 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
Opens in any browser — collapsible call trees, search bar, dark theme.
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]"
# Compare two APK versions
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
# 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
Benchmarked on Apple M-series, single thread:
Compared to veridex (C++, imprecise mode) on the same ~300MB APK:
Create .dexfinder.yaml in your project root to set defaults:
mapping: ./build/outputs/mapping.txt
class-filter: "Lcom/mycompany/"
api-flags: ./hiddenapi-flags.csv
style: java
depth: 8
color: auto
CLI flags always override config file values.
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 仅一层)、灵活的输出格式。
--fail-on blocked 检测到受限 API 时返回非零退出码.dexfinder.yaml 项目默认配置,命令行参数覆盖Homebrew (macOS / Linux):
brew install junelegency/tap/dexfinder
脚本安装 (自动检测系统):
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash
Go 安装:
go install github.com/JuneLeGency/dexfinder/cmd/dexfinder@latest
二进制下载: Releases
# 查看 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)三个独立维度,自由组合:
--format (text / json / model / html / sarif) 输出什么
--layout (tree / list) 怎么排列调用链
--style (java / dex) 怎么显示名称
--color (auto / always / never) 终端着色
--layout 对比(配合 --trace)tree — 合并共同路径,一棵树展示全貌:
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.<init>(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 树
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 显式启用。
输出标签含义:
加载 --mapping 后,输入和输出都支持原始(未混淆)名称。
用原始名查询 → 自动转换为混淆名搜索 DEX:
# 用原始简短类名查(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
输出反混淆名称:
# trace 树形 + 反混淆
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace
同时显示混淆名和原始名:
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]
与其他参数自由组合:
# 原始名 + 展开列表
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --layout list
# 原始名 + DEX 签名风格
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --style dex
# 原始名 + JSON 树 + 显示混淆名
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
输入×输出矩阵:
# 下载 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
# 搜索代码中的 content:// URI
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope string
# 包含被 R8 优化掉的字符串(注解、死代码等)
dexfinder --dex-file app.apk --query "content://com.android.contacts" --scope everything
# 只扫描自己的代码
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/"
# 反混淆 + JSON 树形输出 + 定位 API 调用 + 过滤自己的代码
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
浏览器打开即用——可折叠调用树、搜索栏、暗色主题。
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --format sarif > results.sarif
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
# 检测到 blocked API 时 CI 失败
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --fail-on blocked
# 退出码: 0 = 通过, 2 = 有违规
Apple M 系列芯片,单线程:
与 veridex (C++) 在同一 ~300MB APK 上对比:
在项目根目录创建 .dexfinder.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
| Format | Example | Behavior |
|---|
| Simple name | getDeviceId | Fuzzy substring match across all APIs |
| Java class | android.telephony.TelephonyManager | All methods/fields of that class |
| Java class#method | android.telephony.TelephonyManager#getDeviceId | All overloads of that method |
| Java full signature | ...TelephonyManager#getDeviceId() | Exact + overload fallback |
| DEX/JNI signature | Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String; | Exact match only |
| Value | Description |
|---|
text | Plain text output with colored tags (default) |
json | JSON — scan results or trace with tree/list layout |
model | Structured JSON with full MethodInfo/FieldInfo types (for IDE/CI) |
html | Self-contained HTML report with collapsible trees and search |
sarif | SARIF 2.1.0 static analysis format (GitHub / VS Code) |
| Value | What it searches | Question it answers | Output tag |
|---|
all | Callee APIs + fields + code strings | "Who calls this API?" (default) | [METHOD] [FIELD] [STRING] |
callee | Only target API signatures in invoke-* / get/put instructions | "Who calls this specific method/field?" | [METHOD] [FIELD] |
caller | Only the calling method's signature | "What does this method call internally?" | [CALLER→] |
string | String constants in const-string instructions | "Where is this string used in code?" | [STRING] |
string-table | Code strings + full DEX string table | "Does this string exist anywhere in DEX?" (includes annotations, dead code) | [STRING] [STRING_TABLE] |
everything | All of the above combined | Full picture | all tags |
| Tag | Meaning |
|---|
[METHOD] | A method being called matches your query (callee match). Indented lines are the callers. |
[FIELD] | A field being accessed matches your query. Indented lines are the accessors. |
[CALLER→] | A calling method matches your query. The indented line shows what API it's calling. |
[STRING] | A string constant in code matches your query. Indented lines are where it's used. |
[STRING_TABLE] | String exists in DEX string table but has no const-string reference in code (may be in annotations, optimized out by R8, etc.) |
| Query input | No mapping | --mapping | --mapping --show-obf |
|---|
Obfuscated: LJ7; | ✓ obfuscated output | ✓ deobfuscated output | ✓ both names |
Original simple: KotlinCases | ✗ not found | ✓ auto-converts, deobf output | ✓ auto-converts, both names |
Original full: com.example...KotlinCases | ✗ not found | ✓ auto-converts, deobf output | ✓ auto-converts, both names |
| 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 |
| Flag | Description | Default |
|---|
--dex-file | APK/DEX/JAR file to analyze (required) | — |
--query | Search keyword (Java, DEX/JNI, or simple name) | — |
--trace | Enable call chain tracing (requires --query) | false |
--depth | Max call chain depth | 5 |
--layout | Trace layout: tree or list | tree |
--style | Name style: java or dex | java |
--format | Output format: text, json, model, html, sarif | text |
--output | Write output to file instead of stdout | — |
--color | Color mode: auto, always, never | auto |
--mapping | ProGuard/R8 mapping.txt path | — |
--show-obf | Show obfuscated names alongside deobfuscated | false |
--api-flags | Path to hiddenapi-flags.csv | — |
--class-filter | Comma-separated class descriptor prefixes | — |
--exclude-api-lists | API lists to exclude from reporting | — |
--scope | Search scope: all, callee, caller, string, string-table, everything | all |
--diff | Compare with another APK/DEX and show API differences | — |
--fail-on | Exit non-zero if hidden APIs at this level found (CI gate) | — |
--stats | Show summary statistics only | false |
--version | Show 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 | 以上全部 | 完整视图 | 全部标签 |
| 标签 | 含义 |
|---|
[METHOD] | 你搜的方法被别人调用了。缩进行是调用者。 |
[FIELD] | 你搜的字段被别人访问了。缩进行是访问者。 |
[CALLER→] | 你搜的方法名出现在某个调用方中,缩进行显示它调了什么 API。 |
[STRING] | 代码中的字符串常量匹配。缩进行是使用该字符串的方法。 |
[STRING_TABLE] | 字符串仅存在于 DEX 字符串表中,代码里没有 const-string 引用(可能在注解中、被 R8 优化掉等)。 |
| 查询输入 | 无 mapping | --mapping | --mapping --show-obf |
|---|
混淆名 LJ7; | ✓ 混淆输出 | ✓ 反混淆输出 | ✓ 两者并列 |
原始简名 KotlinCases | ✗ 找不到 | ✓ 自动转换 + 反混淆输出 | ✓ 自动转换 + 两者并列 |
原始全名 com.example... | ✗ 找不到 | ✓ 自动转换 + 反混淆输出 | ✓ 自动转换 + 两者并列 |
| APK 大小 | DEX 数 | 类数 | 方法引用 | 扫描 | 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(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 |