# Этап 1. Статический анализ — отчёт - **Дата:** 2026-05-16 - **Аналитик:** vladtechno@gmail.com + Claude - **Источники:** локальные APK в `recon/artifacts/`, jadx 1.5.5 декомпиляция --- ## 1. Что разбирали Два приложения одного вендора **NaughtySoft**: | Приложение | APK | Версия | Назначение | |---|---|---|---| | «Водитель» | `com.naughtysoft.TtcDriver` (XAPK split) | 1.2.313 (build 323) | Основное приложение для водителей: балансы, штрафы, платежи, обращения, осмотры | | «Механик» | `com.naughtysoft.ttc` | 1.8.13 (build 165) | Приложение для механиков парка: фото машин в 1С | Оба от одного вендора (`com.naughtysoft.*`), технологический стек **разный** (см. §3) — признак того, что вендор находится в процессе технологической миграции и не унифицирует разработку. --- ## 2. Метаданные APK ### Водитель (`com.naughtysoft.TtcDriver`) | Параметр | Значение | |---|---| | Version | 1.2.313 (build 323) | | Target SDK | 36 (Android 16) | | Min SDK | 24 (Android 7) | | Main Activity | `com.naughtysoft.TtcDriver.MainActivity` | | Permissions | INTERNET, CAMERA, RECORD_AUDIO, STORAGE, WAKE_LOCK, POST_NOTIFICATIONS, FCM (`c2dm.permission.RECEIVE`), AD_ID, ACCESS_NETWORK_STATE | | Permissions, которых **НЕТ** | GPS (ACCESS_FINE/COARSE_LOCATION), SMS, READ_CONTACTS, READ_PHONE_STATE, BIND_NOTIFICATION_LISTENER | | `android:usesCleartextTraffic` | **true** (приложение умеет HTTP без TLS) | | `network_security_config.xml` | **отсутствует** (TLS pinning через XML не настроен) | | Распространение | XAPK с App Bundle (base + split: arm64_v8a, en, mdpi, zh) | | Native ABI | **только arm64_v8a** (нет x86_64, нет armeabi-v7a) | Отсутствие GPS-разрешений = приложение пассивное, не трекает позицию водителя. Отсутствие SMS-разрешений = OTP-перехвата автоматического нет, логин классический. ### Механик (`com.naughtysoft.ttc`) | Параметр | Значение | |---|---| | Version | 1.8.13 (build 165) | | Target SDK | 33 (Android 13) | | Min SDK | 19 (Android 4.4) | | Application Label | «Механик» | | Permissions | INTERNET, CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, STORAGE, VIBRATE, NETWORK_STATE, WIFI_STATE | | Native ABI | только arm64_v8a | В Механике в отличие от Водителя есть **GPS** и используется **Xamarin** (см. §3). --- ## 3. Технологические стеки ### Водитель — Flutter (Dart AOT) Подтверждено наличием: - `lib/arm64-v8a/libflutter.so` — Flutter engine (11 МБ) - `lib/arm64-v8a/libapp.so` — **Dart AOT snapshot** с бизнес-логикой (9.6 МБ) - Java-пакеты: `io/flutter/`, `dev/flutter/pigeon`, `_COROUTINE/`, Kotlin runtime - Flutter-плагины: `dev/fluttercommunity/plus`, `com/baseflow/permissionhandler`, `com/jrai/flutter_keyboard_visibility`, `io/scer/pdfx`, `studio/midoridesign/gal`, `io/scer/pdf_renderer`, `dev/fluttered/map_launcher` **Что это значит для реверса:** - Бизнес-логика приложения — **в Dart, скомпилированном AOT в `libapp.so`**. jadx-декомпиляция Java/Kotlin даёт только тонкие plugin wrappers, не бизнес-код. - Все строковые константы (URL, paths, ключи) хранятся в `libapp.so` как plain ASCII → извлекаемы через `grep -a`/`strings` (см. §4). - HTTP-запросы Flutter делает через стандартный Dart `HttpClient` → видимы в mitmproxy как обычный HTTPS (без custom низкоуровневых трюков). - Дальнейший реверс Dart-кода (поведение, проверки) — через **reFlutter** (требует пересборки snapshot) или динамический анализ через mitmproxy. На статическом этапе ограничиваемся извлечёнными строками. ### Механик — Xamarin (.NET/Mono) Подтверждено наличием: - Java-пакеты: `xamarin/`, `mono/`, `crc64xxxxxxxxxxxxxxxx/` (CRC64-обфускация имён классов — характерный паттерн Xamarin) - `assets/assemblies/assemblies.blob` (4 МБ) — упакованный контейнер всех .NET DLL - `assets/assemblies/assemblies.manifest` (1.6 КБ) — манифест содержимого blob **Что это значит для реверса:** - jadx даёт ноль информации о логике Механика (всё в C# DLL). - Для распаковки нужен **pyxamstore** (распаковать blob → отдельные DLL) + **dnSpy/ILSpy** для C# декомпиляции. - Это **отдельный поток работы**, отложен. Приоритет — водитель. **Вывод о стеке вендора:** Xamarin (Mechanic) сейчас deprecated Microsoft'ом в пользу .NET MAUI. Driver переписан на Flutter — современный стек. Вендор находится в процессе технологической миграции, что согласуется с фактом «прекратил доработки» — ресурсы ушли на перенос/переход, а не на обновление наших фич. --- ## 4. Сетевая инфраструктура Все извлечены из `libapp.so` водительского приложения через `grep -aoE 'https?://...'`. ### Бэкенды | Endpoint | Назначение | |---|---| | **`https://api.ttcontrol.naughtysoft.ru/api`** | Главный API вендора NaughtySoft. Основной канал общения приложения с сервером. | | **`https://taksi.0nalog.com:1703/`** | Нестандартный порт **1703** — классический паттерн **HTTP-сервиса 1С Предприятие**. С большой вероятностью это сам сервер 1С PremiumPark, на котором работает конфигурация вендора. Имя `0nalog` (вместо `nalog`) — возможный obscurity-приём. | | **`https://ttcdriver.firebaseio.com`** | Firebase Realtime Database. Помимо FCM-пушей, часть данных может синхронизироваться через Realtime DB. Project ID: `ttcdriver`. | ### Архитектурная гипотеза ``` Driver App (Flutter) │ ├──► api.ttcontrol.naughtysoft.ru (HTTPS, основное взаимодействие) │ │ │ └──► (на бэке вендора, вероятно) ──► taksi.0nalog.com:1703 (1С) │ ├──► taksi.0nalog.com:1703 (возможно, прямые запросы — нужно подтвердить на этапе 2) │ ├──► ttcdriver.firebaseio.com (Realtime DB + FCM регистрация) │ └──► FCM (Firebase Cloud Messaging — push-уведомления о штрафах и пр.) ``` Подтвердить факт прямых обращений на `0nalog:1703` (или это идёт только через прокси `api.ttcontrol`) — задача этапа 2 (mitmproxy). ### Карта API endpoints Извлечены пути `/v1/...` и `/v3/...` из `libapp.so`. Префикс домена — `api.ttcontrol.naughtysoft.ru/api`. | Endpoint | Назначение (гипотеза) | |---|---| | `/v1/GetBalance` | Остаток баланса водителя | | `/v1/GetFines` | Список штрафов | | `/v1/GetChecks` | Чеки 54-ФЗ | | `/v1/GetPayroll` | Зарплата/начисления v1 | | `/v3/GetPayroll` | Зарплата/начисления v3 (новее) | | **`/v1/CreatePayment`** | **Инициация платежа** | | `/v1/GetPaymentDetails/` | Детали платежа | | **`/v1/BanksSBP`** | **Список банков СБП** — платежи через Систему Быстрых Платежей | | `/v1/ChangeQIWIWalletCardNumber` | QIWI Wallet (legacy — QIWI закрылся в 2024, мёртвый код) | | `/v1/CreateAppeal` | Создать обращение/заявку | | `/v1/GetAppealHistory` | История обращений водителя | | `/v1/AddMessageAppeal` | Добавить сообщение к обращению | | **`/v1/AddInspection`** | **Добавить осмотр (фото повреждений)** | | **`/v1/FOTO/`** | **Endpoint для фотографий** | | `/v1/AttractedAdd` | Добавить привлечённого (реферал?) | | `/v1/AttractedList` | Список привлечённых | | `/v1/OnLine` | Heartbeat / online status | | `/v1/GetStatus/` | Статус (требует расшифровки на этапе 2) | | `/v1/Sell` | Продать что-то (требует расшифровки) | | `/v1/GetListOfQuestions` | Список вопросов (FAQ / скрининг) | ### Аутентификация Найдены характерные строки в `libapp.so`: - `Authorization` — заголовок HTTP - `Bearer` — Bearer-токен - `apiKey` — упоминание (вероятно Firebase API key) - `authorization` (lowercase) — тоже встречается **Гипотеза:** стандартная Bearer-token аутентификация. Логин → получение access_token → дальше во всех запросах `Authorization: Bearer `. Подтвердить и понять lifecycle (refresh? expiry?) — задача этапа 3. --- ## 5. Защитные механизмы ### TLS pinning - **На уровне Android system (network_security_config.xml):** отсутствует — конфиг не найден в декомпиле. - **Cleartext traffic разрешён** — приложение умеет HTTP без TLS (вероятно для `taksi.0nalog.com:1703`). - **Программный TLS pinning в Dart-коде:** возможен, но в `libapp.so` явных маркеров pinning'а (типа `setTrustedRoots`, custom SecurityContext с pinned certs) поверхностный grep не выявил. Проверится на этапе 2: если mitmproxy сразу читает трафик — pinning'а нет; если нет — нужен reFlutter/Frida. **Прогноз:** на этапе 2 mitmproxy будет работать **без обхода TLS pinning**. Это сильно упрощает разведку. ### Root/Emulator detection Не сканировалось специально (требует анализа Dart-кода в `libapp.so`). На этапе 2 проверим эмпирически — запустится ли приложение на эмуляторе. Учитывая что: - Приложение Flutter (без agressive anti-debug по умолчанию) - Нет premium-фич, ориентированных на security (банковский класс, антифрод) — вероятность блокирующего detection'а низкая. ### Request signing / HMAC Маркеров явного HMAC (типа `Mac.getInstance("HmacSHA256")`) в Kotlin-стороне не найдено (большая часть Java-кода — Flutter engine + plugins, без бизнес-логики). В Dart возможна реализация, но это нестандартный паттерн для Flutter приложений — обычно полагаются на Bearer + TLS. ### Прочее - **Play Integrity API** — не используется (нет соответствующих библиотек в декомпиле). - **App attestation / SafetyNet** — отсутствует. --- ## 6. Сторонние SDK и зависимости ### Из Kotlin/Java декомпиляции водителя - `com.google.firebase.*` — Firebase (FCM, аналитика) - `com.google.android.gms.*` — Google Play Services - `dev.flutter.pigeon` — Flutter Pigeon (Dart ↔ Native bridges) - `io.flutter.*` — Flutter engine - `com.baseflow.permissionhandler` — permission_handler plugin - `com.jrai.flutter_keyboard_visibility` — keyboard visibility plugin - `io.scer.pdfx`, `io.scer.pdf_renderer` — PDF rendering plugins - `studio.midoridesign.gal` — gal plugin (сохранение в галерею) - `dev.fluttercommunity.plus` — Flutter community plugins - `dev.fluttered.map_launcher` — map_launcher plugin (открытие карт) - `com.github.rmtmckenzie.native_device_orientation` — ориентация устройства - `com.softmaestri.notification` — кастомные нотификации (другой вендор?) - `com.getkeepsafe.relinker` — динамическая загрузка native libraries - `org.apache.commons` — Apache Commons - `org.chromium.support_lib_boundary` — WebView boundary library ### **НЕ найдено** (важно): - **`ru.yoomoney.*`** — нет ЮКассы SDK - **`ru.tinkoff.*`** — нет Tinkoff Acquiring SDK - **`com.yandex.payments.*`** — нет Yandex Pay - **`com.sberbank.*`** — нет Сбер SDK - `com.squareup.okhttp3` / `retrofit2` — нет (HTTP идёт через Dart) - `dagger`, `hilt` — нет DI-фреймворков (Flutter сам по себе их не требует) **Вывод по платежам:** на Kotlin-стороне платёжных SDK провайдеров нет. Платёж через `/v1/CreatePayment` скорее всего возвращает **deep link** (типа `https://qr.nspk.ru/` для СБП или URL веб-страницы провайдера), и Flutter открывает его через стандартный intent. Это **отличный сценарий для миграции** — точно повторяемо в нашем приложении без необходимости лицензировать чьи-то SDK. --- ## 7. Промежуточные гипотезы 1. **Архитектура двухслойная**: NaughtySoft API (`api.ttcontrol`) — фасад, под капотом стоит 1С (`taksi.0nalog:1703`). Подтвердить на этапе 2: смотреть, идут ли с приложения **прямые** запросы на `0nalog:1703` (тогда оба слоя независимы), или только на `api.ttcontrol` (тогда `0nalog` — публично доступный backend 1С только в декомпиле, а реально приложение его не дёргает). 2. **Платежи через СБП + deep links**, без нативных SDK провайдеров → **легко повторимо** в нашем будущем приложении. 3. **Фото-функция (`/v1/AddInspection`, `/v1/FOTO/`) уже есть на бэке** — она просто не выдана водителям в UI текущего приложения. Если на этапе 2 удастся снять трафик этих endpoints (через Механика или через намеренный вызов в Driver если кнопка где-то есть), мы получим готовый протокол для нашего блока B без дизайна с нуля. 4. **QIWI код мёртв** — индикатор того, что подрядчик не зачищает мёртвый функционал. Подтверждает «прекратили доработки». 5. **TLS pinning слабый или отсутствует** → mitmproxy будет работать в этап 2 «из коробки». --- ## 8. Open questions для следующих этапов - Какой формат запроса/ответа на `/v1/CreatePayment`? (этап 2) - Использует ли приложение `/api/...` префикс или `/v1/...` идут напрямую от корня? (этап 2) - Использует ли водитель `taksi.0nalog.com:1703` напрямую или только через прокси `api.ttcontrol`? (этап 2) - Программный TLS pinning в Dart — есть? (этап 2, эмпирически) - Refresh-токен и его lifecycle — какой? (этап 3) - Что приходит в FCM-сообщении при штрафе? Полный объект или только триггер «обнови данные»? (этап 5) - Что лежит в `assemblies.blob` Механика? Те же endpoints или другие? (отдельный поток) --- ## 9. Блокеры и риски | # | Риск | Митигация | |---|---|---| | R1 | **ARM-only ABI** в обоих APK — на x86_64 эмуляторе `adb install` падает с `INSTALL_FAILED_NO_MATCHING_ABIS` | Для этапа 2 либо: (a) создать AVD x86_64 API 33+ с включённой ARM-translation, (b) использовать физическое Android-устройство, (c) использовать ARM-эмулятор (медленный) | | R2 | Программный TLS pinning в Dart-коде возможен, но не подтверждён на статике | Проверить эмпирически на этапе 2; если есть — обойти через **reFlutter** | | R3 | Механик на Xamarin требует отдельного тулинга (pyxamstore + dnSpy) для разбора C# логики | Отдельный поток работы; приоритет — водитель | | R4 | Часть Dart-логики (валидация, формат запросов) невидима без динамики | Перенесено на этап 2 (mitmproxy) | --- ## 10. Артефакты | Файл | Что | |---|---| | `recon/artifacts/original-driver.xapk` | Исходный XAPK водителя из APKPure | | `recon/artifacts/driver-xapk/` | Распакованный XAPK (base APK + splits + manifest.json) | | `recon/artifacts/original-mechanic.apk` | APK Механика | | `recon/artifacts/decompiled/driver/` | jadx-декомпиляция водителя (4331 классов, 25 errors ≈ 0.6%) | | `recon/artifacts/decompiled/mechanic/` | jadx-декомпиляция Механика (даёт только Xamarin glue, не C# логику) | | `recon/artifacts/native/driver/lib/arm64-v8a/libapp.so` | Извлечённый Dart AOT snapshot водителя — главный источник URL и endpoints | --- ## 11. Следующий шаг (этап 2) Все необходимые данные для разворачивания этапа 2 готовы: - Список endpoints для отслеживания — есть - Базовые URL'ы — есть - Подтверждено отсутствие XML-pinning'а — mitmproxy будет работать - Топология FCM известна — этап 5 пойдёт от Firebase project `ttcdriver` **Перед этапом 2 нужно решить ARM-блокер** (R1): выбрать ARM-эмулятор / x86_64 с ARM translation / физическое устройство. Это **открытый пункт для пользователя**. После этого по плану: установка приложения на стенд → mitmproxy + системный CA → проигрыш сценариев S1-S6 (см. §5 design-doc'а) → каталог реальных запросов/ответов.