
Кроссплатформенный поисковик методов APK/DEX с трассировкой цепочек вызовов, деобфускацией ProGuard и обнаружением скрытых API
Английский | Китайский | Сайт

Кроссплатформенное средство поиска ссылок на методы и поля APK/DEX с трассировкой цепочек вызовов, деобфускацией ProGuard/R8 и обнаружением скрытых API Android.
Вдохновлено инструментом veridex от Android, перереализовано на Go с расширенными возможностями: более быстрое обнаружение рефлексии, трассировка цепочек вызовов (veridex показывает только один уровень) и гибкие форматы вывода.
--fail-on blocked завершается с ненулевым кодом при обнаружении ограниченных API.dexfinder.yaml для настроек проекта, флаги CLI переопределяютHomebrew (macOS / Linux):```bash brew install junelegency/tap/dexfinder
**Скрипт** (автоопределение ОС/архитектуры):```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
**Бинарный файл**: скачать из [Релизы](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 автоматически определяет и преобразует между ними.
| Format | Example | Behavior |
|---|---|---|
| Simple name | getDeviceId | Нечеткое совпадение подстроки во всех API |
| Java class | android.telephony.TelephonyManager | Все методы/поля этого класса |
| Java class#method | android.telephony.TelephonyManager#getDeviceId | Все перегруженные версии этого метода |
| Java full signature | ...TelephonyManager#getDeviceId() | Точное совпадение + возврат к перегрузкам |
| DEX/JNI signature | 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 | Структурированный JSON с полными типами MethodInfo/FieldInfo (для 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 | Только сигнатуры целевого API в инструкциях invoke-* / get/put | "Кто вызывает этот конкретный метод/поле?" | [METHOD] [FIELD] |
caller | Только сигнатура вызывающего метода | "Что этот метод вызывает внутри?" | [CALLER→] |
string | Строковые константы в инструкциях const-string | "Где используется эта строка в коде?" | [STRING] |
string-table | Строки кода + полная таблица строк DEX | "Существует ли эта строка где-либо в DEX? (включает аннотации, мертвый код)" | [STRING] [STRING_TABLE] |
everything | Все вышеперечисленное вместе | Полная картина | все теги |
Понимание 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` (по умолчанию) = `callee` + `string`. Направление `caller` намеренно исключено из значения по умолчанию, так как оно отвечает на принципиально другой вопрос. Используйте `--scope=caller` или `--scope=everything` явно, когда это необходимо.
**Понимание выходных тегов:**