# 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` использует Windows `GetBestInterfaceEx` и сверяет выбранный интерфейс для публичных контрольных IPv4/IPv6-адресов с индексом QVPN. Рабочий адаптер и HTTPS напрямую больше не могут сами по себе подтвердить VPN. Проверка выполняется в цикле службы; при потере маршрута статус подключения снимается, повторный отказ восстанавливает локальный туннель на прежнем сервере. Это проверка контрольных маршрутов, а не фильтрация всех обходных путей. - `Subscription` ограничивает одну полную HTTP-попытку 12 секундами, включая тело после `ResponseHeadersRead`. Более короткая отмена вызывающего кода действует раньше; прежний один повтор сохранён. Устранён случай, когда пришедшие заголовки оставляли фоновое обновление ждать тело бессрочно. Семантика подтверждена [документацией Microsoft](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpcompletionoption). - Результат проверки маршрутов `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()`. Поэтому в этой версии изменены проверенные дефекты управления существующим туннелем. Многодневная работа и реальный сон/пробуждение этим исследованием не доказаны.