mirror of
https://github.com/okhsunrog/vpnhide.git
synced 2026-04-28 22:52:15 +00:00
105 lines
5.3 KiB
Markdown
105 lines
5.3 KiB
Markdown
# vpnhide
|
|
|
|
Hide an active Android VPN connection from selected apps.
|
|
|
|
Three components work together to cover all detection vectors -- from Java APIs down to kernel syscalls. A diagnostic test app verifies everything works.
|
|
|
|
## Components
|
|
|
|
| Directory | What | How |
|
|
|-----------|------|-----|
|
|
| **[kmod/](kmod/)** | Kernel module (C) | `kretprobe` hooks in kernel space. Zero footprint in the target app's process -- invisible to any userspace anti-tamper SDK. |
|
|
| **[lsposed/](lsposed/)** | LSPosed module (Kotlin) | Hooks `writeToParcel` in `system_server` for per-UID Binder filtering. Only "System Framework" in LSPosed scope -- no in-process hooks. |
|
|
| **[zygisk/](zygisk/)** | Zygisk module (Rust) | Inline-hooks `libc.so` in the target app's process. Alternative to kmod for users who can't install a kernel module. |
|
|
| **[test-app/](test-app/)** | Diagnostic app (Kotlin + C++) | 22 checks covering all detection vectors. Logs to logcat under tag `VPNHideTest`. |
|
|
|
|
## 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` (activeNetwork, allNetworks) | | | | x |
|
|
| 19 | `LinkProperties` (interfaceName, routes, DNS) | | | | x |
|
|
| 20 | `NetworkInterface.getNetworkInterfaces()` | | x | x | |
|
|
| 21 | `System.getProperty` (proxy settings) | | | x | |
|
|
| 22 | `/proc/net/route` via Java `FileInputStream` | blocked | x | x | |
|
|
|
|
**blocked** = SELinux denies access for untrusted apps (Android 10+). No hook needed.
|
|
|
|
**x** = actively filtered by this component.
|
|
|
|
Rows 1-4 and 20 are the only vectors reachable by regular apps. Everything else is either blocked by SELinux or goes through Java APIs (covered by lsposed).
|
|
|
|
## Which modules do I need?
|
|
|
|
- **Apps with aggressive anti-tamper SDKs** (banking, government): `kmod` + `lsposed`. Zero in-process footprint -- undetectable by integrity checks.
|
|
- **Other apps**: `zygisk` + `lsposed`. Simpler to install (no kernel module), covers all reachable vectors.
|
|
- **To verify your setup**: install `test-app`, add it to target lists, run with VPN active -- all checks should pass.
|
|
|
|
## Configuration
|
|
|
|
Both kmod and zygisk modules have a WebUI (KernelSU/Magisk manager -> module settings) to select target apps. On save, the WebUI writes to:
|
|
- `targets.txt` -- persistent package names (survives module updates)
|
|
- `/proc/vpnhide_targets` -- resolved UIDs for the kernel module (kmod only)
|
|
- `/data/system/vpnhide_uids.txt` -- resolved UIDs for the lsposed system_server hooks
|
|
|
|
All changes apply immediately -- no reboot needed.
|
|
|
|
## Building
|
|
|
|
- **kmod**: `cd kmod && make && ./build-zip.sh` (kernel source + clang, see [kmod/BUILDING.md](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 + NDK)
|
|
|
|
## Verified against
|
|
|
|
- [RKNHardering](https://github.com/xtclovver/RKNHardering/) -- all detection vectors clean
|
|
- [YourVPNDead](https://github.com/loop-uh/yourvpndead) -- all detection vectors clean
|
|
|
|
Both implement the official Russian Ministry of Digital Development VPN/proxy detection methodology ([source](https://t.me/ruitunion/893)).
|
|
|
|
## Split tunneling
|
|
|
|
Works correctly with split-tunnel VPN configurations. Only the apps in the target list are affected -- all other apps see normal VPN state.
|
|
|
|
Note: detection apps that compare device-reported public IP against external checkers require split tunneling -- the detection app's HTTPS requests must exit through the carrier, not the tunnel.
|
|
|
|
## Threat model
|
|
|
|
vpnhide is designed for one scenario: "I have a VPN running and certain apps refuse to work because they detect it. I want those specific apps to think the VPN isn't there."
|
|
|
|
It is NOT designed for:
|
|
- Hiding root or custom ROM presence
|
|
- Bypassing Play Integrity
|
|
- Fooling server-side detection (DNS leakage, IP blocklists, latency fingerprinting, TLS fingerprinting)
|
|
|
|
## Known limitations
|
|
|
|
- `kmod` requires a GKI kernel with `CONFIG_KPROBES=y` (standard on Pixel 6-9a with `android14-6.1`)
|
|
- `lsposed` requires LSPosed or a compatible Xposed framework
|
|
- `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
|
|
|
|
- **zygisk**: 0BSD
|
|
- **lsposed**: unlicensed (do whatever you want)
|
|
- **kmod**: GPL-2.0 (required for kernel modules)
|