vpnhide/README.md

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)