# 🦎 tdlib-obf — клиентский TDLib с маскировкой TLS-почерка под браузер > [!info] О чём заметка > `tdlib-obf` — форк **TDLib** (официальной библиотеки для написания Telegram-клиентов) от сообщества **telemt**, который маскирует MTProto-трафик под обычный браузерный HTTPS, чтобы обходить государственный DPI (Deep Packet Inspection — глубокая инспекция пакетов; в РФ — оборудование ТСПУ, Технические Средства Противодействия Угрозам). Главное: это **клиентская** реализация — она меняет TLS-почерк (JA4) именно там, где это вообще возможно, внутри самого клиента. Тем самым `tdlib-obf` — это «полноценный» ответ на тезис из [[mtproxy/ja4-sni-client-side|разбора, почему обход MTProxy клиентский]]: чистый слом JA4 серверный прокси сделать не может, а форк клиента — может. > [!warning] Статус данных > Технические детали ниже взяты в основном из **собственного аудит-документа проекта** (`docs/Documentation/STEALTH_IMPLEMENTATION_RU.md`, состояние на апрель–май 2026) — это самоотчёт авторов, **не независимая проверка**. Читай заявленные свойства маскировки как «по документации проекта», а не как подтверждённый внешним аудитом факт. Базовый коммит форка и ветка проверены напрямую по git (июнь 2026) и помечены отдельно. --- ## TL;DR 1. `tdlib-obf` — это **TDLib с обфускацией**: тот же API, но при сборке с флагом `TDLIB_STEALTH_SHAPING=ON` клиент строит TLS-рукопожатие, неотличимое (по замыслу) от реального браузера. 2. Маскировка решает ровно тот рычаг, который [[mtproxy/ja4-sni-client-side|можно дёргать только на клиенте]] — **JA4-почерк ClientHello**: вместо одного протухшего пресета Telegram используется реестр из 8 рантайм-профилей реальных браузеров (по аудит-доку — Chrome 120/131/133, Firefox 148/149, Safari, iOS, Android; в коде заведены и новые lanes), выбираемых на лету. 3. Заодно адресуется беда [[Zapret/mtproto/10-telemt-logs-dpi|#30733 (протухший отпечаток)]]: используемые Chrome-профили несут **post-quantum** `key_share` (ML-KEM), которого не было в старом почерке Telegram. 4. Работает **только через MTProto-прокси с FakeTLS** (`ProxySecret::emulate_tls()`). Прямые соединения не маскируются (а часть leak-путей прямого TCP-SYN в обход прокси форк, по документации, дополнительно закрыл). 5. Честное ограничение от самих авторов: после TLS идёт **сырой MTProto, а не настоящий HTTP** — полной неотличимости на уровне L7 проект не обещает. 6. Это **библиотека, а не готовый клиент**: своё приложение пишешь поверх неё (проще всего — консольный клиент на `libtdjson`). --- ## Термины (чтобы заметка читалась без контекста) - **TDLib** (Telegram Database Library) — официальная библиотека от Telegram для написания клиентов. Сама по себе не приложение, а движок: берёт на себя протокол, шифрование, базу сообщений. Готовые клиенты (Unigram, Telegram X) построены поверх неё. - **libtdjson** — собранная динамическая библиотека TDLib с JSON-интерфейсом, к которой подключаются из любого языка (Python, C++, и т.д.). - **MTProto** — собственный транспортный протокол Telegram (шифрование + формат пакетов), поверх которого работает мессенджер. - **DPI / ТСПУ** — DPI (Deep Packet Inspection) — глубокая инспекция пакетов; ТСПУ (Технические Средства Противодействия Угрозам) — это DPI-оборудование, установленное у российских операторов. - **L7** — седьмой (прикладной) уровень модели OSI: грамматика самого протокола поверх TLS (HTTP/2, HTTP/1.1). «L7-неотличимость» — когда трафик неотличим от браузерного и на этом уровне, а не только в TLS-рукопожатии. - **ClientHello / JA4 / SNI / FakeTLS** — раскрыты в [[mtproxy/ja4-sni-client-side|заметке про клиентскую сторону JA4/SNI]]. Кратко: ClientHello — первый незашифрованный пакет TLS, который шлёт клиент; JA4 — его отпечаток; FakeTLS — режим MTProxy, где трафик маскируется под HTTPS. - **ECH** (Encrypted ClientHello) — расширение TLS, прячущее SNI внутри зашифрованной части рукопожатия. - **DRS / IPT** — внутренние подсистемы формирования трафика (traffic shaping): Dynamic Record Sizing (динамический размер TLS-записей) и Inter-Packet Timing (имитация тайминга пакетов). --- ## Зачем это нужно: рычаг, который есть только у клиента > [!example] На пальцах > Представь, что у входа стоит охранник (ТСПУ) и узнаёт «гостей Telegram» по **визитке** (JA4-почерк ClientHello). У официального клиента визитка одна и та же, к тому же устаревшего образца — охранник выучил её наизусть. Сервер-прокси переклеить визитку не может: гость показывает её **до** того, как дойдёт до сервера. А `tdlib-obf` — это сам гость, который печатает себе **свежую визитку под видом обычного браузера** перед каждым выходом. Архитектурный факт, разобранный в [[mtproxy/ja4-sni-client-side|отдельной заметке]]: JA4 и SNI лежат в ClientHello, а его шлёт **клиент**, и цензор видит этот пакет ещё до сервера. Поэтому чистый слом почерка возможен только до цензора — на стороне клиента. До сих пор это воплощалось как отдельный локальный relay (тестовый [gist Flowseal](https://gist.github.com/Flowseal/de630dd9d9ddaa86cc6bed9b473fae0c), который строит свой ClientHello). `tdlib-obf` идёт дальше: переносит ту же логику **внутрь самого клиента-движка**, без прослойки-relay. --- ## Как работает маскировка (4 слоя) По документации проекта, stealth-контур включает четыре одновременно работающих слоя: | Слой | Что делает | |---|---| | **Profile-driven ClientHello** | Реестр профилей реальных браузеров (по аудит-доку — Chrome 120/131/133, Firefox 148/149 вкл. macOS, Safari 26.3, iOS, Android; в коде есть и новые lanes — Chrome 147, Firefox 149 Windows/Android). Выбор «липкий» (sticky) — зависит от назначения, временного окна и платформы, чтобы не дёргать TLS-семейство на каждом соединении. Профили `verified` построены на реальных перехватах трафика, `advisory` — консервативные. | | **Route-aware ECH** | Политика ECH зависит от маршрута: на RU/неизвестных маршрутах ECH **выключен**, на не-RU — включается с «предохранителем» (circuit breaker), который отрубает ECH для направления после нескольких ошибок. | | **Transport shaping** | Имитация тайминга пакетов (IPT, не просто `sleep(random)`, а burst/idle-модель), динамический размер TLS-записей (DRS: slow-start → congestion-open → steady-state), классификация типа трафика (handshake / keepalive / bulk / interactive). | | **Capture-driven верификация** | Сотни нативных тестов + «корпус» реальных перехватов, сверка отпечатков JA3/JA4 с эталонами, статистические прогоны на 1024 сидах — чтобы маскировка не «схлопывалась» в узнаваемый паттерн. | > [!important] Это адресует «протухший почерк» #30733 > Беда официального клиента из [[Zapret/mtproto/10-telemt-logs-dpi|#30733]] не в номере версии (он как раз представляется свежим Chrome 134/macOS), а в том, что его отпечаток идёт **без** post-quantum `key_share`, тогда как реальные Chrome 131+ его уже несут. К концу 2025 уже около половины «человеческих» TLS несут `X25519MLKEM768` (по данным Cloudflare — ~43% к сентябрю и более 50% к декабрю 2025). По документации `tdlib-obf` синхронизирует PQ-группу между `supported_groups` и `key_share` в Chrome-профилях — то есть отпечаток выходит пост-квантовым, чего старому почерку Telegram не хватало. > [!note] Что закрывает, а что нет > `tdlib-obf` бьёт по рычагу **JA4/почерк** (и его свежесть). Условие «один и тот же SNI в залпе» из [[mtproxy/ja4-sni-client-side|детекта июня 2026]] — отдельная история: SNI в FakeTLS задаётся `ee`-секретом прокси (`tls_domain`), а не выводится из него, так что его ротация — вопрос того, к каким секретам/доменам подключается клиент, а не самого слоя маскировки. Третье условие — «залп на один ip:port» — частично снимается серверными мерами (pacing, разные порты), см. [[Zapret/mtproto/10-telemt-logs-dpi|разбор логов]]. --- ## Как использовать > [!tip] Главное правило сборки > Маскировка включается **только** при сборке с `-DTDLIB_STEALTH_SHAPING=ON` и **только** в режиме FakeTLS-прокси (`ProxySecret::emulate_tls()`). Жёсткий контракт: если использовать `emulate_tls()`, но собрать с `TDLIB_STEALTH_SHAPING=OFF`, процесс **аварийно падает** (`LOG(FATAL)`), а не работает молча без маскировки — «забыть включить» нельзя. `tdlib-obf` — это библиотека, поэтому «свой клиент» = твоё приложение поверх её API. Практичный путь без написания C++: - [ ] Получить `api_id`/`api_hash` на [my.telegram.org](https://my.telegram.org). - [ ] Собрать `libtdjson` из исходников с флагом `TDLIB_STEALTH_SHAPING=ON` (нужен компилятор **C++23**, OpenSSL, zlib ≥ 1.3.2, gperf, CMake — это единственная C++-часть). - [ ] Взять готовый терминальный клиент на TDLib (например `tg` от paul-nameless) и указать ему путь к своей `libtdjson` через `library_path` — получаешь рабочий клиент в терминале без своего кода. - [ ] Подключаться через **MTProto-прокси с FakeTLS-секретом** (`ee…`) — без него маскировки нет. Свой прокси можно поднять на [[mtproxy/mtproto-zig|mtproto.zig]] / telemt / mtg вне зоны блокировки. > [!warning] Готовый десктоп-GUI «в лоб» не подойдёт > Telegram Desktop и его форки (Kotatogram, Materialgram) **не используют TDLib** — у них свой MTProto-движок, подменить его на `tdlib-obf` нельзя. Из десктоп-GUI на TDLib есть **Unigram** (Windows), но его `develop` закреплён на более свежем коммите TDLib, чем база форка, и схема API (`td_api.tl`) за это время разошлась (на июнь 2026 — порядка 260 строк diff; точное число зависит от того, на какой коммит TDLib закреплён Unigram) — пересобрать Unigram с обфускацией можно только пересадив изменения форка на нужный коммит и разрулив конфликты. Поэтому самый дешёвый путь к рабочему клиенту — консольный/TUI на `libtdjson`. --- ## Честные ограничения Авторы прямо перечисляют их в документации — это плюс к прозрачности (но прозрачность не заменяет независимую проверку): > [!quote] Из документации проекта (раздел «Честные ограничения») > После TLS-рукопожатия идёт **сырой MTProto, а не браузероподобный HTTP**. Полная L7-неотличимость **не заявляется** — на уровне глубокой L7-аналитики (настоящий HTTP/2-фрейминг, грамматика HTTP/1.1) трафик всё ещё может выделяться. Runtime-реестр профилей консервативнее эмпирического корпуса, а генерация ServerHello зависит от серверной стороны. Дополнительно: - **QUIC/HTTP3 запрещены** — транспорт всегда TCP+TLS (`allow_quic=true` считается ошибкой конфигурации). - Это **community-форк**, не официальный Telegram (лицензия MIT поверх Boost-лицензии TDLib). --- ## Версия и происхождение (проверено по git, июнь 2026) - Дефолтная ветка репозитория — **`master`** (не `main`). - Форк отделился от upstream TDLib на коммите `8fc2344f` (**25 апреля 2026**). Сам форк схему `td_api.tl` тоже правит (+91/−13 строк относительно базы) — это важно учитывать при попытке подружить его с готовым клиентом, заточенным под другую версию TDLib. - Мейнтейнеры — сообщество telemt (то же, что и [[Zapret/mtproto/00-overview|MTProto-прокси telemt]]). --- ## 📚 См. также - [[mtproxy/ja4-sni-client-side|Почему обход MTProxy клиентский (JA4/SNI)]] — архитектурный тезис, ответом на который и является tdlib-obf - [[mtproxy/tsrman-tg-android-faketls|tsrman/tg — Telegram для Android со сменой JA4]] — родственный клиентский подход, но в виде готового приложения (форк Telegram-Android), а не библиотеки - [[Zapret/mtproto/10-telemt-logs-dpi|Чтение логов telemt и #30733]] — протухший JA4-почерк официального клиента, который tdlib-obf лечит PQ-профилями - [[mtproxy/mtproto-zig|MTProxy и mtproto.zig]] — серверная сторона FakeTLS-прокси, к которой подключается клиент - [[Zapret/mtproto/00-overview|MTProto Proxy — полный гайд]] — общий обзор экосистемы telemt - [[VLESS/dpi-tls-june-2026|Сибирская схема: подсеть + фингерпринт + частота]] — та же логика «И трёх условий» и про свежесть почерка/ML-KEM - 🔗 [tdlib-obf на GitHub](https://github.com/telemt/tdlib-obf) — исходники и документация (ветка `master`) - 🔗 [tdesktop#30733](https://github.com/telegramdesktop/tdesktop/issues/30733) — протухший фингерпринт официального клиента