# Как проверить APK-файл на скрытый код: разбор DEX и smali через SQL-запросы

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-proverit-apk-fayl-na-skrytyy-kod-razbor-dex-i-smali.html

Проверка APK на скрытый код — это поиск в установочном пакете Android логики, о которой вам не сказали: догрузки сторонних модулей из интернета, тихой отправки данных или чтения идентификаторов устройства. Гайд для стажёра, который уже умеет распаковывать архивы и запускать команды в терминале, но никогда не разбирал DEX (скомпилированный байт-код приложения) и smali (читаемый текстовый аналог этого байт-кода). Подходит для APK с Android 5.0 и выше (minSdk 21+), проверяется на ПК с Windows, macOS или Linux — root на телефоне не нужен.

## Требования и подготовка
![Иллюстрация к разделу «Требования и подготовка»](https://ai-release.org/guides/img/kak-proverit-apk-fayl-na-skrytyy-kod-razbor-dex-i-smali-ru-1.jpg)


- Java 17 или новее — без неё apktool (распаковщик APK) не запустится. Проверка: команда `java -version`.
- apktool 2.9.x — достаёт из APK папки `smali`, `smali_classes2`, `res` и файл `AndroidManifest.xml`.
- jadx 1.4.x — декомпилятор в Java-код, читать его проще, чем smali.
- Python 3.10+ и модуль `sqlite3` (SQLite — встроенная файловая база данных; модуль уже входит в Python).
- SQLite CLI — утилита `sqlite3` для ручных запросов.
- Анализируемый APK, скачанный из доверенного источника. Если приложение ставится с магазина вроде RuStore — берите файл оттуда: [как скачивать и устанавливать ИИ-приложения на Android](https://ai-release.org/guides/kak-skachivat-i-ustanavlivat-ii-prilozheniya-na-android.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).
- Рабочая папка, например `C:\apkcheck` или `~/apkcheck`, куда сложите APK и результаты.
- Тестовое устройство или эмулятор — только для запуска в изолированной среде, без личных аккаунтов.

## Пошаговая инструкция
![Иллюстрация к разделу «Пошаговая инструкция»](https://ai-release.org/guides/img/kak-proverit-apk-fayl-na-skrytyy-kod-razbor-dex-i-smali-ru-2.jpg)


1. Создайте рабочую папку и скопируйте туда APK. Сразу считайте хеш файла: `sha256sum app.apk` (на Windows — `certutil -hashfile app.apk SHA256`).
   **Пример:** вывод вида `3f2a...9c1b  app.apk`. Запишите его: если хеш изменится, значит файл подменили, и все выводы ниже недействительны.
   Почему это работает: хеш — отпечаток содержимого, любая правка байтов его меняет.

2. Распакуйте APK: `apktool d -f -o out app.apk`.
   **Пример:** в папке `out` появляются `AndroidManifest.xml`, `res/`, `smali/`, `smali_classes2/`. Если приложение многомодульное, папок `smali_classesN` будет несколько.
   Ожидаемый результат: `apktool` пишет «I: Copying assets and libs…» и завершается без ошибок.

3. Сделайте вторую копию — в Java: `jadx -d out_java app.apk`.
   **Пример:** в `out_java/sources/com/example/app/` лежат `.java`-файлы с читаемыми именами методов.
   Почему это работает: jadx умеет восстанавливать имена классов из отладочной информации, а smali — нет. Два представления дополняют друг друга.

4. Соберите индекс smali в SQLite — скрипт ниже кладёт каждую строку каждого `.smali` в таблицу.
```python
import pathlib, sqlite3
db = sqlite3.connect("smali.db")
db.execute("CREATE TABLE IF NOT EXISTS lines (file TEXT, line INTEGER, code TEXT)")
for path in pathlib.Path("out").rglob("*.smali"):
    for i, text in enumerate(path.read_text(encoding="utf-8", errors="replace").splitlines(), 1):
        db.execute("INSERT INTO lines VALUES (?,?,?)", (str(path), i, text))
db.commit()
```
   **Пример:** запуск `python index_smali.py`, на выходе — файл `smali.db` размером в десятки мегабайт.
   Почему это работает: SQLite превращает поиск по тысячам файлов в один запрос, а главное — позволяет группировать и считать совпадения.

5. Ищите динамическую загрузку кода — главный признак скрытой логики.
```sql
SELECT file, line, code FROM lines WHERE code LIKE '%DexClassLoader%';
SELECT file, line, code FROM lines WHERE code LIKE '%Ljava/lang/reflect/Method%';
```
   **Пример:** строка вида `invoke-virtual {v0, v1}, Ljava/lang/DexClassLoader;->loadClass:(...)`. Если рядом есть `const-string` с `http`, приложение скачивает и исполняет чужой код.
   Ожидаемый результат: пустая выборка — признак нормы; 5–20 совпадений в одном классе — повод читать его целиком.

6. Проверьте сбор данных об устройстве.
```sql
SELECT file, COUNT(*) AS hits FROM lines
WHERE code LIKE '%getDeviceId%' OR code LIKE '%getImei%' OR code LIKE '%getSubscriberId%'
GROUP BY file ORDER BY hits DESC LIMIT 10;
```
   **Пример:** вывод `smali/com/example/app/Analytics.smali | 7` означает, что класс собирает идентификаторы семь раз. Смотрите, куда эти значения передаются дальше.
   Почему это работает: `GROUP BY` и `ORDER BY` показывают самый «жадный» до данных класс, а не разбросанные одиночные вызовы.

7. Отдельно посмотрите сетевые строки в smali и в Java-выгрузке.
```sql
SELECT DISTINCT file FROM lines WHERE code LIKE '%const-string%http%';
```
   **Пример:** `smali/com/example/app/net/Uploader.smali` — откройте файл и посмотрите, какой URL собирается.
   Ожидаемый результат: список доменов, которые приложение реально использует.

8. Разберите `AndroidManifest.xml`: разрешения (`INTERNET`, `READ_PHONE_STATE`, `READ_SMS`), экспортированные компоненты (`android:exported="true"`), список `activity`, `service`, `receiver`.
   **Пример:** приложение-фонарик с разрешением `READ_SMS` — явное несоответствие заявленной функции.
   Почему это важно: скрытый код начинается с лишнего права.

9. Проверьте встроенные базы приложения — они тоже SQL, и в них часто лежат конфиги, endpoints и токены. Файлы ищите в `out/assets/` и `out/res/raw/` с расширениями `.db`, `.sqlite`, `.sqlite3`.
```bash
sqlite3 out/assets/config.db ".tables"
sqlite3 out/assets/config.db "SELECT * FROM settings LIMIT 5;"
```
   **Пример:** вывод `.tables` — `settings  telemetry_queue`. Вторая таблица с очередью отправки — сигнал о фоновой передаче данных.

10. Прогоните строки на подозрительный контент: `strings app.apk | grep -iE "base64|exec|su |chmod"`.
    **Пример:** длинная base64-строка внутри smali, которая декодируется в `.dex`. Это классическая упаковка скрытого модуля.
    Ожидаемый результат: короткий список, каждую строку проверяете вручную в smali.

11. Сведите выводы в чек-лист и решайте по нему:
- [ ] Есть динамическая загрузка кода (`DexClassLoader`, `loadClass`)?
- [ ] Есть сетевые адреса, не описанные в документации приложения?
- [ ] Приложение просит права, не нужные для его функции?
- [ ] Собираются ли IMEI, номер телефона, список установленных приложений?
- [ ] Найденные строки обфусцированы (однобуквенные имена классов, base64)?

## Возможные проблемы и решения
![Иллюстрация к разделу «Возможные проблемы и решения»](https://ai-release.org/guides/img/kak-proverit-apk-fayl-na-skrytyy-kod-razbor-dex-i-smali-ru-3.jpg)


**Симптом: `apktool` падает с ошибкой вида `Invalid resource` или «java.lang.OutOfMemoryError».** У больших APK не хватает памяти. Решение: закройте браузер и IDE, увеличьте лимит — `java -Xmx4g -jar apktool.jar d app.apk`; если ошибка осталась, ищите более новую версию apktool. Проверьте, что распаковка дошла до конца: папка `smali` должна существовать, иначе шаг 4 проиндексирует пустоту.

**Симптом: скрипт из шага 4 падает с `sqlite3.OperationalError: no such table` или создаёт базу на 0 строк.** Вы запустили его не из той папки. Решение: команда `pwd` (или `cd`) должна показать папку, где лежит `out`; путь `pathlib.Path("out")` относительный. Проверьте, что индекс реально наполнился: `sqlite3 smali.db "SELECT COUNT(*) FROM lines;"` — счётчик должен быть в сотнях тысяч.

**Симптом: SQL-запрос возвращает сотни совпадений, но среди них нет ничего опасного.** Слишком широкий шаблон: `LIKE '%http%'` ловит и строки лицензий, и подсказки интерфейса. Решение: сужайте до конкретного класса — добавьте `AND file LIKE '%net%'`, или ищите пары: строка с `http` должна встречаться в одном файле с `invoke` на сетевой метод. Так вы отсекаете шум. Если задача — понять, ведёт ли найденный код себя автономно, пригодится отдельная методика проверки: [тесты автономности ИИ-агента и риски](https://ai-release.org/guides/kak-proverit-mozhet-li-ii-agent-rabotat-avtonomno-i-bez.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

## FAQ

**Что такое smali простыми словами?**
Это текстовое представление байт-кода: каждая строка — одна инструкция виртуальной машины Android. Читается тяжелее Java, но именно в smali видно всё, что реально исполняется, включая код без исходников.

**Можно ли проверить APK без root и без установки приложения?**
Да. Всё в гайде делается на ПК над файлом: распаковка, декомпиляция и SQL-запросы root не требуют. Root нужен только если вы хотите снять дамп памяти уже запущенного приложения.

**Заменяет ли такой разбор антивирус?**
Нет. Антивирус ищет известные сигнатуры, а SQL-запросы по smali показывают поведение: загрузку кода, сбор идентификаторов, лишние права. Это разные слои проверки, и их стоит совмещать.

**Почему SQL, если DEX — не база данных?**
Мы сами переносим строки smali в SQLite на шаге 4. Дальше SQL даёт то, чего не даёт обычный поиск по файлам: `GROUP BY` по классам, счётчики совпадений и сортировку `ORDER BY` — то есть приоритет для ручного чтения.
