graph TD
A[用户设置应用黑名单] --> B[Zygisk 注入]
B --> C[LSPosed 拦截方法]
C --> D{"应用是否在黑名单? (Zygisk)?"}
D -->|"是"| E{"是VPN源环境监控? (LSPosed)?"}
E -->|"否"| F[正常流程]
E -->|"是"| G{"修改返回结果 (LSPosed)"}
D -->|"否"| H[正常流程]
G --> F
F --> I[完成]
Скрывает активное VPN-соединение на Android от выбранных приложений.
VPN Hide 2.0: установите vpnhide.apk и один модуль vpnhide-core.zip из одной сборки. Core уже содержит payload kmod, KPM и обеих ABI Zygisk, сам выбирает и запускает подходящий backend, пишет конфигурацию и применяет Ports. Приложение работает через локальный сокет и не вызывает su. Отдельные ZIP бэкендов для установки не нужны.
Статус main: переработка 2.0 ещё продолжается. Автоматическое обслуживание, расширенная автономная диагностика и приёмка на устройствах не завершены; фактическое состояние — в roadmap.
Существующие модули, такие как NoVPNDetect и NoVPNDetect Enhanced, покрывают только Java API обнаружение и хукают внутри процесса целевого приложения через Xposed. У этого подхода две критические проблемы:
Обнаружение anti-tamper защитой — любое приложение с проверкой инъекций в память обнаруживает хуки Xposed и отказывается работать. Автор NoVPNDetect Enhanced прямо пишет: «Модуль не будет работать если у подключаемого приложения есть защита от LSPosed, проверка на инъекции в память. Например MirPay, Т-Банк.»
Нет нативного покрытия — приложения, использующие C/C++ код, кроссплатформенные фреймворки (Flutter, React Native) или прямые системные вызовы, могут обнаружить VPN через ioctl, getifaddrs, netlink-сокеты и /proc/net/*. Java-хуки эти векторы полностью пропускают.
vpnhide решает обе проблемы многослойной архитектурой:
Уровень 1 — Java API (модуль lsposed): хукает system_server, а не целевое приложение. NetworkCapabilities, NetworkInfo и LinkProperties фильтруются на уровне Binder до того, как данные попадут в процесс приложения. Приложение получает чистые данные через IPC — этот слой не устанавливает хуки внутри процесса цели. Этот же модуль скрывает выбранные приложения от приложений-наблюдателей на уровне PackageManager (роль Apps).
Уровень 2 — нативный (kmod, встроенный в ядро, KPM или Zygisk): покрывает нативные пути обнаружения. Активным должен быть ровно один Native-бэкенд:
kmod (рекомендуется для поддерживаемых GKI-ядер) — хуки kprobe/kretprobe на уровне ядра. Фильтрует ioctl, getifaddrs/netlink-дампы интерфейсов, адресов, маршрутов и policy rules, а также отклоняет SO_BINDTODEVICE / SO_BINDTOIFINDEX для скрытых интерфейсов до изменения состояния сокета. Этот бэкенд не внедряет библиотеку в процесс цели.
KPM — KernelPatch Module с теми же 11 логическими kernel-хуками, но без привязки к GKI-варианту .ko. Полезен для старых/non-GKI ядер 4.9 / 4.14 / 4.19 / 5.4 и ситуаций, где .ko не может загрузиться. Требует KernelPatch runtime: APatch или KPatch-Next-Module.
Zygisk — запасной вариант, когда совместимый ядерный бэкенд недоступен. Его inline-хуки libc.so работают внутри процессов приложений и могут обходиться прямыми системными вызовами. Банковские, антифрод- и другие защищённые приложения могут обнаружить провайдер или внедрённый код и отказаться работать. Предпочтителен совместимый ядерный бэкенд; его выбор не скрывает установленный провайдер Zygisk или root.
Уровень 3 — Ports (часть модуля core): через iptables блокирует выбранным приложениям доступ к 127.0.0.1 / ::1, чтобы они не могли обнаружить локально запущенный VPN / proxy-демон по открытому порту (роль Ports). Правила применяет модуль core; отдельного модуля Ports в 2.0 нет.
Java-слой и ядерный бэкенд обходятся без собственных inline-хуков в процессе цели. Приложения всё ещё могут обнаруживать root, провайдер Zygisk или другие изменения. Ни один бэкенд не гарантирует совместимость со всеми банковскими, государственными или другими защищёнными приложениями.
Что именно скрывает vpnhide
vpnhide скрывает от выбранных приложений три вещи — всё настраивается пер-апп через четыре роли J / N / A / P (Java, Native, Apps, Ports):
Скрытие интерфейса — главная задача. Убирает VPN-интерфейсы и маршруты из нативных API (ioctl, getifaddrs, netlink, /proc/net/*, NetworkInterface), не позволяет привязать сокет к скрытому интерфейсу и очищает Java API (NetworkCapabilities, NetworkInfo, LinkProperties). Его дают две роли сразу — Java (J) и Native (N), они включаются независимо.
Скрытие портов — блокирует доступ к localhost для выбранных приложений, чтобы они не могли обнаружить Clash, sing-box, V2Ray, Happ и подобные инструменты через проверку локальных портов (роль Ports (P)).
Скрытие приложений — позволяет скрыть выбранные установленные приложения от выбранных приложений-наблюдателей. Полезно против проверок package visibility, например когда приложение пытается определить, установлен ли на устройстве VPN или proxy-клиент (роль Apps (A)).
Какие модули мне нужны?
Для VPN Hide нужны APK + единый Core ZIP. Для Java-слоя дополнительно нужен LSPosed/Vector с модулем VPN Hide в scope System Framework. Ports входит в Core.
Core проверяет применимость backend: совместимый встроенный драйвер, подходящий bundled .ko, аутентифицированный KPM runtime, затем подходящий Zygisk loader. Несколько файлов payload внутри Core не являются конфликтом и не требуют выбора пользователя. Неподтверждённая совместимость или неизвестное состояние загрузки остаются явной причиной отказа, а не выбором наугад.
KernelPatch runtime для KPM и Zygisk loader — отдельные системные зависимости, когда выбранный путь их требует. Они не заменяются отдельным VPN Hide backend ZIP. Для встроенного драйвера отдельный модуль-бэкенд также не нужен, но Core остаётся необходимым.
Установка
Эта инструкция относится к ветке 2.0. Берите APK и полный Core ZIP из одной сборки CI либо одного соответствующего релиза; не смешивайте их с пакетами старой схемы установки.
Установите vpnhide.apk, затем полный vpnhide-core.zip через Magisk / KernelSU / APatch.
Для Java включите модуль VPN Hide в LSPosed/Vector и добавьте System Framework в его scope. Перезагрузите устройство.
Откройте Обзор: состояние выбора, запуска и недостающих зависимостей сообщает Core. Вручную выбирать GKI и скачивать kmod/KPM/Zygisk ZIP не требуется.
Во вкладке Скрытие назначьте роли J / N / A / P приложениям, от которых нужно скрытие. Сохраните изменения. Для Zygisk перезапустите уже работавшие приложения-цели; новый процесс диагностики не доказывает обновление их hooks.
Старые отдельные модули учитываются при миграции и восстановлении. Сначала подготовьте проверенный полный replacement; не удаляйте рабочую установку заранее. Общий автоматизированный maintenance flow ещё доводится.
Конфигурацию /data/system/vpnhide_config.json пишет только Core через типизированные команды приложения/агента. Старые источники 0.x/1.x читаются изолированными адаптерами и сохраняются до подтверждённой миграции/архивации.
Скриншоты
Обзор — VPN скрыт
Скрытие — единый список
Как это работает
Статистика
Разбор по хукам
Выбор хуков для приложения
Диагностика
Настройки
Сообщество
Проверка
В приложении есть встроенная система диагностики, которая автоматически обнаруживает большинство проблем с настройкой.
Обзор (запускается при каждом открытии приложения):
Статус модулей и бэкендов (установлен, активен, версия, количество целей)
Валидация конфигурации LSPosed — читает базу данных LSPosed и проверяет, что VPN Hide включён, System Framework в scope, и нет лишних приложений в scope (частая ошибка при настройке)
Обнаружение несоответствия версий — сравнивает версии установленных модулей с версией приложения и подсказывает, что именно нужно обновить
Рекомендация Native-бэкенда — определяет ядро устройства и подбирает нужный файл kmod, KPM или Zygisk
Проверка скрытия в реальном времени (при активном VPN) — выполняет 13 нативных и 12 Java API проверок, чтобы убедиться, что VPN действительно скрыт
Все обнаруженные проблемы показываются в виде карточек с конкретными инструкциями по исправлению.
Статистика — счётчики перехватов по каждому приложению: какие приложения и какими методами проверяют VPN.
Настройки → Диагностика — детальная разбивка по каждой проверке с индивидуальными результатами PASS/FAIL по всем 25 проверкам. Полезна для отладки, когда «Обзор» показывает неполное скрытие.
vpnhide-core.zip: root-демон, который однострочный service.sh запускает раз за загрузку. Он выбирает и загружает ровно один нативный бэкенд, доставляет ему конфиг, применяет iptables-правила Ports, обслуживает сокет приложения и выполняет его типизированную диагностику.
Тот же драйвер, что .ko, но вкомпилированный в ядро (CONFIG_VPNHIDE=y) — для ядер, где .ko не загрузить: интегрированные модули, нет kprobes, LTO. scripts/integrate.py вносит его в дерево ядра; модуль не нужен, core подхватывает его при загрузке.
Два kernel-level Native-бэкенда: стабильный GKI .ko на kretprobe и KPM на KernelPatch inline hooks. Оба дают нулевой след в процессе приложения; активным должен быть только один. (подробнее, KPM)
блок. = на сток-enforcing сборках (Android 10+) SELinux обычно запрещает обычным приложениям доступ к этому файлу /proc/net/* / /sys. Но политика SELinux настроена по-разному на разных устройствах и прошивках (OEM- и кастомные ROM, permissive-сборки), поэтому защитой vpnhide следует считать только явно указанное в таблице покрытие.
libc = best-effort покрытие Zygisk: прямой системный вызов обходит inline-хук.
опц. = скрытие файловых путей в .ko по умолчанию выключено. Включите его
в настройках и перезагрузите устройство; в выключенном состоянии глобальные
VFS-хуки вообще не устанавливаются.
Важно: ioctl и netlink-дампы доступны обычному приложению без помощи SELinux; на Linux 5.7+ это относится и к первой привязке сокета к интерфейсу. Именно через netlink детекторы вроде RKNHardering обходят блокировку /proc/net/route (см. issue #86). Kernel-level варианты (kmod/KPM) закрывают отмеченные в таблице нативные пути без следа в процессе. Zygisk закрывает только вызовы, проходящие через libc; прямой raw syscall обходит его хуки. На более старых ядрах привязку непривилегированного сокета отклоняет само ядро. Остальное либо часто блокируется SELinux на стоке (но это зависит от устройства), либо идёт через Java API и покрывается LSPosed.
KPM реализует те же 11 логических kernel-хуков, что и .ko, но отдельные различия ABI и поведения на старых ядрах перечислены в полной карте векторов.
Полная карта векторов — с разбивкой по слоям, нюансами SELinux и известными пробелами — в docs/detection-vectors.md.
Сборка из исходников
Скрипты отдельных компонентов создают внутренние входы сборки. core/build.py даёт только daemon-base, даже если его локальный файл называется vpnhide-core.zip. Полный устанавливаемый пакет собирает tools/vpnhide-tooling bundle assemble из Core base, всех семи KMI, KPM и двух Zygisk ABI; CI публикует пользователю только полный Core, APK и подписанное описание пакета.
core: python3 core/build.py — собирает vpnhide-core для arm64 + armv7 (cargo-ndk) в core/target/vpnhide-core.zip.
kmod: ./kmod/build.py --kmi android14-6.1 (или --all) — авто-запускает DDK-контейнер через podman/docker. Подробнее: kmod/BUILDING.md.
zygisk: cd zygisk && ./build.py (Rust + NDK + cargo-ndk)
lsposed: cd lsposed && ./gradlew assembleDebug (JDK 17 + Rust + NDK + cargo-ndk). Обычный debug APK остаётся debuggable, но проходит R8/shrink, чтобы не раздувать Xposed-модуль при установке и agent smoke-тестах. Для старой unminified debug-сборки используйте ./gradlew assembleRawDebug.
Заметки для контрибьюторов, застрявших на Windows
Если вы используете Windows, при сборке некоторых подпроектов возникают определенные неудобства.
lsposed: отлично собирается в Android Studio.
Для kmod и zygisk вам (к сожалению) потребуется установить Docker for Windows.
kmod: python .\kmod\build.py --kmi android14-6.1 — скрипт сам подберёт docker и поднимет образ ddk-min (тот же, что в CI).
KPM: собирайте из Linux или WSL. Скрипт ожидает POSIX-инструменты, make/clang, KernelPatch submodule и Android NDK; нативная сборка на Windows сейчас не документирована.
Причина, по которой zygisk нельзя собрать напрямую, заключается в том, что исходный код зависимости zygisk-api содержит файл с именем aux.rs. Cargo использует libgit2 для работы с git, в котором есть защита, запрещающая создавать файлы, содержащие зарезервированные слова Windows. Вы получите ошибку: cannot checkout to invalid path 'src/aux.rs'; class=Checkout (20). Сообщают, что после какого-то обновления стало возможным создавать файлы, содержащие зарезервированные слова, с расширением, но, похоже, в libgit2 это поведение не было изменено.
Оба реализуют официальную методику обнаружения VPN/прокси Минцифры РФ (источник).
Раздельное туннелирование (split tunneling)
Корректно работает с конфигурациями VPN с раздельным туннелированием: затрагиваются только приложения из списка целей.
Настоятельно рекомендуется использовать split tunneling в паре с VPN Hide. VPN Hide прячет VPN на устройстве, но не может изменить то, что видит сервер: если приложение идёт через туннель, сервис видит выходной IP VPN-сервера и может отказать по нему. Поэтому приложения, которым туннель не нужен (банки, госуслуги, платёжные сервисы), лучше исключить из туннеля в настройках VPN-клиента — тогда они видят настоящий IP и никаких следов VPN. Подробнее: Напрямую или через туннель.
Приложения-детекторы, сравнивающие публичный IP устройства с внешними чекерами, лучше оставлять вне туннеля — их трафик должен выходить через оператора, а не через VPN.
Модель угроз
Подробная модель угроз: возможности атакующего приложения, доверенные компоненты, границы защиты и ограничения диагностики.
vpnhide скрывает активный VPN от конкретных приложений. Он НЕ предназначен для:
kmod требует поддерживаемое GKI-ядро с CONFIG_KPROBES=y (стандарт на устройствах Android 12+)
KPM требует KernelPatch runtime (APatch или KPatch-Next-Module); не ставьте KPM одновременно с .ko
lsposed требует LSPosed, LSPosed-Next или Vector
zygisk собирается под arm64-v8a и armeabi-v7a (внедрение в 32-битные процессы); kernel-бэкенды — только arm64
Прямые системные вызовы svc #0 обходят хуки libc в Zygisk — для этого нужен kernel-level backend (kmod или KPM)
До VPN Hide Core может достучаться только приложение (dev.okhsunrog.vpnhide), установленное в основном пользователе Android (user 0). Core создаёт свой сокет в каталоге данных именно этого приложения, поэтому копии во вторичном пользователе, рабочем профиле или пространстве клонов показывают экран «core недоступен». Управляйте всеми профилями из копии в основном пользователе
Серверная детекция неисправима на стороне клиента — используйте раздельное туннелирование
Поддержать проект
vpnhide бесплатный, без рекламы и телеметрии. Платных функций не будет — донат ничего не открывает.
Тот же список есть в приложении: Настройки → Поддержать проект, там адреса копируются по тапу.
评论