ZaStoGram — форк Telegram для Android с MTProxy FakeTLS, нативным WSS-транспортом, защитой приватности и обновлениями из Forgejo. https://t.me/zastogram
  • Java 59.6%
  • C++ 25.3%
  • C 10.6%
  • Kotlin 2.5%
  • Python 1.2%
  • Other 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-20 17:18:14 +03:00
.github/workflows Диагностика: включить сетевые логи MTProxy 2026-06-19 19:35:36 +03:00
buildSrc update to 12.8.0 (6913) 2026-06-16 19:04:08 +02:00
gradle/wrapper update to 12.0.0 (6163) 2025-09-01 19:12:49 +04:00
TMessagesProj добавил выбор JA4/TLS-профиля прямо в настройки прокси 2026-06-20 17:18:14 +03:00
TMessagesProj_App update to 12.7.0 (6740) 2026-05-21 14:11:54 +04:00
TMessagesProj_AppHockeyApp update to 12.7.0 (6740) 2026-05-21 14:11:54 +04:00
TMessagesProj_AppHuawei update to 12.7.0 (6740) 2026-05-21 14:11:54 +04:00
TMessagesProj_AppStandalone DRS + переписанная отправка данных откат чтобы проверить что ломает подключение 2026-06-18 18:16:43 +03:00
TMessagesProj_AppTests update to 12.8.0 (6913) 2026-06-16 19:04:08 +02:00
Tools добавил выбор JA4/TLS-профиля прямо в настройки прокси 2026-06-20 17:18:14 +03:00
.gitignore Починил именно native lifecycle для ConnectionTypeProxy, без трогания обычных MTProto/FakeTLS соединений. 2026-06-19 21:43:56 +03:00
apkdiff.py update apkdiff.py apkfrombundle.py 2023-01-26 17:06:12 +04:00
apkfrombundle.py update apkdiff.py apkfrombundle.py 2023-01-26 17:06:12 +04:00
build.gradle update to 12.0.0 (6163) 2025-09-01 19:12:49 +04:00
Dockerfile update to 12.0.0 (6163) 2025-09-01 19:12:49 +04:00
gradle.properties Improve APK build cache diagnostics 2026-06-18 20:27:11 +03:00
gradlew first commit 2013-10-25 19:19:00 +04:00
LICENSE first commit 2013-10-25 19:19:00 +04:00
README.md добавил выбор JA4/TLS-профиля прямо в настройки прокси 2026-06-20 17:18:14 +03:00
settings.gradle update to 11.14.0 (6102) 2025-08-11 13:36:23 +04:00

ZaStoGram — Telegram для Android с усиленной маскировкой MTProxy

image

Экспериментальный форк официального Telegram для Android. Цель форка — сделать подключение к MTProxy FakeTLS (ee-секрет) менее похожим на стандартный Telegram MTProxy-трафик и ближе к обычному браузерному HTTPS.

Это не новый мессенджер и не отдельный протокол. База остаётся официальным Telegram Android, а изменения сосредоточены вокруг MTProxy/FakeTLS-пути.

Простыми словами

  • MTProxy — прокси для Telegram.
  • FakeTLS — режим MTProxy, где начало соединения выглядит как TLS/HTTPS.
  • DPI / ТСПУ — оборудование провайдера, которое классифицирует и режет трафик по признакам на проводе.
  • JA4 — отпечаток TLS ClientHello. По нему можно отличить настоящий браузер от синтетического FakeTLS, если ClientHello сделан плохо.

Проблема MTProxy не только в одном хеше. DPI может смотреть на TLS-рукопожатие, временные интервалы, размеры записей, количество одновременных соединений и поведение после рукопожатия. Поэтому здесь важна аккуратная маскировка без поломки MTProto.

Что сейчас реализовано

Путь MTProxy FakeTLS от tsrman-коммита

В активном пути транспорта сохранено поведение, близкое к рабочему tsrman/tg-варианту:

  • ClientHello держится в отдельном буфере до полной отправки: если send() отправил только часть данных, остаток досылается на следующем EPOLLOUT;
  • фаза данных использует стабильное фиксированное ограничение 2878 байт;
  • рискованные эксперименты с динамическим размером TLS-записей сейчас убраны из активного пути.

Это важно для надёжности: сначала соединение должно стабильно работать, и только потом можно снова усиливать маскировку фазы данных.

Стабильный выбор TLS-профиля

Для MTProxy FakeTLS выбранный TLS-профиль теперь не меняется хаотично на каждое соединение. Профиль выбирается стабильно по адресу прокси, секрету и локальной соли.

В автоматическом пуле сейчас только Android-семейства:

  • Android Chrome;
  • Firefox Android;
  • Android OkHttp.

Так разные установки и разные прокси могут получать разные сетевые отпечатки, но один конкретный адрес прокси не прыгает между профилями каждую секунду. Desktop Firefox и Yandex оставлены в коде как заготовки для ручных тестов, но в авто-выбор временно не входят, пока мы добиваемся стабильного подключения.

В настройках списка прокси добавлен выбор JA4 / TLS-профиль.

  • Auto — режим по умолчанию. Клиент сам выбирает стабильный профиль для конкретного адрес:порт:секрет;
  • Chrome, Ffox A, OkHttp, Firefox, Yandex — ручной режим для тестов. В этом режиме один выбранный профиль принудительно используется для всех FakeTLS-прокси, а служебная проверка прокси использует тот же профиль.

Это нужно, чтобы на одном APK быстро сравнивать, какой отпечаток лучше проходит у конкретного провайдера или набора прокси, не пересобирая приложение.

Защитные проверки ClientHello

Перед отправкой ClientHello проверяется на базовую совместимость с MTProxy:

  • корректная TLS-запись и длины;
  • ожидаемое смещение списка наборов шифров;
  • первый шифр не из GREASE относится к TLS 1.3 TLS_AES_*;
  • наличие SNI-домена из ee-секрета;
  • размер в пределах серверного лимита.

Это защищает от красивого, но несовместимого ClientHello.

Рандомизация внутри ClientHello

Оставлены низкорисковые элементы маскировки:

  • случайные поля ClientHello;
  • случайные ECH-данные там, где профиль их использует;
  • случайная цель расширения заполнения вместо старого фиксированного размера;
  • безопасная генерация GREASE-значений без выхода за границы массива.

Управляемая мягкая фрагментация ClientHello

В настройках списка прокси добавлен переключатель Мягкая фрагментация ClientHello. Он действует только на MTProxy FakeTLS (ee-секреты).

Когда режим включён, уже собранный и проверенный ClientHello отправляется не одним логическим залпом, а двумя небольшими TCP-отправками с коротким неблокирующим интервалом. TLS-структура, SNI, HMAC и MTProto-трафик после подключения не меняются.

Режим нужен для A/B-тестов против DPI: можно собрать один APK и сравнивать прокси с фрагментацией и без неё прямо из GUI, не откатывая код. По умолчанию режим выключен, чтобы рабочий транспорт оставался максимально близким к стабильному пути.

Планировщик MTProxy-подключений

Для ee FakeTLS добавлен контроллер допуска подключений к одному адресу прокси. Он ограничивает не скорость уже установленного MTProto-трафика, а только залп одинаковых попыток connect -> ClientHello -> server_hello_hmac_ok к одному адресу прокси.

Ключ планировщика: адрес прокси:порт:SNI.

В текущей диагностической сборке активная очередь рукопожатий временно выключена флагом MT_PROXY_HANDSHAKE_ADMISSION_ENABLED = false: настоящий connect() снова запускается сразу, как в базовом транспортном пути. Это нужно, чтобы отделить баги нашего admission-controller от внешнего freeze/блокировки прокси.

Код планировщика оставлен для следующего этапа. Когда он включён, его задача:

  • держать максимум одно активное FakeTLS-рукопожатие на адрес прокси;
  • после недавних успешных server_hello_hmac_ok поднимать лимит до двух;
  • ставить новые рукопожатия в очередь по приоритету: Generic/Temp -> GenericMedia -> Push -> Download -> Upload;
  • не пропускать служебную проверку прокси через жёсткую очередь, чтобы не получать ложный результат "прокси не работает" из-за ожидания слота;
  • освобождать слот сразу после server_hello_hmac_ok, чтобы загрузка и отправка файлов после подключения шли параллельно как раньше.

Зависания в фазе client_hello_sent сейчас только логируются; штрафной cooldown тоже временно выключен, чтобы клиент сам не переводил живые прокси в долгое состояние "недоступен" во время диагностики блокировок.

Это сделано против узнаваемого залпового шаблона, когда клиент почти одновременно открывает много одинаковых FakeTLS-соединений к одному прокси. Жёсткий режим типа "один SYN в секунду" не используется: он слишком грубо замедляет Telegram и сам может стать странной сигнатурой.

Диагностика запуска подключения

Добавлены диагностические точки для MTProxy-подключения:

  • connect_start;
  • socket_connected;
  • client_hello_sent;
  • server_hello_hmac_ok;
  • server_hello_hmac_timeout, если ServerHello структурно получен, но HMAC не совпал за короткое диагностическое окно;
  • on_connected;
  • first_tls_app_sent, когда первый MTProto-пакет ушёл внутри TLS ApplicationData;
  • first_tls_app_recv, когда от сервера пришла первая полезная TLS ApplicationData;
  • mtproxy_disconnect с причиной, состоянием и флагами первой MTProto-активности внутри TLS (first_tls_sent, first_tls_recv);
  • admission_grant, admission_queue, admission_release, admission_disabled, admission_freeze_detected, admission_freeze_observed.

Это нужно, чтобы отличать DPI-обрыв от багов в нашем транспортном пути.

Архитектура проверки прокси

Проверка прокси разделена на три слоя, чтобы GUI не запускал лишние соединения и не спорил с native-состоянием:

  • ProxyCheckScheduler в Java принимает ручные проверки из bottom sheet, фоновые проверки из списка прокси и проверки ротации. Он держит один активный check, склеивает одинаковые endpoint'ы, хранит владельцев проверки и отменяет active check через cancelProxyCheck().
  • Native-слой ConnectionsManager завершает проверку через единый finishProxyCheck: успех по TL_pong, сетевой обрыв, timeout, start-fail и явная отмена проходят через одну точку очистки request/token/socket.
  • Tools/analyze_mtproxy_markers.py сводит Java scheduler, native proxy-check, rotation и FakeTLS-маркеры в один отчёт. Важный verdict: connected_without_socket_connected_marker означает, что лог дошёл до on_connected, но в этом срезе нет маркера socket_connected; такой случай нельзя считать TCP-недоступностью.

В отчёте есть два разных среза:

  • FakeTLS endpoint phases — фазы настоящего FakeTLS-подключения по адресу прокси: TCP/connect, отправка ClientHello, проверка ServerHello/HMAC, первая MTProto ApplicationData и поздний disconnect;
  • Plain MTProxy lifecycle — обычные dd/legacy MTProxy-секреты отдельно от FakeTLS. Этот срез группируется по endpoint, аккаунту, DC и типу соединения, чтобы отличать "проверка прокси доступна" от ситуации, где, например, Generic получает RPC-ответы, а Download много отправляет и почти ничего не получает;
  • Native endpoint outcomes — результат служебной проверки прокси. Значение fail:tcp_not_connected относится к TCP/connect-слою, а fail:tcp_connected_no_pong означает, что TCP открылся, но MTProxy ping не завершился.

Tools/collect_mtproxy_logs.ps1 строит основной mtproxy_markers.txt только по текущему logcat.txt. Сырые device logs всё ещё подтягиваются в папку сессии, но не смешиваются с live-статистикой, чтобы старые файлы не портили выводы.

Единая карта ошибок прокси

Статус прокси теперь передаётся не числовыми кодами, а строковой фазой. Один и тот же словарь используется в native-логе, Java scheduler, GUI и анализаторе:

  • tcp_not_connected — TCP-соединение не открылось;
  • tcp_connected_no_pong — TCP открылся, но MTProxy ping не завершился;
  • client_hello_sent_no_server_hello — ClientHello отправлен, валидный ServerHello не пришёл;
  • server_hello_hmac_mismatch — ServerHello пришёл, но не прошёл HMAC-проверку MTProxy;
  • post_handshake_no_appdata — рукопожатие прошло, но первые MTProto-данные не пришли;
  • dropped_after_appdata — соединение поднялось и отвалилось уже после первых MTProto-данных.

Единый источник GUI-текстов — ProxyCheckDiagnostics. Поэтому список прокси, bottom sheet проверки и логи используют одинаковые имена фаз. Это нужно, чтобы по экрану и по logcat было видно, где именно умирает прокси и похоже ли это на недоступный сервер, несовместимость транспорта или фильтрацию пути.

Корректная досылка неполной TLS-записи

Стартовый FakeTLS ClientHello отправляется через отдельный ожидающий буфер: если неблокирующий send() принял только часть hello, остаток досылается на следующем EPOLLOUT, а состояние client_hello_sent логируется только после полной отправки.

Если peer закрыл TCP-соединение (recv() == 0), сокет закрывается сразу с меткой recv_eof, а не ждёт общего таймаута подключения.

Если после полной отправки ClientHello нет корректного server_hello_hmac_ok за время freeze-таймера, попытка закрывается с меткой server_hello_timeout_close, чтобы не держать мёртвое рукопожатие до общего таймаута.

Проверка HMAC для ServerHello теперь привязана к границам TLS-записей, а не к случайному размеру одного recv(). Это сохраняет совместимость с официальным MTProxy, где ответ состоит из ServerHello + ChangeCipherSpec + ApplicationData, и не ломается на telemt-подобных ответах с дополнительными профилированными ApplicationData-записями в серверном handshake flight.

После установленного FakeTLS-соединения reader принимает только полезные ApplicationData-записи MTProto, но корректно пропускает служебный ChangeCipherSpec, не отдаёт пустые TLS-записи в MTProto-парсер и закрывает соединение с отдельной меткой tls_alert, если peer прислал TLS Alert.

Для обёрнутых TLS-записей добавлена очередь ожидающей отправки записи: если send() отправил только часть TLS-записи, остаток досылается как продолжение той же записи, а полезная нагрузка MTProto не выбрасывается раньше полной отправки. Успешная досылка обновляет таймер активности соединения, чтобы активная отправка не считалась простым бездействием.

Сборка

Готового APK здесь намеренно нет. Собирай приложение из исходников.

  1. Получи api_id и api_hash на my.telegram.org.
  2. Укажи свои значения в проекте Telegram Android.
  3. Подставь свой ключ подписи релизной сборки.
  4. Собери через Android Studio или GitHub Actions.

GitHub Actions настроен на ccache с CCACHE_COMPILERCHECK=content, чтобы повторные сборки нативного кода были заметно быстрее после прогрева кэша.

На время диагностики MTProxy GitHub Actions включает сетевые логи Telegram прямо в обычном артефакте ZaStoGram-standalone-afat. После установки такого APK можно собрать маркеры:

D:\bin\platform-tools\adb.exe devices -l

Из WSL:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$(wslpath -w Tools/collect_mtproxy_logs.ps1)" -Adb "D:\bin\platform-tools\adb.exe" -Package org.zastogram.messenger -Seconds 180

Во время записи надо открыть приложение и повторить подключение к MTProxy. Главный файл для разбора: mtproxy_markers.txt. Скрипт также создаёт mtproxy_analysis.txt: он группирует попытки по ConnectionSocket и показывает, где остановилось подключение: TCP/connect, отправка ClientHello, проверка server_hello_hmac_ok, переход в on_connected или первые TLS ApplicationData-записи MTProto.

Для сравнения профилей и endpoint'ов рядом создаются CSV:

  • mtproxy_attempts.csv — каждая FakeTLS-попытка: endpoint, профиль, фаза отказа, задержка до HMAC, close/error и набор увиденных маркеров;
  • mtproxy_endpoint_profile_stats.csv — агрегат по endpoint + profile: количество попыток, процент успеха, топ отказов, медиана HMAC и максимальный burst рукопожатий за 1 и 5 секунд.

Именно эти файлы нужны, чтобы отделить нашу ошибку транспорта от внешней блокировки или нестабильного прокси. Перед публичным релизом это нужно выключить обратно, чтобы не оставлять подробные сетевые логи в обычной сборке.

Как пользоваться

  1. Подними MTProxy с FakeTLS вне зоны блокировки.
  2. Используй ee-секрет с доменом.
  3. В приложении добавь MTProto-прокси обычным способом: Настройки -> Данные и память -> Прокси -> Добавить прокси -> MTProto.

Маскировка из этого форка применяется именно к FakeTLS/ee-секрету. Для обычных dd-секретов и других вариантов без FakeTLS эти изменения не дают того же эффекта.

Честные ограничения

  • SNI не ротируется сам по себе. Он берётся из ee-секрета.
  • Фаза данных пока не имитирует настоящий HTTP/2 или HTTP/1.1.
  • Динамический размер TLS-записей сейчас не включён в активный путь.
  • Планировщик ограничивает только фазу открытия FakeTLS-соединения. Он не пытается полностью замаскировать статистику уже установленного MTProto-трафика.
  • Это не гарантия вечного обхода блокировок: DPI-правила меняются.
  • Это неофициальный форк, использовать его нужно с пониманием рисков.

Потом реализуем

  • Вернуть DRS аккуратно: случайные размеры TLS-записей, фазовая модель, защита от повторяющихся шаблонов и сброс состояния после простоя, но только после проверки досылки неполных записей и пути передачи данных на реальном MTProxy.
  • IPT: неблокирующая имитация межпакетных интервалов с разделением на рукопожатие, поддержание соединения, интерактивный трафик и передачу файлов.
  • Больше стабильных браузерных профилей из telemt/tdlib-obf: Android Brave, дополнительные Chrome/Firefox/Yandex-варианты, Windows/iOS профили, но только через защитные тесты совместимости с MTProxy.
  • Ручное переопределение профиля для отладки без публичного интерфейса, чтобы быстро сравнивать профили при тестах.
  • Политика ECH с учётом маршрута и автоматическим отключением неудачного варианта, чтобы не долбить сеть ECH-профилем, если конкретный маршрут его режет.
  • Управляемая политика отправки ClientHello: мягкая фрагментация только фазы рукопожатия, маленький jitter между кусками, подробные логи размера кусков и быстрый флаг отката. Сейчас это не включено в стабильный путь.
  • Ограничение MSS как отдельный эксперимент после проверки фрагментации ClientHello: оно меняет TCP-поведение ниже уровня FakeTLS и поэтому требует отдельного сравнения с VPN/без VPN.
  • Маскировка прикладного уровня: обрамление HTTP/2 или HTTP/1.1 поверх TLS-подобного транспорта. Это самый глубокий и самый рискованный слой, его нельзя делать косметически.
  • Заполняющий трафик во время простоя и маскировка жизненного цикла соединений, если они не будут ломать MTProto и батарею на Android.

Основа и благодарности

  • DrKLO/Telegram — официальный Telegram Android.
  • tsrman/tg — рабочая база изменений FakeTLS, JA4 и временных интервалов.
  • telemt/tdlib-obf — идеи и референсы по профилям маскировки, DRS/IPT и реестру профилей.