- PVSM.RU - https://www.pvsm.ru -
Привет, Хабр

Если читали мои предыдущие статьи - знаете контекст. Если нет - кратко:
С 1 сентября 2025 MAX предустанавливается на все продаваемые в РФ телефоны
Домен max.ru [1] - в белом списке ТСПУ.
Пока скрипт-кидиdom находят по одной мелкой дырке и пишут об этом статьи и сайты я взял APK МАХ и реверснул его целиком.
Макс отправляет на сервера VK то какие у вас скачаны приложения
Детекцию VPN - приложение проверяет наличие VPN-соединения и по команде сервера может полностью заблокировать вам доступ к чатам и мини-аппам, пока вы его не выключите.
Тотальный трекинг адресной книги - MAX в реальном времени следит за изменениями контактов, отправляет серверу размер вашей телефонной книги и собирает хеши номеров даже тех людей, которые в мессенджере не зарегистрированы.
Обход Google Play и жесткий Force Update - сервер может заблокировать работу текущей версии приложения и принудительно установить апдейт со своего CDN, причем в коде заложена возможность ставить APK в обход системы.
Управление NFC-чипом из мини-апп - любое внутреннее мини-приложение может без предупреждения передать на NFC-терминал свой кастомный payload (например, имитировать пропуск или карту).
Фейковые чаты
Удаление сообщений из базы пушами - сервер может отправить скрытый пуш-запрос, который сотрет сообщение прямо из локальной базы данных на вашем телефоне без следа, или незаметно запросить ваши координаты.
Отключение TLS-валидации и RCE
Передачу номера (Mobile ID) по открытому HTTP - для авторизации без SMS мессенджер шлет запросы операторам в незашифрованном виде, чтобы те вписывали ваш номер в заголовки. Этот же механизм доступен системным мини-аппам без вашего ведома.
Скрытый SDK деанонимизации и запись звука - обфусцированный модуль trace_flow собирает реальные IP-адреса в обход VPN, а функция collect-debug-dump позволяет серверу тайно писать сырой звук с микрофона во время звонков и заливать его в аналитику.
Аппаратный фингерпринт через Widevine DRM - для отслеживания используется неизменяемый ID из защищенной зоны процессора (TEE), который невозможно сбросить даже после удаления приложения или Hard Reset устройства.
ZipSlip уязвимость в DownloadService (Удаленное исполнение кода)
И много всего другого

В MAX встроен MyTracker SDK от VK (Tracker ID 34982109644049932883, инициализация в defpackage/d6.java при старте OneMeApplication). И в нём есть отдельный модуль для сбора того, что у вас установлено.
Класс: com.my [2].tracker.core.o.f (AppsDataProvider).
private static List b(List list) {
ArrayList arrayList = new ArrayList();
for (PackageInfo packageInfo : list) {
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if ((applicationInfo.flags & 1) == 0) { // не-системные
arrayList.add(new e.a(
applicationInfo.packageName,
TimeUtils.convertToSec(packageInfo.firstInstallTime)
));
}
}
return arrayList;
}
Через интерфейс MyTrackerConfig.InstalledPackagesProvider.getInstalledPackages() берётся весь список пакетов, фильтруется по flags & 1 == 0 (выкидываются системные), и для каждого юзерского приложения снимается:
packageName - полное имя пакета
firstInstallTime - когда установлено, с точностью до секунды
public e a(InstalledPackagesProvider provider) {
List<PackageInfo> packages = provider.getInstalledPackages();
List filtered = b(packages);
String joined = a(filtered); // join через ","
String currentHash = n.a(joined);
String savedHash = enginePrefs.getString("appsHash");
if (savedHash.equals(currentHash)) return EMPTY; // не изменился — молчим
enginePrefs.setString("appsHash", currentHash);
return new e(filtered); // изменился — шлём ВЕСЬ список
}
appsHash хранится в SharedPreferences и сравнивается с текущим. Поставили новое приложение или удалили - хэш не сошёлся - улетает полный список целиком, не дельта. То есть сервер у себя всегда держит актуальный снапшот ваших приложений и видит сам факт изменений в реальном времени.
Endpoint захардкожен в TrackerConfig.b():
tracker-api.vk-analytics.ru
Это летит не в MAX backend api.oneme.ru [3], а на отдельный VK-аналитический контур vk-analytics.ru [4], рядом с GAID/OAID (w.java/z.java), Magisk-детектом из /proc/<pid>/mounts (m.java [5]) и AntiFraud-сенсорами (гироскоп, магнитное поле, давление, освещённость, proximity).
То есть: вот этот device fingerprint (GAID + OAID + sensor signature) + рутован он или нет + полный список того, что у него установлено
Думаю вы и так об этом слышали но повторюсь
В пяти разных местах приложения (контакты, история звонков, новая беседа, открытие чата, экран звонка) MAX показывает плашку:
«Отключите VPN. Чтобы пользоваться MAX»
Сама детекция тривиальная - hasTransport(TRANSPORT_VPN).
|
Уровень |
Поведение |
|---|---|
|
|
плашка всегда, как только видим VPN |
|
|
только если сервер «отдельно попросил» |
|
|
VPN активен И сервер попросил |
Сервер MAX в любой момент выкручивает уровень до 1 для нужного аккаунта. И тогда вы не сможете открыть чат, не закрыв VPN.
Мини-приложения внутри MAX просто не работают через VPN - WebAppHttpClient кидает WebAppHasVpnException. Хочешь воспользоваться мини-апой? Изволь выключить VPN.
ContentObserver подписан на корень адресной книги с notifyForDescendants=true. Любое изменение любой записи дёргает callback в реальном времени.
Обратная запись через SyncAdapter с флагом caller_is_syncadapter=true, обходящим часть Android-проверок. MAX пишет в вашу адресную книгу свои записи (имя + телефон + MIME-type tt_contact_mimetype).
Каждую сессию серверу отправляется общее число записей в вашей адресной книге. Просто как метрика. Даже если ни один из этих контактов не пользуется MAX.
new bbi(1, "app.phonebook.size", ...); // phonebookSize (Int)
И три PmsKey для сбора «не-контактов» (записи, которые НЕ пользователи MAX):
non-contact-sync-time
non-contact-max-chunk-size
non-contact-collection-interval
Хеши номеров уходят на сервер. Частоту и размер чанка задаёт сервер.
if (((mec) ...).a()) {
return; // звонок не показывается
}
Серверный флаг hbg.a == 1 + строка-версия. Если совпало - клиент уходит в ForceUpdateScreen, который заменяет всё содержимое приложения. Входящие звонки не приходят. Сообщения не отправляются. На экране:
«Писать и звонить в этой версии не получится»
И кнопка «Обновить», ведущая на https://download.max.ru/#android?version= [6]. APK с собственного CDN. Мимо Google Play.
В манифесте есть и неподставленный Gradle-placeholder ${REQUEST_INSTALL_PACKAGES}. Если кто-то соберёт релиз с этой переменной - MAX будет уметь устанавливать APK сам из себя.
Архитектура устойчива к ситуациям «Google Play заблокирован», «санкции», «нужно срочно доставить обновление всей стране». Один серверный флаг - и вся аудитория получит апдейт с серверов MAX.
В манифесте зарегистрирован Host APDU сервис с proprietary AID F0010203040303. Когда вы прикладываете телефон к NFC-терминалу, который запрашивает SELECT с этим AID, ОС маршрутизирует команды в MAX.
И что делает MAX?
Возвращает терминалу байты, которые туда положила открытая в этот момент мини-апа.
@Override
public byte[] processCommandApdu(byte[] bArr, Bundle bundle) {
if (b != -92) return error; // 0xA4 = SELECT
byte[] payload = jxb.d.get(); // <- что положила МИНИ-АПА
return payload;
}
То есть произвольная мини-апа внутри MAX в рантайме может зарядить NFC-сервис своим payload, и при касании к терминалу телефон отдаст этот payload. Карта лояльности? Пропуск? Цифровой ID? Что угодно. Что уходит по NFC - полностью контролируется кодом мини-приложения.
UX-предупреждения «мини-апа сейчас активирует NFC» в коде сервиса нет.
AID не банковский, для оплаты нужен другой AID и category=payment. Но любой не-платёжный сценарий - пожалуйста.
В списке 334 серверно-управляемых флагов есть очень показательные:
fake-chats — isFakeChatsEnabled
fake-in-app-review — isFakeInAppReviewEnabled
calls-fakeboss-incoming-call-enabled — callFakeBossesEnabled
В коде лежит класс FakeInAppReview. Это поддельный Pixel Perfect диалог «оцените приложение в Google Play». Оценка идет на сервера MAX. Серверно включаемый. Зачем - догадайтесь сами.
fake-chats - буквально серверно включаемые фейковые чаты в списке. в релизе. радостьтокакая.
calls-fakeboss-incoming-call-enabled - режим «фальшивого начальника» в звонке, с отдельным классом gj6.FakeBossListItem со всеми полями (contactServerId, phoneNumber, country, registrationDate). сервер может пометить профиль как «принадлежит организации» или наоборот - «не принадлежит».
И отдельно есть PmsKey devnull - DevNullServerConfig. Имя класса говорит само за себя: серверная фильтрация событий аналитики (выборочно - у отдельных аккаунтов).
В марте 2026 пресса заметила, что MAX обращается к Google, AWS, Telegram, WhatsApp.
HostReachabilityChecker. Список хостов приходит с сервера через PmsKey host-reachability. Не зашит в код. То есть сервер MAX в любой момент решает, какие домены вам прозондировать.
Клиент делает DNS-резолв + TCP-handshake к каждому хосту из списка. Результат + дополнительные данные улетают в OneLog:
{
"hosts": { "google.com": false, "telegram.org": false, ... },
"operator": "25099:MegaFon", // MCCMNC + название
"connection_type": 2,
"ip": "ВАШ_ВНЕШНИЙ_IP",
"vpn": 1 // 1 если активен VPN
}
То есть на сервер MAX в одном пакете уходит: какие хосты вам доступны, через какого оператора вы сидите, ваш внешний IP, есть ли у вас VPN.
Пресс-служба объяснила это «обеспечением работы звонков». Почему этот же IP вместе со списком VPN/оператор/доступность чужих сервисов улетает в общий аналитический канал OneLog одним JSON-ом никто так и не ответил
Функция getChooserIntentWithTgOnFirstPlaceOrDefault (sic) знает, установлен ли у вас Telegram (org.telegram.messenger).
Парсер FCM-push в MAX поддерживает тип MessageRemoved (и варианты ChatMessageRemoved, ChatMessageRemoved-channel). Когда такой push приходит:
nn6 parsed = ...; // парсит {chatId, msgId}
fei.a().e(parsed, ...); // УДАЛЯЕТ сообщение из локальной БД
То есть сервер по push может удалить сообщение из вашей локальной базы без следа.
Ещё веселее тип TamtamSpam:
uri — URI для нотификации
msg — текст
title — заголовок
imageUrl — картинка
Сервер отправляет push с произвольным URI, который откроется по тапу. Ничто в коде не ограничивает схему. То есть сервер MAX может отправить вам пуш-нотификацию от имени MAX, ведущую куда захочет - хоть в мини-апу, хоть на внешний сайт.
И тип LocationRequest - silent push, будит клиент, заставляет его подключиться к серверу по WS и быть готовым принять команду. Дальше сервер по WS может попросить координаты.
И из списка PmsKey:
outgoing-call-uri — URI исходящего звонка (можно подменять с сервера)
Сервер задаёт URI, по которому идёт исходящий звонок. Это рычаг подмены маршрута голоса.
Да, вы прочитали правильно. В списке PmsKey:
net-ssl-session-validate — SSLSession.isValid
Это серверный флаг. Если сервер MAX отправит false - клиент перестанет валидировать TLS-сессию.
Это значит, что серверной командой можно временно открыть клиент для MitM-атаки. Не сам сервер - а любая прокси-инфраструктура на пути. На корпоративной сети, на оператор-ной CG-NAT, на государственном ТСПУ.
В компании с другими флагами (log-sensitive - разрешить логи с чувствительными данными, user-debug-report - куда репортить лог) это образует комплект «дай мне всё, что лежит у тебя в памяти, и не проверяй сертификат тому, кто это запрашивает».
libEnhancementLibShared.so [7], 5.72 МБ. По строкам внутри:
/home/good/mainframer/webrtc4/.../one-ann-audio-processing/...
contrib/kaldi/.../feature-mfcc.cc
enh/modules/automatic_speech_recognition/asr_service.cpp
Это форк Google WebRTC, в который вкомпилили модуль one-ann-audio-processing (ann = artificial neural network). Внутри - полный embedded ML-runtime:
ASR (Conformer-CTC-128) - распознавание речи на устройстве
KWS (BCResNet streaming) - детекция ключевых слов в реальном времени на сыром аудио
Diarization - кто когда говорит
Speaker Recognition - идентификация говорящего по голосу
Audio Classifier - теги аудио-событий
TFLite + XNNPACK + опциональный Android NNAPI
BCResNetExternalStateKWS - streaming-режим: состояние сети живёт между батчами, что нужно для непрерывной детекции без задержек. Модель - это .tflite файл, который можно подменить с сервера.
Каждое срабатывание KWS улетает в аналитику как событие bad_call_detected_by_audio_spotter(confidence). Какое слово сработало в событии не передаётся (только confidence), но сам факт срабатывания на каждого юзера серверу известен.
Отдельно есть vk::enh::SpeakerRecognitionEngineFactory + SpeakerRecognitionVerifierFactory. То есть по голосу можно определить, что это говорит конкретно вы. Где хранятся voiceprints, кому отдаются - отдельный вопрос на отдельную статью.
Серверный ASR в групповых звонках включается автоматически. Класс AsrOnlineManager, формат AsrOnlineChunk(participantId, text) - то есть транскрипция с атрибуцией по участникам. Кто что сказал.
Запись звонков, кстати, по умолчанию privacy="PUBLIC". Запись летит в чат «Избранное» инициатора. Без E2E это значит - у сервера полный доступ.
Маленькая хорошая новость: в версии 26.16.0 (вышла после моего основного анализа) KWS-стек удалён. BCResNetKWS, BCResNetExternalStateKWS, FeatureExtractor - все классы вычищены. Но инфраструктура «скачать ML-модель по URL с сервера» сохранена - её просто переключили обслуживать только NoiseSuppression. Если решат вернуть KWS - всё готово.
А ещё я нашёл ZipSlip ( 7.0 до 9.8 по шкале CVSS ). Тот самый DownloadService, который качает файлы по URL с сервера - распаковывает ZIP без санитизации имён entry. new File(destDir, entry.getName()). Без проверки на .. Без канонизации.

То есть entry с именем ../../shared_prefs/ri9.xml - и клиент послушно перезапишет SharedPreferences. Токен авторизации, адрес сервера, debug-флаги - всё что лежит в sandbox.
../../ позволяет записать файл в любое место sandbox-а: SharedPreferences, БД, кеш. Перезаписать server.host [8] в prefs? Пожалуйста.
Открываем network_security_config.xml:
<domain-config cleartextTrafficPermitted="true">
<domain>mobileid.megafon.ru</domain>
<domain>idgw.mobileid.mts.ru</domain>
<domain>hhe.mts.ru</domain>
<domain>he-mc.tele2.ru</domain>
<domain>he-mc.t2.ru</domain>
<domain>balance.beeline.ru</domain>
</domain-config>
Шесть доменов, шесть операторов, HTTP без TLS. Начиная с Android 9 cleartext-трафик запрещён по умолчанию - но эти шесть доменов специально вынесены в исключения.
Зачем? Header Enrichment. Схема:
Ваш телефон в мобильной сети оператора.
Делает HTTP-запрос (открытым текстом) на оператор-ный эндпоинт.
Оператор на своём оборудовании дописывает в заголовки ваш MSISDN (номер телефона).
Сервер MAX видит заголовки → знает, кто вы. Без SMS-кода.
Почему обязательно HTTP без TLS? Потому что в TLS оператор видит только SNI и IP назначения, до содержимого не дотягивается. А чтобы вписать заголовки - нужен полный доступ к содержимому. Архитектурное требование: открытый канал. Это намеренная регрессия безопасности ради удобства интеграции с операторами.
Между телефоном и оператором (Wi-Fi, прокси, любой посредник) и на самом операторе - всё видно в чистом виде. И сам факт авторизации, и часто номер.
Точно такой же канал доступен мини-приложениям внутри MAX через приватный JS-bridge verify_mobile_id:
new zij("VERIFY_MOBILE_ID", 0);
public String d() { return "verify_mobile_id"; }
public boolean e() { return true; } // private = true
Контракт: мини-апа отправляет MAX-у URL оператора, MAX делает HTTP-запрос со своей мобильной сети, возвращает мини-апе headers целиком. Мини-апа парсит и узнаёт ваш номер.
В коде нет видимого диалога согласия. Метод приватный - для системных мини-апок без подтверждения. То есть «доверенная» мини-апа (государственная, банк, рекламный партнёр) может молча получить ваш MSISDN.
PmsKey webapp-phone-hash - серверно включается режим, в котором мини-апам отдаётся хеш номера телефона как стабильный идентификатор (фингерпринт между запусками). Теперь без HE можно связывать вас между разными мини-апами.
В MAX вшит отдельный, глубоко обфусцированный (через XOR-шифрование строк, детский сад) SDK под неймспейсом ru.trace_flow.dps (DPS - Digital Probe System ).
Что он делает: При каждом выходе приложения из фона он стучится на 6 внешних IP-чекеров (yandex, ifconfig.me [9], ipify, AWS и т.д.), чтобы узнать ваш реальный публичный IP-адрес, даже если вы сидите через сплит-туннель VPN.
Обход API Android: Чтобы понять, включен ли VPN, он не просто спрашивает систему, а через рефлексию перечисляет сетевые интерфейсы (tun, ppp, tap, ipsec).
Эксфильтрация: Ваш User ID, Device ID, Реальный IP, Флаг VPN, Оператор по симке он отправляет POST-запросом на левый домен trace-flow.ru/api/v1/report [10], которого нет в политике конфиденциальности и даже гугле.
Сервер может прислать WebSocket-сообщение с опкодом 2 и командой cmd. Клиент молча выполняет:
SYNC_CONTACTS: принудительно собирает всю вашу телефонную книгу и сливает на сервер.
SEND_LOG: вызывает фейковый краш (IllegalStateException("onNotifDebug")). Это триггерит штатный краш-репортер (Apptracer), который собирает весь logcat устройства (до 32 МБ логов), состояние всех потоков, дампы кучи и отправляет на sdk-api.apptracer.ru [11].
Итог: Сервер может по клику мышки выкачать ваши логи и контакты.
В кастомном WebRTC от VK/OK есть функция nativeSubmitDumpRequest.
Сервер через команды управления звонком может прислать JSON: {type: "collect-debug-dump", audio: true, duration: 2147483647}.
Телефон молча начинает писать сырой звук (raw PCM) с 6 точек пайплайна (включая чистый микрофон ДО шумоподавления и чистый звук собеседника).
Пишет в файлы на устройстве.
WorkManager (SampleUploadWorker) потом так же молча заливает эти аудиофайлы на apptracer.ru [12]. UI "Идёт запись" не появляется.
В библиотеке tech.kwik (отвечает за QUIC/WebTransport для передачи медиа в звонках) класс qse.java [13] реализует X509TrustManager с абсолютно пустыми методами checkServerTrusted.
Комментарий в коде прямо гласит (выводится в консоль): "SECURITY WARNING: INSECURE configuration! Server certificate validation is disabled".
Это в production-сборке. Любой провайдер может подменить сертификат для медиа-трафика звонков. Пришел в кафе, сделал ARP spoofing, читаешь сообщения гоев с QUIC.
В APK есть библиотека libqrcode.so [14]. По названию - сканер кодов. А на деле зашит нативный код верификации подписи APK (IntegrityProtectionInit, sign_check), который генерирует криптографический seed для звонков. Звонки не будут работать, если подпись APK изменена. Они буквально спрятали защиту от реверсеров в либу с безобидным именем.

Мини-аппы в MAX работают не как песочницы:
Сервер может вызвать evaluateJavascript() с любым кодом внутри любой запущенной мини-апы.
Через JS-bridge мини-апа может вызвать WebAppSetupScreenCaptureBehavior. Это программно снимает с Android-окна флаг FLAG_SECURE.
После этого любое другое приложение (или сам сервер через дамп экрана) может делать скриншоты ваших переписок.
JS-bridge также позволяет вызвать WebAppOpenMaxLink, куда можно передать любой внутренний диплинк (например, автологин) вообще без валидации URL.
Для деанонимизации (в том самом скрытом SDK) используется не только AID и MAC.
Приложение дергает MediaDrm Widevine UUID (edef8ba9-79d6-4ace-a3c8-27dcd51d21ed), хеширует его SHA-256 и использует как deviceId.
Этот идентификатор зашит в защищенную зону процессора (TEE). Он не сбрасывается при переустановке приложения, смене Google-аккаунта или даже сбросе до заводских настроек. Человека можно будет отследить навсегда.
MAX обязательно ставится на каждый новый телефон в РФ. И его домен всегда в белом списке ТСПУ. это единственный мессенджер, который останется работать. Содержащий всё вышеперечисленное.
Репозиторий - zarazaex69/m [15]
Если есть предложения по работе или личные вопросы - t.me/owenewans [16]
Подписывайтесь на t.me/openlibrecommunity [17] - там обновления и новые статьи.
Говорят они подарки дарят @nogosol [18]
ПОДАРКИ. ТЕЛЕГРАМ: t.me/openlibrecommunity [19]
РУБЛИ. СБП, КАРТА: pay.cloudtips.ru/p/28c476e5 [20]
КРИПТА. TON, USDT: UQD_Qc2cxLGe1P4wANi46cKdEvvzyJRrJTYPvGX2KAZDnsDh
КРИПТА, TRC 20, USDT: TYQqdACH5PrScvsMowSyS8JjaaF5wvFf5Q
КРИПТА, BTC: bc1qvw0ts0jk5e5dfj9fdez76j9ck95lqz04fpf02a
Автор: zarazaexe
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/slezhka/451776
Ссылки в тексте:
[1] max.ru: http://max.ru
[2] com.my: http://com.my
[3] api.oneme.ru: http://api.oneme.ru
[4] vk-analytics.ru: http://vk-analytics.ru
[5] m.java: http://m.java
[6] https://download.max.ru/#android?version=: https://download.max.ru/#android?version=
[7] libEnhancementLibShared.so: http://libEnhancementLibShared.so
[8] server.host: http://server.host
[9] ifconfig.me: http://ifconfig.me
[10] trace-flow.ru/api/v1/report: https://trace-flow.ru/api/v1/report
[11] sdk-api.apptracer.ru: http://sdk-api.apptracer.ru
[12] apptracer.ru: http://apptracer.ru
[13] qse.java: http://qse.java
[14] libqrcode.so: http://libqrcode.so
[15] zarazaex69/m: https://github.com/zarazaex69/m
[16] t.me/owenewans: https://t.me/owenewans
[17] t.me/openlibrecommunity: https://%D0%BD%D0%B0%20t.me/openlibrecommunit
[18] @nogosol: https://www.pvsm.ru/users/nogosol
[19] t.me/openlibrecommunity: https://t.me/openlibrecommunity
[20] pay.cloudtips.ru/p/28c476e5: https://pay.cloudtips.ru/p/28c476e5
[21] Источник: https://habr.com/ru/articles/1036222/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1036222
Нажмите здесь для печати.