Integrate Xray 26.9.9 with the sing-box system tunnel and verify Windows routes during health checks. Improve endpoint selection, network recovery, subscription refresh deadlines, diagnostics, packaging, and regression coverage.
18 KiB
Happ 4.5.4: статическое исследование Windows-клиента, 24 октября 2026
Исследована копия C:\Program Files\FlyFrogLLC\Happ\Happ.exe в C:\Tools\QVPN-private\happ-review-20261024\Happ.exe. SHA-256 оригинала и копии совпал: 010A05548865A85DF250337E0C14CC137248B96C9A2446E4F2EFEAEB4455176A. Размер — 21 260 712 байт. PE x64, ImageBase 0x140000000; таблица COFF-символов отсутствует. Использованы PE-импорты Qt, встроенные строки, шаблоны JSON, unwind-границы функций и дизассемблирование. Настройки пользователя, базы, текущие журналы и секреты здесь не читались. Приложения, службы и сетевые настройки не изменялись.
Видно означает наличие данных или соответствующей ветви машинного кода. Вывод означает интерпретацию этих данных. Статическое исследование не подтверждает выполнение ветви в текущем соединении. Имена C++ ниже восстановлены из встроенных диагностических строк, а не из отладочных символов.
Собственный TUN Xray
Видно: встроенное имя coreConfigs::TConfigBuilder::injectXrayTunInbound находится по файловому смещению 0x46c210, VA 0x14046d010. Соответствующая функция ограничена unwind-таблицей: VA 0x1400ba700–0x1400bdad8. Это отдельный генератор native TUN Xray, наряду с поддержкой сторонних TUN-процессов.
| Параметр/ветвь | Доказательство |
|---|---|
tag=tun-in, protocol=tun |
строки: файл 0x46c114, 0x45b2cc; присваивание protocol: VA 0x1400bb56f–0x1400bb5b0 |
Default нового TUN: mtu=1500 |
VA 0x1400bb0d5: mov edx,0x5dc, затем QJsonValue(int); ключ mtu: файл 0x46c13c |
userLevel=8 |
VA 0x1400bb132–0x1400bb171 |
desc=Happ |
строки Happ: файл 0x458198, desc: 0x46c140; присваивание VA 0x1400bb18f–0x1400bb1d0 |
IPv4 gateway 172.19.0.1/30 |
строка: файл 0x46c120; создание массива VA 0x1400ba7c8–0x1400ba7f8 |
DNS виртуального интерфейса 172.19.0.2 |
строка: файл 0x46c150; массив DNS и присваивание VA 0x1400bb24d–0x1400bb2c1 |
IPv4 default route 0.0.0.0/0 |
строка: файл 0x46c160; массив autoSystemRoutingTable: VA 0x1400bb30b–0x1400bb3c8 |
| IPv6 gateway и default route добавляются условно | fdfe:dcba:9877::1/126: файл 0x46bd90; ::/0: файл 0x46c16c; ветви VA 0x1400ba81a–0x1400ba844, 0x1400bb357–0x1400bb384 |
При наличии sniffing у SOCKS он копируется для TUN и получает routeOnly=true |
чтение sniffing: VA 0x1400ba9ec–0x1400baadc; bool true и ключ routeOnly: VA 0x1400bab4c–0x1400bab5b, ключ: файл 0x46c130 |
DNS-трафик отправляется в dns-out |
конструкция routing rule с port 53, network tcp,udp, outboundTag dns-out: VA 0x1400bc330–0x1400bc41b; строки: файл 0x46c0e8, 0x46c2e8 |
Видно: IPv6 по умолчанию выключен в этом генераторе. Фабрика XrayTunOptions VA 0x1400cfbe0–0x1400cfe2e вызывает getter VA 0x140153860; затем сравнивает результат с 1 и сохраняет boolean в нулевой байт options (0x1400cfc43–0x1400cfc51). Getter читает ключ Preferences/TunnelSettings/preferredIPType (файл 0x4baae0, VA 0x1404bb8e0) с default QVariant(int 0) (VA 0x140153883–0x1401538ce). Вторая возможность включить IPv6: одна из строк списка Preferences/AdvancedSettings/excludedRoutes содержит :. Ключ списка находится по файлу 0x4bb078, VA 0x1404bbe78; getter VA 0x14014fc90; проверка QString::contains(':') — VA 0x1401c60e0–0x1401c60eb, обход списка — VA 0x1400ba78b–0x1400ba7bf.
Текущее значение preferredIPType пользователя этим исследованием не установлено. Нельзя переносить статический default на активное соединение. Отличие от безусловного dual-stack TUN требует отдельного сопоставления активных настроек. Разница MTU с конфигурацией QVPN 1500 не обнаружена.
Выбор физического адаптера
Видно: при создании native TUN вызывается helper VA 0x1401d4570 (вызов 0x1400bb44a). Его строки сообщают о поиске интерфейса default route; он использует GetAdaptersAddresses для получения имени адаптера. Непустое имя присваивается autoOutboundsInterface; при неуспехе остаётся значение auto и выдаётся предупреждение (строка: файл 0x46c1a0; ветвь VA 0x1400bb43c–0x1400bb546; ключ: файл 0x46c2a8).
Вывод: генератор не выбирает просто первый перечисленный адаптер. Это не доказывает автоматическое переключение на другой физический адаптер после запуска: native TUN получает конкретное имя, когда resolver успешен. Алгоритм повторной генерации при смене сети здесь не исследован.
DNS: шаблоны, а не доказательство активной политики
| Шаблон в Happ.exe | Статически видимое содержимое |
|---|---|
файл 0x4682a0, VA 0x1404690a0 |
DNS hosts и queryStrategy параметризованы; servers содержит один https://1.1.1.1/dns-query |
файл 0x468320, VA 0x140469120 |
другой шаблон: UDP DNS 1.1.1.1 и 8.8.8.8, port 53; подмена domain:googleapis.cn на googleapis.com |
файл 0x468470 |
несколько параметризованных DNS-серверов и domain-scoped правила |
файлы 0x4685a0, 0x4686e0 |
варианты параметризованных серверов, domain-scoped правил и port/дополнительных параметров |
файл 0x468800 |
FakeDNS pool 198.18.0.0/15, poolSize 10000 |
Вывод: Happ поддерживает разные DNS-режимы. Утверждение, что именно резервный DNS обеспечивает работоспособность активного Happ, этими шаблонами не подтверждено. В одном из штатных шаблонов upstream единственный, как и в прежней конфигурации QVPN. Точный выбор шаблона и активные значения требуют отдельной runtime-проверки.
Mux, UDP443 и Reality
| Шаблон/поле | Доказательство и граница вывода |
|---|---|
| Mux выключен | файл 0x468880, VA 0x140469680: enabled false, concurrency -1, xudpConcurrency 8, xudpProxyUDP443 пустая строка |
| Mux включён и настраивается | файл 0x4688f0, VA 0x1404696f0: enabled true, остальные три поля параметризованы |
| Поля GUI/настроек | useMuxing, muxingTcpConcurrency, muxingXudpConcurrency, muxingHandleQUICMode: файл 0x444ce8–0x444d1d |
| TCP Reality | файл 0x469240, VA 0x14046a040: network tcp, header.type none; параметры fingerprint, publicKey, serverName, shortId, show, spiderX и security |
| Другие Reality-транспорты | gRPC Reality: файл 0x469810; остальные шаблоны не устанавливают выбор активного узла |
Видно: настройки Mux/QUIC конфигурируемы. Не установлено: активный UDP443 policy, включение Mux в рабочей сессии, автоматическое изменение flow. Нельзя объяснять превосходство Happ «включённым Mux» по наличию шаблона. Синтаксические варианты network tcp/raw и Reality publicKey/password сами по себе не доказывают разницу поведения совместимого ядра.
Разрешение доменного адреса сервера
Встроенные диагностические строки показывают отдельный TServerAddressResolver: параллельные DoH A/AAAA (файл 0x463400), проверку нескольких IP через временные VPN-ядра и proxy ping (файлы 0x463930, 0x463988, 0x463a40), принятие первого рабочего ответа (0x463780) и возврат к исходному домену, если IP не ответили (0x463868). Это сильное свидетельство возможностей соответствующего компонента; его полный алгоритм не восстановлен. Применимость к текущим локациям с IP literal не подтверждена.
Практический результат для QVPN
Статически подтверждены другой путь TUN (собственный Xray), условное IPv6, выбор default-route адаптера, маршрутизация DNS через отдельный outbound и сохранение исходной цели при sniffing. Не подтверждены активная DNS-резервируемость, включённый Mux, специальные значения UDP443 или фрагментация как причины работоспособности Happ. Замена всего TUN требует отдельной проверки очистки Windows-маршрутов, DNS, geo/routing и аварийного завершения; одно наличие генератора не доказывает безопасную взаимозаменяемость.
Воспроизводимые локальные материалы: pe-inventory.txt, shipped-strings.jsonl, configuration-strings.json, disassembly.txt, disassembly-annotated.txt, inject-xray-tun.dis.txt, xray-tun-options.dis.txt, default-route-adapter.dis.txt и скрипты извлечения в каталоге копии. Никакие ресурсы или закрытый программный код Happ в исходники QVPN не переносились.
Отдельная служба Windows
Исследована также копия happd.exe: SHA-256 BDF6857524C1DB459282C3C96CD9C77C0AF78DA557B793F1D739452559748D20, размер 3 699 624 байта. Видно: PE импортирует Windows IP Helper (GetIpForwardTable2, CreateIpForwardEntry2, DeleteIpForwardEntry2, SetIpInterfaceEntry) и WFP (FwpmEngineOpen0, FwpmFilterAdd0, FwpmFilterGetById0, FwpmFilterDeleteById0). Сами импорты не доказывают активность конкретного фильтра.
Встроенные сообщения по файловым смещениям 0x244A00, 0x247550, 0x247B70, 0x24D668, 0x24D822 описывают обнаружение потерянного после сна адаптера, установку DNS, 15-секундный допуск heartbeat после пробуждения, разрешающие фильтры интерфейса и проверку сохранности WFP-фильтров. Вывод: управление соединением Happ включает отдельную политику Windows, а общий Xray и одинаковый ключ не определяют поведение всей системы. Эти строки не являются измерением работоспособности каждого пути в текущем сеансе.
Изменения QVPN 1.0.5
SystemTunnelProbeиспользует WindowsGetBestInterfaceExи сверяет выбранный интерфейс для публичных контрольных IPv4/IPv6-адресов с индексом QVPN. Рабочий адаптер и HTTPS напрямую больше не могут сами по себе подтвердить VPN. Проверка выполняется в цикле службы; при потере маршрута статус подключения снимается, повторный отказ восстанавливает локальный туннель на прежнем сервере. Это проверка контрольных маршрутов, а не фильтрация всех обходных путей.Subscriptionограничивает одну полную HTTP-попытку 12 секундами, включая тело послеResponseHeadersRead. Более короткая отмена вызывающего кода действует раньше; прежний один повтор сохранён. Устранён случай, когда пришедшие заголовки оставляли фоновое обновление ждать тело бессрочно. Семантика подтверждена документацией Microsoft.- Результат проверки маршрутов
SystemRoutesVerifiedдоступен через существующий IPC и в диагностике интерфейса. Секреты подписки в него не входят.
Регрессии: 70 проверок успешно, включая обход IPv4/IPv6 при поднятом TUN, неизвестные ошибки Windows route lookup, IPv4-only сеть, зависшее тело подписки и отмену. Живые результаты установки, восстановления и контролируемой потери маршрута сохраняются отдельно в happ-comparison-verification.json, installed-stability-verification.json, system-route-verification.json.
24 октября установлена и проверена версия 1.0.5.0; подписка сохранена, 50 локаций. Подключение к Оулу заняло 3,67 с, системные DNS/HTTPS и сравнительная проверка внешнего выхода прошли. Принудительное завершение Xray, TUN-ядра и службы восстановилось на той же локации за 6,36, 11,24 и 9,07 с соответственно; дочерних процессов после сбоя службы не осталось.
Отдельно добавлен один временный маршрут 1.1.1.1/32 через физическую сеть при поднятом адаптере QVPN. Обход обнаружен за 1,07 с: SystemRoutesVerified=false, состояние connecting вместо ложного connected. Локальный туннель перезапущен за 12,8 с без смены сервера; после удаления тестового маршрута проверенное подключение вернулось за 0,61 с. Удаление именно добавленного маршрута подтверждено. В последующих 61,5 с наблюдения было 27 снимков состояния, 6 успешных системных HTTPS-проверок, 0 самопроизвольных перезапусков и 0 смен сервера. Независимый завершающий HTTPS-запрос вернул 204.
Установщик: dist/QVPN-Setup-1.0.5.exe, SHA-256 B2518BDC3E96CE5CEE905CEE2A44252CA6424CF8771845F17E5F5B5A42D3501F. Все 211 файлов payload совпали с манифестом. Первое обновление откатилось после отказа Windows переместить каталог программы; повторная установка завершилась успешно. Финальное состояние проверки: QVPN подключён к Оулу, служба Happ остановлена.
Транспортное ядро уже совпадало с Happ до этих изменений; SHA-256 текущих бинарников Xray повторно совпал 24 октября. Перенос native TUN требует отдельной реализации DNS-политики, совместимости RU/private-правил и очистки после аварии: Xray использует .dat, а текущий QVPN — .srs; принудительное завершение процесса не гарантирует вызов native Close(). Поэтому в этой версии изменены проверенные дефекты управления существующим туннелем. Многодневная работа и реальный сон/пробуждение этим исследованием не доказаны.