This guide explains the reverse side of RKNHardering’s checks: what the app actually observes, which approaches genuinely change the observable state, and which merely create the appearance of a solution. It is written for development, compatibility testing, and validation of defensive mechanisms you control. The settings below do not guarantee passage through third-party antifraud systems, which may use additional server-side signals, hardware-backed attestation, and proprietary rules.
The material has been checked against the RKNHardering 2.10.0 source code included in this project copy. Completeness is tracked against three registries: 65 EvidenceSource entries, 85 NativeSignalId entries, and 41 beta checks. In the complete matrix, every identifier has separate columns for “without root,” “with root,” and “what remains visible.”
| What RKNHardering detects | What actually needs to change | Best practical option |
|---|---|---|
| GeoIP, differing IPs across RU/non-RU checks, CDN, STUN, and call tests | The route and the real external address | Correct per-app routing and consistent DNS/HTTP/UDP behavior; where required, an egress with the expected country and network type |
TRANSPORT_VPN, TUN, routes, netlink, /proc, and interfaces |
Android’s local network view | Without root, move the VPN to a router or another device; with root, use a system Java layer plus one kernel/native backend |
| Localhost ports and Clash/sing-box/Xray APIs | The target UID’s access to the local control plane | Disable the listener or API; with root, block loopback access for the target UID |
| Installed VPN applications | Package visibility | A separate profile helps only partially; with root, filter PackageManager in system_server |
Magisk/KernelSU/APatch, hooks, RWX regions, maps, properties, and mounts |
Process state and the mount namespace | Do not inject hooks into the target process; minimize the root surface; prefer a kernel-level solution over Zygisk |
| Second Space, work profiles, and app clones | Android user/profile identity | Run in the primary user; moving into a profile is not a complete bypass and creates its own signal |
Android VpnService creates a virtual interface and a system VPN model. Excluding an app from the tunnel through per-app routing changes the path used by that app’s traffic, but it does not necessarily hide the existence of the TUN interface, VPN network, or related routes. RKNHardering checks this separately: an active TUN interface while the app itself has no VPN transport is treated as evidence of explicit per-app exclusion. Adding RKNHardering to a bypass list can therefore help with server-side IP signals, but it is not VPN hiding by itself.
The strongest non-root design is to remove the VPN from the phone as a system object: run it on a router, travel router, separate phone acting as a hotspot, or another gateway. The Android device under test then has no VpnService, TUN interface, or VPN client package. The external IP and server-side indicators must still remain internally consistent.
The official Android references are VpnService and VpnService.Builder. addAllowedApplication and addDisallowedApplication control app routing, while establish() creates the VPN interface itself.
Source labels are used consistently throughout the text:
Start with the threat model and order of operations rather than installing modules immediately. Then use the relevant page:
boot.img or init_boot.img as appropriate for the root solution, module list, VPN configurations, and a backup of profile data.Success is not one green card. All of the following must hold together: