Find a file
okhsunrog e2d41dea13 style: add clang-format, ktlint, editorconfig and format all code
- Add .editorconfig with ktlint config (disable wildcard-import rule,
  allow PascalCase for @Composable functions)
- Add kmod/.clang-format from upstream kernel tree
- Run clang-format on vpnhide_kmod.c (kernel coding style)
- Run ktlint --format on all Kotlin files (lsposed + test-app)
2026-04-12 23:26:36 +03:00
.github ci: rename APK artifacts to vpnhide-lsposed.apk and vpnhide-test.apk 2026-04-11 23:07:03 +03:00
kmod style: add clang-format, ktlint, editorconfig and format all code 2026-04-12 23:26:36 +03:00
lsposed style: add clang-format, ktlint, editorconfig and format all code 2026-04-12 23:26:36 +03:00
test-app style: add clang-format, ktlint, editorconfig and format all code 2026-04-12 23:26:36 +03:00
zygisk fix: rustfmt, clippy, and test fixes for zygisk 2026-04-12 23:17:20 +03:00
.editorconfig style: add clang-format, ktlint, editorconfig and format all code 2026-04-12 23:26:36 +03:00
.gitignore chore: ignore stray zip files in repo root 2026-04-12 05:41:08 +03:00
.gitmodules monorepo: combine vpnhide-zygisk, vpnhide (lsposed), and vpnhide-kmod 2026-04-11 15:01:49 +03:00
LICENSE license: unify entire project under MIT 2026-04-11 21:58:07 +03:00
README.md docs: clarify root grant differs between Magisk and KernelSU-Next 2026-04-12 05:37:07 +03:00
update-version.sh chore: add VERSION file and update-version.sh, bump to v0.4.0 2026-04-12 03:23:16 +03:00
VERSION chore: add VERSION file and update-version.sh, bump to v0.4.0 2026-04-12 03:23:16 +03:00

vpnhide

Hide an active Android VPN connection from selected apps.

Which modules do I need?

You always need lsposed (handles Java API detection) plus one native module:

  • kmod + lsposed (recommended) — kernel-level hooks, zero in-process footprint. Invisible to anti-tamper SDKs in banking/government apps. Requires a supported GKI kernel (see below).
  • zygisk + lsposed — in-process libc hooks. Use this if your device's GKI generation isn't covered by the kmod builds, or if you can't install kernel modules.

Install

Download the latest release from Releases.

  1. Install vpnhide-kmod-<your-gki>.zip via KernelSU-Next manager → Modules → Install from storage
  2. Install vpnhide-lsposed.apk as a regular app
  3. In LSPosed manager, enable the vpnhide module and add "System Framework" to its scope
  4. Reboot (required — LSPosed hooks are injected into system_server at boot, so the module must be active before system_server starts)
  5. Open the VPN Hide app, grant it root access (Magisk will prompt automatically; on KernelSU-Next, grant permission manually in the manager), and select target apps

Finding your GKI generation: run adb shell uname -r. The output looks like 6.1.75-android14-11-g... — the generation is android14-6.1. Download the matching vpnhide-kmod-android14-6.1.zip.

Note: the android14 in the GKI name is NOT your Android version — it's the kernel generation. All Pixels from 6 to 9a share the same android14-6.1 kernel. Pixel 10 series moves to android16-6.12.

zygisk + lsposed

  1. Install vpnhide-zygisk.zip via KernelSU-Next or Magisk manager → Modules
  2. Install vpnhide-lsposed.apk as a regular app
  3. In LSPosed manager, enable the vpnhide module and add "System Framework" to its scope
  4. Reboot (required — LSPosed hooks are injected into system_server at boot)
  5. Open the VPN Hide app, grant it root access (Magisk will prompt automatically; on KernelSU-Next, grant permission manually in the manager), and select target apps

Configuration

VPN Hide app (recommended): open the VPN Hide app (installed as vpnhide-lsposed.apk) and grant it root access (Magisk prompts automatically; on KernelSU-Next, grant permission in the manager). It shows all installed apps with icons, names, and search. Check the apps you want to hide VPN from, tap Save. Works with both kmod and zygisk — writes to all target locations automatically via su.

WebUI: on KernelSU-Next, open the module in the manager and tap WebUI. Same functionality, but only available on KernelSU-Next (Magisk doesn't support WebUI).

Shell: edit /data/adb/vpnhide_kmod/targets.txt or /data/adb/vpnhide_zygisk/targets.txt directly (one package name per line). Reboot for changes to take effect.

After changing targets, force-stop and restart the affected apps — hooks take effect on the next app launch.

Verify

Install vpnhide-test.apk from the release, add it to the target list via WebUI, and launch it with VPN active. All checks should show PASS.

Components

Directory What How
kmod/ Kernel module (C) kretprobe hooks in kernel space. Zero footprint in the target app's process. (details)
lsposed/ LSPosed module + target picker app (Kotlin) Hooks writeToParcel in system_server for per-UID Binder filtering. The APK also serves as the target management UI. (details)
zygisk/ Zygisk module (Rust) Inline-hooks libc.so in the target app's process. Alternative to kmod. (details)
test-app/ Diagnostic app (Kotlin + Rust) 24 checks covering all detection vectors.

Detection coverage

# Detection vector SELinux kmod zygisk lsposed
1 ioctl(SIOCGIFFLAGS) on tun0 x x
2 ioctl(SIOCGIFNAME) resolve index to name x x
3 ioctl(SIOCGIFCONF) interface enumeration x x
4 getifaddrs() (uses netlink internally) x x
5 netlink RTM_GETLINK dump blocked x x
6 netlink RTM_GETADDR dump (IPv4 + IPv6) blocked x
7 netlink RTM_GETROUTE dump blocked
8 /proc/net/route blocked x x
9 /proc/net/ipv6_route blocked x
10 /proc/net/if_inet6 blocked x
11 /proc/net/tcp, tcp6 blocked
12 /proc/net/udp, udp6 blocked
13 /proc/net/dev blocked
14 /proc/net/fib_trie blocked
15 /sys/class/net/tun0/ blocked
16 NetworkCapabilities (hasTransport, NOT_VPN, transportInfo) x
17 NetworkInfo (getType, getTypeName) x
18 ConnectivityManager.getActiveNetwork() x
19 ConnectivityManager.getAllNetworks() + VPN scan x
20 LinkProperties (interfaceName, routes, DNS) x
21 NetworkInterface.getNetworkInterfaces() x x
22 System.getProperty (proxy settings) x
23 /proc/net/route via Java FileInputStream blocked x x

blocked = SELinux denies access for untrusted apps (Android 10+). No hook needed.

Rows 1-4, 19, and 21 are the only vectors reachable by regular apps. Everything else is either blocked by SELinux or goes through Java APIs (covered by lsposed).

Building from source

  • kmod: cd kmod && make && ./build-zip.sh — see kmod/BUILDING.md
  • zygisk: cd zygisk && ./build-zip.sh (Rust + NDK + cargo-ndk)
  • lsposed: cd lsposed && ./gradlew assembleDebug (JDK 17)
  • test-app: cd test-app && ./gradlew installDebug (JDK 17 + Rust + NDK)

Verified against

Both implement the official Russian Ministry of Digital Development VPN/proxy detection methodology (source).

Split tunneling

Works correctly with split-tunnel VPN configurations. Only the apps in the target list are affected.

Detection apps that compare device-reported public IP against external checkers require split tunneling — the detection app's traffic must exit through the carrier, not the tunnel.

Threat model

vpnhide hides an active VPN from specific apps. It is NOT designed for:

  • Hiding root or custom ROM presence
  • Bypassing Play Integrity
  • Fooling server-side detection (DNS leakage, IP blocklists, latency/TLS fingerprinting)

Known limitations

  • kmod requires a GKI kernel with CONFIG_KPROBES=y (standard on Android 12+ devices)
  • lsposed requires LSPosed, LSPosed-Next, or Vector
  • zygisk is arm64 only
  • Direct svc #0 syscalls bypass zygisk's libc hooks — that's what kmod is for
  • Server-side detection is unfixable client-side — use split tunneling

License

MIT. See LICENSE.

The kernel module declares MODULE_LICENSE("GPL") as required by the Linux kernel to resolve EXPORT_SYMBOL_GPL symbols at runtime.