Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
dexfinder — Cross-platform APK/DEX method finder with call chain tracing, ProGuard deobfuscation, and hidden API detection | Kitploit
Tools/GitHubGitHub/junelegency/dexfinder
Android SecurityStatic AnalysisVulnerability AnalysisCode AnalysisReverse EngineeringInformation GatheringDevSecOpsMobile SecurityBinary Analysis
GitHubjunelegency/dexfinder

dexfinder

Cross-platform APK/DEX method finder with call chain tracing, ProGuard deobfuscation, and hidden API detection

92104 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository

dexfinder

English | 中文 | Website dexfinder demo


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.

Features

  • APK/DEX/JAR scanning — Parse DEX bytecode, extract all method/field/string references
  • Multi-format query — Search by Java name, DEX/JNI signature, or simple keyword
  • Call chain tracing — Trace callers up to N levels deep, merged tree or flat list, with cycle detection
  • ProGuard/R8 deobfuscation — Load mapping.txt, display original names alongside obfuscated
  • Hidden API detection — Load hiddenapi-flags.csv, detect blocked/unsupported APIs
  • Reflection detection — Cross-match classes × strings to find reflection-based hidden API usage
  • Flexible output — text / json / model / html / sarif, tree / list layout, java / dex name style — all orthogonal
  • Color terminal output — Auto-detected ANSI colors for tags, tree connectors, and API levels
  • APK diff — Compare two APK/DEX versions, detect added/removed/changed API references
  • HTML reports — Self-contained interactive HTML with collapsible trees, search, and dark theme
  • SARIF output — SARIF 2.1.0 for GitHub Code Scanning, VS Code, and CI pipelines
  • CI integration — --fail-on blocked exits non-zero when restricted APIs are found
  • Config file — .dexfinder.yaml for project defaults, CLI flags override
  • Zero external dependencies — Pure Go, self-contained DEX parser
  • Cross-platform — macOS (Intel / Apple Silicon), Linux (amd64 / arm64), Windows

Install

Homebrew (macOS / Linux):

root@kitploit:~
brew install junelegency/tap/dexfinder

Script (auto-detects OS/arch):

root@kitploit:~
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash

Go install:

root@kitploit:~
go install github.com/JuneLeGency/dexfinder/cmd/dexfinder@latest

Binary: download from Releases.

Quick Start

root@kitploit:~
# 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 Formats

The --query flag accepts multiple input styles. dexfinder auto-detects and converts between them.

root@kitploit:~
# 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"

Output Control

Three independent axes, freely combinable:

root@kitploit:~
--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)

ValueDescription
treeMerged tree — shared call paths collapsed into one tree (default)
listFlat list — each unique call chain shown as independent stack

--style

ValueExampleUse case
javacom.example.Foo.method(Foo.java)Human-readable (default)
dexFoo.method(Ljava/lang/String;)VPrecise signature analysis

--scope (search scope)

Controls what kind of references the query matches against. This is critical for understanding results.

Understanding callee vs caller:

root@kitploit:~
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:

Examples

1. Scan APK statistics

root@kitploit:~
dexfinder --dex-file app.apk --stats
root@kitploit:~
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

2. Find all location tracking calls

root@kitploit:~
dexfinder --dex-file app.apk --query "requestLocationUpdates"
root@kitploit:~
[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. Trace call chains — tree view

root@kitploit:~
dexfinder --dex-file app.apk \
  --query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;" \
  --trace --depth 5
root@kitploit:~
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)

4. Trace call chains — list view (Java crash style)

root@kitploit:~
dexfinder --dex-file app.apk \
  --query "Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;" \
  --trace --depth 5 --layout list
root@kitploit:~
--- 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)

5. Trace with DEX signature style

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 3 --style dex
root@kitploit:~
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

6. JSON output — tree

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 2 --format json
root@kitploit:~
{
  "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)" }
          ]}
      ]
    }
  }]
}

7. JSON output — list

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --depth 2 --format json --layout list
root@kitploit:~
{
  "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)"]
    ]
  }]
}

8. Structured model output (for CI/IDE)

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format model | jq '.call_chains[0]'
root@kitploit:~
{
  "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
}

9. ProGuard/R8 mapping — query and display

With --mapping, both input and output support original (unobfuscated) names.

Query by original name → auto-converts to obfuscated name for DEX search:

root@kitploit:~
# 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:

root@kitploit:~
# Tree trace with deobfuscated names
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace --depth 3
root@kitploit:~
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:

root@kitploit:~
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace
root@kitploit:~
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:

root@kitploit:~
# 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:

10. Hidden API detection

root@kitploit:~
# 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
root@kitploit:~
#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. Search string constants (content:// URIs, API keys, etc.)

root@kitploit:~
# 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
root@kitploit:~
[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)

12. Filter by class prefix

root@kitploit:~
# 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/"

13. Combine everything

root@kitploit:~
# 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/"

14. HTML report

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format html --output report.html

Opens in any browser — collapsible call trees, search bar, dark theme.

15. SARIF for GitHub Code Scanning

root@kitploit:~
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]"

16. APK diff

root@kitploit:~
# Compare two APK versions
dexfinder --dex-file new.apk --diff old.apk --query "getDeviceId"
root@kitploit:~
+ 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

17. CI gate with --fail-on

root@kitploit:~
# 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

Performance

Benchmarked on Apple M-series, single thread:

Compared to veridex (C++, imprecise mode) on the same ~300MB APK:

  • veridex precise: 27s (no reflection via Binder/AIDL)
  • veridex imprecise: >32 min (killed, cartesian product explosion)
  • dexfinder: 5.4s (reverse-index optimization)

All Options

Config File

Create .dexfinder.yaml in your project root to set defaults:

root@kitploit:~
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.

Building from Source

root@kitploit:~
git clone https://github.com/JuneLeGency/dexfinder.git
cd dexfinder
go build -o dexfinder ./cmd/dexfinder/
go test ./...

License

Apache License 2.0


dexfinder

官网: junelegency.github.io/dexfinder

跨平台 APK/DEX 方法与字段引用查找器,支持调用链追踪、ProGuard/R8 反混淆、Android Hidden API 检测。

基于 Android veridex 原理,用 Go 重新实现并增强:更快的反射检测、多层调用链追踪(veridex 仅一层)、灵活的输出格式。

特性

  • APK/DEX/JAR 扫描 — 解析 DEX 字节码,提取所有方法/字段/字符串引用
  • 多格式查询 — 支持 Java 类名、DEX/JNI 签名、简单关键字
  • 调用链追踪 — 向上追溯 N 层调用者,合并树或展开列表,自动检测递归环
  • ProGuard/R8 反混淆 — 加载 mapping.txt,显示原始名称
  • Hidden API 检测 — 加载 hiddenapi-flags.csv,检测 blocked/unsupported API
  • 反射检测 — 类名×字符串交叉匹配,发现反射调用的隐藏 API(兼容 veridex)
  • 灵活输出 — text / json / model / html / sarif 格式,tree / list 布局,java / dex 命名风格——正交组合
  • 彩色终端输出 — 自动检测 TTY,标签、树形连接线、API 级别着色
  • APK 差异对比 — 对比两个 APK 版本,检测新增/移除/变化的 API 引用
  • HTML 报告 — 自包含交互式 HTML,可折叠树、搜索过滤、暗色主题
  • SARIF 输出 — SARIF 2.1.0 格式,支持 GitHub Code Scanning、VS Code
  • CI 集成 — --fail-on blocked 检测到受限 API 时返回非零退出码
  • 配置文件 — .dexfinder.yaml 项目默认配置,命令行参数覆盖
  • 零外部依赖 — 纯 Go 实现,自包含 DEX 解析器
  • 跨平台 — macOS (Intel / Apple Silicon)、Linux (amd64 / arm64)、Windows

安装

Homebrew (macOS / Linux):

root@kitploit:~
brew install junelegency/tap/dexfinder

脚本安装 (自动检测系统):

root@kitploit:~
curl -sSL https://raw.githubusercontent.com/JuneLeGency/dexfinder/main/install.sh | bash

Go 安装:

root@kitploit:~
go install github.com/JuneLeGency/dexfinder/cmd/dexfinder@latest

二进制下载: Releases

快速开始

root@kitploit:~
# 查看 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)

输出控制

三个独立维度,自由组合:

root@kitploit:~
--format  (text / json / model / html / sarif)    输出什么
--layout  (tree / list)                           怎么排列调用链
--style   (java / dex)                            怎么显示名称
--color   (auto / always / never)                 终端着色

--layout 对比(配合 --trace)

tree — 合并共同路径,一棵树展示全貌:

root@kitploit:~
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 风格):

root@kitploit:~
--- 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 输出

root@kitploit:~
# 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 的区别:

root@kitploit:~
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)

加载 --mapping 后,输入和输出都支持原始(未混淆)名称。

用原始名查询 → 自动转换为混淆名搜索 DEX:

root@kitploit:~
# 用原始简短类名查(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

输出反混淆名称:

root@kitploit:~
# trace 树形 + 反混淆
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --trace

同时显示混淆名和原始名:

root@kitploit:~
dexfinder --dex-file app.apk --query "KotlinCases" --mapping mapping.txt --show-obf --trace
root@kitploit:~
com.example.KotlinCases.fetchLocationAsync(KotlinCases.java)
└── com.example.KotlinCases$testCoroutines$3.invokeSuspend(KotlinCases.java)  [obf: G7.e]

与其他参数自由组合:

root@kitploit:~
# 原始名 + 展开列表
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

输入×输出矩阵:

Hidden API 检测

root@kitploit:~
# 下载 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

字符串搜索

root@kitploit:~
# 搜索代码中的 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

按包名过滤

root@kitploit:~
# 只扫描自己的代码
dexfinder --dex-file app.apk --query "getDeviceId" --class-filter "Lcom/mycompany/"

组合使用

root@kitploit:~
# 反混淆 + 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/"

HTML 报告

root@kitploit:~
dexfinder --dex-file app.apk --query "getDeviceId" --trace --format html --output report.html

浏览器打开即用——可折叠调用树、搜索栏、暗色主题。

SARIF(GitHub Code Scanning)

root@kitploit:~
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --format sarif > results.sarif

APK 版本对比

root@kitploit:~
dexfinder --dex-file new.apk --diff old.apk --query "getDeviceId"
root@kitploit:~
+ 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

CI 卡点

root@kitploit:~
# 检测到 blocked API 时 CI 失败
dexfinder --dex-file app.apk --api-flags hiddenapi-flags.csv --fail-on blocked
# 退出码: 0 = 通过, 2 = 有违规

性能

Apple M 系列芯片,单线程:

与 veridex (C++) 在同一 ~300MB APK 上对比:

  • veridex precise: 27s(无法追踪 Binder/AIDL 反射)
  • veridex imprecise: >32 分钟(笛卡尔积爆炸,被 kill)
  • dexfinder: 5.4s(反向索引优化)

全部参数

配置文件

在项目根目录创建 .dexfinder.yaml 设置默认值:

root@kitploit:~
mapping: ./build/outputs/mapping.txt
class-filter: "Lcom/mycompany/"
api-flags: ./hiddenapi-flags.csv
style: java
depth: 8
color: auto

命令行参数始终覆盖配置文件。

从源码构建

root@kitploit:~
git clone https://github.com/JuneLeGency/dexfinder.git
cd dexfinder
go build -o dexfinder ./cmd/dexfinder/
go test ./...

许可证

Apache License 2.0

Download Tool
FormatExampleBehavior
Simple namegetDeviceIdFuzzy substring match across all APIs
Java classandroid.telephony.TelephonyManagerAll methods/fields of that class
Java class#methodandroid.telephony.TelephonyManager#getDeviceIdAll overloads of that method
Java full signature...TelephonyManager#getDeviceId()Exact + overload fallback
DEX/JNI signatureLandroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;Exact match only
ValueDescription
textPlain text output with colored tags (default)
jsonJSON — scan results or trace with tree/list layout
modelStructured JSON with full MethodInfo/FieldInfo types (for IDE/CI)
htmlSelf-contained HTML report with collapsible trees and search
sarifSARIF 2.1.0 static analysis format (GitHub / VS Code)
ValueWhat it searchesQuestion it answersOutput tag
allCallee APIs + fields + code strings"Who calls this API?" (default)[METHOD] [FIELD] [STRING]
calleeOnly target API signatures in invoke-* / get/put instructions"Who calls this specific method/field?"[METHOD] [FIELD]
callerOnly the calling method's signature"What does this method call internally?"[CALLER→]
stringString constants in const-string instructions"Where is this string used in code?"[STRING]
string-tableCode strings + full DEX string table"Does this string exist anywhere in DEX?" (includes annotations, dead code)[STRING] [STRING_TABLE]
everythingAll of the above combinedFull pictureall tags
TagMeaning
[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 inputNo 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 SizeDEX FilesClassesMethod RefsScanHidden API
~1 MB1~2K~18K24ms—
~10 MB2~25K~100K335ms—
~300 MB30+~180K~1.2M3.9s5.4s
FlagDescriptionDefault
--dex-fileAPK/DEX/JAR file to analyze (required)—
--querySearch keyword (Java, DEX/JNI, or simple name)—
--traceEnable call chain tracing (requires --query)false
--depthMax call chain depth5
--layoutTrace layout: tree or listtree
--styleName style: java or dexjava
--formatOutput format: text, json, model, html, sariftext
--outputWrite output to file instead of stdout—
--colorColor mode: auto, always, neverauto
--mappingProGuard/R8 mapping.txt path—
--show-obfShow obfuscated names alongside deobfuscatedfalse
--api-flagsPath to hiddenapi-flags.csv—
--class-filterComma-separated class descriptor prefixes—
--exclude-api-listsAPI lists to exclude from reporting—
--scopeSearch scope: all, callee, caller, string, string-table, everythingall
--diffCompare with another APK/DEX and show API differences—
--fail-onExit non-zero if hidden APIs at this level found (CI gate)—
--statsShow summary statistics onlyfalse
--versionShow versionfalse
格式示例行为
简单名称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→]
stringconst-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 MB1~2K~18K24ms—
~10 MB2~25K~100K335ms—
~300 MB30+~180K~1.2M3.9s5.4s
参数说明默认值
--dex-fileAPK/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、sariftext
--output输出到文件而非 stdout—
--color颜色模式: auto、always、neverauto
--mappingProGuard/R8 mapping.txt 路径—
--show-obf同时显示混淆名和反混淆名false
--api-flagshiddenapi-flags.csv 路径—
--class-filter类描述符前缀过滤(逗号分隔)—
--exclude-api-lists排除的 API 级别—
--scope搜索范围: all、callee、caller、string、string-table、everythingall
--diff对比另一个 APK/DEX,显示 API 差异—
--fail-on检测到指定级别 API 时返回非零退出码(CI 卡点)—
--stats仅显示统计摘要false
--version显示版本号false