Привет, Хабр

Если читали мои предыдущие статьи - знаете контекст. Если нет - кратко:
-
С 1 сентября 2025 MAX предустанавливается на все продаваемые в РФ телефоны
-
Домен
max.ru- в белом списке ТСПУ.
Пока скрипт-киди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 (Удаленное исполнение кода)
-
И много всего другого

MyTracker сливает список ваших приложений на сервера VK
В MAX встроен MyTracker SDK от VK (Tracker ID 34982109644049932883, инициализация в defpackage/d6.java при старте OneMeApplication). И в нём есть отдельный модуль для сбора того, что у вас установлено.
Класс: com.my.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, а на отдельный VK-аналитический контур vk-analytics.ru, рядом с GAID/OAID (w.java/z.java), Magisk-детектом из /proc/<pid>/mounts (m.java) и AntiFraud-сенсорами (гироскоп, магнитное поле, давление, освещённость, proximity).
То есть: вот этот device fingerprint (GAID + OAID + sensor signature) + рутован он или нет + полный список того, что у него установлено
MAX знает что вы используете VPN
Думаю вы и так об этом слышали но повторюсь
В пяти разных местах приложения (контакты, история звонков, новая беседа, открытие чата, экран звонка) MAX показывает плашку:
«Отключите VPN. Чтобы пользоваться MAX»
Сама детекция тривиальная - hasTransport(TRANSPORT_VPN).
|
Уровень |
Поведение |
|---|---|
|
|
плашка всегда, как только видим VPN |
|
|
только если сервер «отдельно попросил» |
|
|
VPN активен И сервер попросил |
Сервер MAX в любой момент выкручивает уровень до 1 для нужного аккаунта. И тогда вы не сможете открыть чат, не закрыв VPN.
Мини-приложения внутри MAX просто не работают через VPN - WebAppHttpClient кидает WebAppHasVpnException. Хочешь воспользоваться мини-апой? Изволь выключить VPN.
MAX знает, сколько у вас людей в телефоне
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=. 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. Но любой не-платёжный сценарий - пожалуйста.
Fake-chats и fake-in-app-review
В списке 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. Имя класса говорит само за себя: серверная фильтрация событий аналитики (выборочно - у отдельных аккаунтов).
Сервер спрашивает «а ты дотягиваешься до Telegram?»
В марте 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).
Сервер может удалить ваше сообщение пушем. И подменить URL звонка
Парсер 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, по которому идёт исходящий звонок. Это рычаг подмены маршрута голоса.
TLS-валидацию можно выключить серверной командой
Да, вы прочитали правильно. В списке PmsKey:
net-ssl-session-validate — SSLSession.isValid
Это серверный флаг. Если сервер MAX отправит false - клиент перестанет валидировать TLS-сессию.
Это значит, что серверной командой можно временно открыть клиент для MitM-атаки. Не сам сервер - а любая прокси-инфраструктура на пути. На корпоративной сети, на оператор-ной CG-NAT, на государственном ТСПУ.
В компании с другими флагами (log-sensitive - разрешить логи с чувствительными данными, user-debug-report - куда репортить лог) это образует комплект «дай мне всё, что лежит у тебя в памяти, и не проверяй сертификат тому, кто это запрашивает».
На вашем телефоне живёт ML-модель, слушающая ключевые слова
libEnhancementLibShared.so, 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 в prefs? Пожалуйста.Mobile ID: ваш номер уходит по открытому HTTP.
Открываем
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 можно связывать вас между разными мини-апами.Скрытый SDK для деанонимизации:
В MAX вшит отдельный, глубоко обфусцированный (через XOR-шифрование строк, детский сад) SDK под неймспейсом
ru.trace_flow.dps(DPS - Digital Probe System ).-
Что он делает: При каждом выходе приложения из фона он стучится на 6 внешних IP-чекеров (yandex, ifconfig.me, ipify, AWS и т.д.), чтобы узнать ваш реальный публичный IP-адрес, даже если вы сидите через сплит-туннель VPN.
-
Обход API Android: Чтобы понять, включен ли VPN, он не просто спрашивает систему, а через рефлексию перечисляет сетевые интерфейсы (tun, ppp, tap, ipsec).
-
Эксфильтрация: Ваш User ID, Device ID, Реальный IP, Флаг VPN, Оператор по симке он отправляет POST-запросом на левый домен trace-flow.ru/api/v1/report, которого нет в политике конфиденциальности и даже гугле.
Официальный C2-канал: WS-опкод DEBUG (код 2)
Сервер может прислать WebSocket-сообщение с опкодом 2 и командой cmd. Клиент молча выполняет:
-
SYNC_CONTACTS: принудительно собирает всю вашу телефонную книгу и сливает на сервер.
-
SEND_LOG: вызывает фейковый краш (IllegalStateException("onNotifDebug")). Это триггерит штатный краш-репортер (Apptracer), который собирает весь logcat устройства (до 32 МБ логов), состояние всех потоков, дампы кучи и отправляет на sdk-api.apptracer.ru.
-
Итог: Сервер может по клику мышки выкачать ваши логи и контакты.
Тихая "прослушка" звонков: collect-debug-dump
В кастомном WebRTC от VK/OK есть функция nativeSubmitDumpRequest.
Сервер через команды управления звонком может прислать JSON:{type: "collect-debug-dump", audio: true, duration: 2147483647}.-
Телефон молча начинает писать сырой звук (raw PCM) с 6 точек пайплайна (включая чистый микрофон ДО шумоподавления и чистый звук собеседника).
-
Пишет в файлы на устройстве.
-
WorkManager (SampleUploadWorker) потом так же молча заливает эти аудиофайлы на apptracer.ru. UI "Идёт запись" не появляется.
Хардкодный обход TLS для QUIC (WebTransport)
В библиотеке tech.kwik (отвечает за QUIC/WebTransport для передачи медиа в звонках) класс qse.java реализует X509TrustManager с абсолютно пустыми методами checkServerTrusted.
-
Комментарий в коде прямо гласит (выводится в консоль): "SECURITY WARNING: INSECURE configuration! Server certificate validation is disabled".
-
Это в production-сборке. Любой провайдер может подменить сертификат для медиа-трафика звонков. Пришел в кафе, сделал ARP spoofing, читаешь сообщения гоев с QUIC.
Скрытие анти-тампера под видом QR-сканера
В APK есть библиотека libqrcode.so. По названию - сканер кодов. А на деле зашит нативный код верификации подписи APK (IntegrityProtectionInit, sign_check), который генерирует криптографический seed для звонков. Звонки не будут работать, если подпись APK изменена. Они буквально спрятали защиту от реверсеров в либу с безобидным именем.

WebApp RCE: серверная инъекция JS и снятие защиты экрана
Мини-аппы в MAX работают не как песочницы:
-
Сервер может вызвать evaluateJavascript() с любым кодом внутри любой запущенной мини-апы.
-
Через JS-bridge мини-апа может вызвать WebAppSetupScreenCaptureBehavior. Это программно снимает с Android-окна флаг FLAG_SECURE.
-
После этого любое другое приложение (или сам сервер через дамп экрана) может делать скриншоты ваших переписок.
-
JS-bridge также позволяет вызвать WebAppOpenMaxLink, куда можно передать любой внутренний диплинк (например, автологин) вообще без валидации URL.
фингерпринт через Widevine DRM
Для деанонимизации (в том самом скрытом SDK) используется не только AID и MAC.
-
Приложение дергает MediaDrm Widevine UUID (edef8ba9-79d6-4ace-a3c8-27dcd51d21ed), хеширует его SHA-256 и использует как deviceId.
-
Этот идентификатор зашит в защищенную зону процессора (TEE). Он не сбрасывается при переустановке приложения, смене Google-аккаунта или даже сбросе до заводских настроек. Человека можно будет отследить навсегда.
Главное
MAX обязательно ставится на каждый новый телефон в РФ. И его домен всегда в белом списке ТСПУ. это единственный мессенджер, который останется работать. Содержащий всё вышеперечисленное.
А так же
Репозиторий - zarazaex69/m
Если есть предложения по работе или личные вопросы - t.me/owenewans
Подписывайтесь на t.me/openlibrecommunity - там обновления и новые статьи.
Говорят они подарки дарят @nogosol
почему после моей статьи хабр начал падать
джоник и кот какой то хз какой кто знает отпишите пожалуйста вижу первый раз Поддержать нас донатом ( даже 10 рублей , мне очень ХОЧЕТСЯ ЕСТЬ )
ПОДАРКИ. ТЕЛЕГРАМ: t.me/openlibrecommunity
РУБЛИ. СБП, КАРТА: pay.cloudtips.ru/p/28c476e5
КРИПТА. TON, USDT: UQD_Qc2cxLGe1P4wANi46cKdEvvzyJRrJTYPvGX2KAZDnsDh
КРИПТА, TRC 20, USDT: TYQqdACH5PrScvsMowSyS8JjaaF5wvFf5Q
КРИПТА, BTC: bc1qvw0ts0jk5e5dfj9fdez76j9ck95lqz04fpf02a
-
Автор: zarazaexe
