Android root detection bypass via Frida
A test APK with three separate root-detection mechanisms stacked on top of each other — common pattern in banking and DRM-sensitive apps. Goal: get past all three without touching the APK on disk.
Mapping the checks
Static triage with jadx first, searching for the usual suspects:
$ jadx-gui app.apk
Three distinct checks turned up:
subinary path check — walks a hardcoded list of paths (/system/bin/su,/system/xbin/su, etc.) and checksFile.exists()on each- Build tags check — reads
Build.TAGSand flags anything containing"test-keys" RootBeerlibrary check — a third-party root detection library doing its own more thorough scan
Patching all three statically means re-signing the APK and re-installing it every time something changes. Frida avoids that entirely — hook the relevant methods at runtime and feed them fake answers.
The Frida script
Java.perform(function () {
// 1. File.exists() — return false for su paths specifically
var File = Java.use('java.io.File');
File.exists.implementation = function () {
var path = this.getAbsolutePath();
if (path.indexOf('su') !== -1) {
return false;
}
return this.exists();
};
// 2. Build.TAGS — spoof to release-keys
var Build = Java.use('android.os.Build');
Build.TAGS.value = 'release-keys';
// 3. RootBeer — hook the public check method directly
var RootBeer = Java.use('com.scottyab.rootbeer.RootBeer');
RootBeer.isRooted.implementation = function () {
return false;
};
});
$ frida -U -f com.example.app -l bypass.js --no-pause
All three checks pass clean. App boots straight past the root-detection screen into the normal flow.
Why hook instead of patch
Patching the APK works too, but it’s a one-shot fix tied to that exact build — the moment the developer adds a fourth check or changes a string the detection logic looks for, the patch is stale and needs redoing from scratch. The Frida script targets the behaviour (file existence, a static field, a known library’s public method) rather than specific bytes, so it survives minor app updates far better. Worth keeping a small library of these hooks per detection pattern rather than writing one-off scripts each time.