From d6429b7ac760892bd2e3a6df4741a8177b0b3479 Mon Sep 17 00:00:00 2001 From: Riyad Mondol Date: Sat, 14 Jun 2025 05:04:12 +0600 Subject: [PATCH 1/7] Add files via upload Added root detection bypass --- root_detection_bypass.js | 336 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 root_detection_bypass.js diff --git a/root_detection_bypass.js b/root_detection_bypass.js new file mode 100644 index 0000000..b0dd8b2 --- /dev/null +++ b/root_detection_bypass.js @@ -0,0 +1,336 @@ +(() => { + 'use strict'; + + const CONFIG = { + fingerprint: "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys", + secureProps: { + "ro.secure": "1", + "ro.debuggable": "0", + "ro.build.type": "user", + "ro.build.tags": "release-keys" + } + }; + + const ROOT_INDICATORS = { + paths: new Set([ + "/data/local/bin/su", + "/data/local/su", + "/data/local/xbin/su", + "/dev/com.koushikdutta.superuser.daemon/", + "/sbin/su", + "/su/bin/su", + "/system/bin/su", + "/system/xbin/su", + "/system/sbin/su", + "/vendor/bin/su", + "/data/adb/su/bin/su", + "/system/bin/failsafe/su", + "/system/bin/.ext/.su", + "/system/bin/.ext/su", + "/system/bin/failsafe/su", + "/system/sd/xbin/su", + "/system/usr/we-need-root/su", + "/cache/su", + "/data/su", + "/dev/su", + "/data/adb/magisk", + "/sbin/.magisk", + "/cache/.disable_magisk", + "/dev/.magisk.unblock", + "/cache/magisk.log", + "/data/adb/magisk.img", + "/data/adb/magisk.db", + "/data/adb/magisk_simple", + "/init.magisk.rc", + "/system/app/Superuser.apk", + "/system/etc/init.d/99SuperSUDaemon", + "/system/xbin/daemonsu", + "/system/xbin/ku.sud", + "/data/adb/ksu", + "/data/adb/ksud", + "/system/xbin/busybox", + "/system/app/Kinguser.apk" + ]), + + packages: new Set([ + "com.noshufou.android.su", + "com.noshufou.android.su.elite", + "eu.chainfire.supersu", + "com.koushikdutta.superuser", + "com.thirdparty.superuser", + "com.yellowes.su", + "com.koushikdutta.rommanager", + "com.koushikdutta.rommanager.license", + "com.dimonvideo.luckypatcher", + "com.chelpus.lackypatch", + "com.ramdroid.appquarantine", + "com.ramdroid.appquarantinepro", + "com.topjohnwu.magisk", + "me.weishu.kernelsu" + ]), + + commands: new Set([ + "su", + "which su", + "whereis su", + "locate su", + "find / -name su", + "mount", + "magisk", + "/system/bin/su", + "/system/xbin/su", + "/sbin/su", + "/su/bin/su" + ]), + + binaries: new Set([ + "su", + "busybox", + "magisk", + "supersu", + "ksud", + "daemonsu" + ]) + }; + + const Logger = { + prefix: "RootBypass: ", + info(message) { + console.log(`${this.prefix}${message}`); + }, + error(message, error) { + console.error(`${this.prefix}ERROR: ${message}`, error || ""); + } + }; + + function bypassNativeFileCheck() { + const fopen = Module.findExportByName("libc.so", "fopen"); + if (fopen) { + Interceptor.attach(fopen, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + if (retval.toInt32() !== 0) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked fopen: ${this.path}`); + retval.replace(ptr(0x0)); + } + } + } + }); + } + + const access = Module.findExportByName("libc.so", "access"); + if (access) { + Interceptor.attach(access, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + if (retval.toInt32() === 0) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked access: ${this.path}`); + retval.replace(ptr(-1)); + } + } + } + }); + } + + const stat = Module.findExportByName("libc.so", "stat"); + if (stat) { + Interceptor.attach(stat, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked stat: ${this.path}`); + retval.replace(ptr(-1)); + } + } + }); + } + + const lstat = Module.findExportByName("libc.so", "lstat"); + if (lstat) { + Interceptor.attach(lstat, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked lstat: ${this.path}`); + retval.replace(ptr(-1)); + } + } + }); + } + } + + function bypassJavaFileCheck() { + const UnixFileSystem = Java.use("java.io.UnixFileSystem"); + UnixFileSystem.checkAccess.implementation = function(file, access) { + const filename = file.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file access check: ${filename}`); + return false; + } + return this.checkAccess(file, access); + }; + + const File = Java.use("java.io.File"); + File.exists.implementation = function() { + const filename = this.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file exists check: ${filename}`); + return false; + } + return this.exists(); + }; + + File.length.implementation = function() { + const filename = this.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file length check: ${filename}`); + return 0; + } + return this.length(); + }; + + const FileInputStream = Java.use("java.io.FileInputStream"); + FileInputStream.$init.overload('java.io.File').implementation = function(file) { + const filename = file.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked FileInputStream creation: ${filename}`); + throw new Java.use("java.io.FileNotFoundException").$new(filename); + } + return this.$init(file); + }; + } + + function setProp() { + try { + const Build = Java.use("android.os.Build"); + const fields = { + "TAGS": "release-keys", + "TYPE": "user", + "FINGERPRINT": CONFIG.fingerprint + }; + + Object.entries(fields).forEach(([field, value]) => { + const fieldObj = Build.class.getDeclaredField(field); + fieldObj.setAccessible(true); + fieldObj.set(null, value); + }); + + const system_property_get = Module.findExportByName("libc.so", "__system_property_get"); + if (system_property_get) { + Interceptor.attach(system_property_get, { + onEnter(args) { + this.key = args[0].readCString(); + this.ret = args[1]; + }, + onLeave(retval) { + const secureValue = CONFIG.secureProps[this.key]; + if (secureValue !== undefined) { + const valuePtr = Memory.allocUtf8String(secureValue); + Memory.copy(this.ret, valuePtr, secureValue.length + 1); + } + } + }); + } + + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('java.lang.String').implementation = function(cmd) { + if (cmd.startsWith("getprop ")) { + const prop = cmd.split(" ")[1]; + if (CONFIG.secureProps[prop]) { + Logger.info(`Blocked getprop command: ${cmd}`); + return null; + } + } + return this.exec(cmd); + }; + } catch (error) { + Logger.error("Error setting up build properties bypass", error); + } + } + + function bypassRootPackageCheck() { + const ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager"); + + ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(str, i) { + if (ROOT_INDICATORS.packages.has(str)) { + Logger.info(`Blocked package check: ${str}`); + str = "com.nonexistent.package"; + } + return this.getPackageInfo(str, i); + }; + + ApplicationPackageManager.getInstalledPackages.overload('int').implementation = function(flags) { + const packages = this.getInstalledPackages(flags); + const packageList = packages.toArray(); + const filteredPackages = packageList.filter(pkg => !ROOT_INDICATORS.packages.has(pkg.packageName.value)); + return Java.use("java.util.ArrayList").$new(filteredPackages); + }; + } + + function bypassShellCommands() { + try { + const ProcessBuilder = Java.use('java.lang.ProcessBuilder'); + ProcessBuilder.command.overload('java.util.List').implementation = function(commands) { + const cmdList = commands.toArray(); + if (cmdList.length > 0) { + const cmd = cmdList[0].toString(); + if (ROOT_INDICATORS.commands.has(cmd) || (cmdList.length > 1 && ROOT_INDICATORS.binaries.has(cmdList[1].toString()))) { + Logger.info(`Blocked ProcessBuilder command: ${cmdList.join(' ')}`); + return this.command(Java.use("java.util.Arrays").asList([""])); + } + } + return this.command(commands); + }; + + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0]; + if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1]))) { + Logger.info(`Blocked Runtime.exec command array: ${cmdArray.join(' ')}`); + return this.exec([""]); + } + } + return this.exec(cmdArray); + }; + + const ProcessImpl = Java.use("java.lang.ProcessImpl"); + ProcessImpl.start.implementation = function(cmdArray, env, dir, redirects, redirectErrorStream) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0].toString(); + const arg = cmdArray.length > 1 ? cmdArray[1].toString() : ""; + + if (ROOT_INDICATORS.commands.has(cmd) || ROOT_INDICATORS.binaries.has(arg)) { + Logger.info(`Blocked ProcessImpl command: ${cmdArray.join(' ')}`); + return ProcessImpl.start.call(this, [Java.use("java.lang.String").$new("")], env, dir, redirects, redirectErrorStream); + } + } + return ProcessImpl.start.call(this, cmdArray, env, dir, redirects, redirectErrorStream); + }; + } catch (error) { + Logger.error("Error setting up shell command bypass", error); + } + } + + Logger.info("Initializing root detection bypass..."); + bypassNativeFileCheck(); + bypassJavaFileCheck(); + setProp(); + bypassRootPackageCheck(); + bypassShellCommands(); + Logger.info("Root detection bypass initialized successfully"); +})(); From fa10ac6f9bf53e7d810a3d3b20ef7381dfcd0d59 Mon Sep 17 00:00:00 2001 From: Riyad Mondol Date: Sat, 14 Jun 2025 05:08:12 +0600 Subject: [PATCH 2/7] Delete root_detection_bypass.js --- root_detection_bypass.js | 336 --------------------------------------- 1 file changed, 336 deletions(-) delete mode 100644 root_detection_bypass.js diff --git a/root_detection_bypass.js b/root_detection_bypass.js deleted file mode 100644 index b0dd8b2..0000000 --- a/root_detection_bypass.js +++ /dev/null @@ -1,336 +0,0 @@ -(() => { - 'use strict'; - - const CONFIG = { - fingerprint: "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys", - secureProps: { - "ro.secure": "1", - "ro.debuggable": "0", - "ro.build.type": "user", - "ro.build.tags": "release-keys" - } - }; - - const ROOT_INDICATORS = { - paths: new Set([ - "/data/local/bin/su", - "/data/local/su", - "/data/local/xbin/su", - "/dev/com.koushikdutta.superuser.daemon/", - "/sbin/su", - "/su/bin/su", - "/system/bin/su", - "/system/xbin/su", - "/system/sbin/su", - "/vendor/bin/su", - "/data/adb/su/bin/su", - "/system/bin/failsafe/su", - "/system/bin/.ext/.su", - "/system/bin/.ext/su", - "/system/bin/failsafe/su", - "/system/sd/xbin/su", - "/system/usr/we-need-root/su", - "/cache/su", - "/data/su", - "/dev/su", - "/data/adb/magisk", - "/sbin/.magisk", - "/cache/.disable_magisk", - "/dev/.magisk.unblock", - "/cache/magisk.log", - "/data/adb/magisk.img", - "/data/adb/magisk.db", - "/data/adb/magisk_simple", - "/init.magisk.rc", - "/system/app/Superuser.apk", - "/system/etc/init.d/99SuperSUDaemon", - "/system/xbin/daemonsu", - "/system/xbin/ku.sud", - "/data/adb/ksu", - "/data/adb/ksud", - "/system/xbin/busybox", - "/system/app/Kinguser.apk" - ]), - - packages: new Set([ - "com.noshufou.android.su", - "com.noshufou.android.su.elite", - "eu.chainfire.supersu", - "com.koushikdutta.superuser", - "com.thirdparty.superuser", - "com.yellowes.su", - "com.koushikdutta.rommanager", - "com.koushikdutta.rommanager.license", - "com.dimonvideo.luckypatcher", - "com.chelpus.lackypatch", - "com.ramdroid.appquarantine", - "com.ramdroid.appquarantinepro", - "com.topjohnwu.magisk", - "me.weishu.kernelsu" - ]), - - commands: new Set([ - "su", - "which su", - "whereis su", - "locate su", - "find / -name su", - "mount", - "magisk", - "/system/bin/su", - "/system/xbin/su", - "/sbin/su", - "/su/bin/su" - ]), - - binaries: new Set([ - "su", - "busybox", - "magisk", - "supersu", - "ksud", - "daemonsu" - ]) - }; - - const Logger = { - prefix: "RootBypass: ", - info(message) { - console.log(`${this.prefix}${message}`); - }, - error(message, error) { - console.error(`${this.prefix}ERROR: ${message}`, error || ""); - } - }; - - function bypassNativeFileCheck() { - const fopen = Module.findExportByName("libc.so", "fopen"); - if (fopen) { - Interceptor.attach(fopen, { - onEnter(args) { - this.path = args[0].readUtf8String(); - }, - onLeave(retval) { - if (retval.toInt32() !== 0) { - const path = this.path.toLowerCase(); - if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked fopen: ${this.path}`); - retval.replace(ptr(0x0)); - } - } - } - }); - } - - const access = Module.findExportByName("libc.so", "access"); - if (access) { - Interceptor.attach(access, { - onEnter(args) { - this.path = args[0].readUtf8String(); - }, - onLeave(retval) { - if (retval.toInt32() === 0) { - const path = this.path.toLowerCase(); - if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked access: ${this.path}`); - retval.replace(ptr(-1)); - } - } - } - }); - } - - const stat = Module.findExportByName("libc.so", "stat"); - if (stat) { - Interceptor.attach(stat, { - onEnter(args) { - this.path = args[0].readUtf8String(); - }, - onLeave(retval) { - const path = this.path.toLowerCase(); - if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked stat: ${this.path}`); - retval.replace(ptr(-1)); - } - } - }); - } - - const lstat = Module.findExportByName("libc.so", "lstat"); - if (lstat) { - Interceptor.attach(lstat, { - onEnter(args) { - this.path = args[0].readUtf8String(); - }, - onLeave(retval) { - const path = this.path.toLowerCase(); - if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked lstat: ${this.path}`); - retval.replace(ptr(-1)); - } - } - }); - } - } - - function bypassJavaFileCheck() { - const UnixFileSystem = Java.use("java.io.UnixFileSystem"); - UnixFileSystem.checkAccess.implementation = function(file, access) { - const filename = file.getAbsolutePath(); - if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file access check: ${filename}`); - return false; - } - return this.checkAccess(file, access); - }; - - const File = Java.use("java.io.File"); - File.exists.implementation = function() { - const filename = this.getAbsolutePath(); - if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file exists check: ${filename}`); - return false; - } - return this.exists(); - }; - - File.length.implementation = function() { - const filename = this.getAbsolutePath(); - if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file length check: ${filename}`); - return 0; - } - return this.length(); - }; - - const FileInputStream = Java.use("java.io.FileInputStream"); - FileInputStream.$init.overload('java.io.File').implementation = function(file) { - const filename = file.getAbsolutePath(); - if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked FileInputStream creation: ${filename}`); - throw new Java.use("java.io.FileNotFoundException").$new(filename); - } - return this.$init(file); - }; - } - - function setProp() { - try { - const Build = Java.use("android.os.Build"); - const fields = { - "TAGS": "release-keys", - "TYPE": "user", - "FINGERPRINT": CONFIG.fingerprint - }; - - Object.entries(fields).forEach(([field, value]) => { - const fieldObj = Build.class.getDeclaredField(field); - fieldObj.setAccessible(true); - fieldObj.set(null, value); - }); - - const system_property_get = Module.findExportByName("libc.so", "__system_property_get"); - if (system_property_get) { - Interceptor.attach(system_property_get, { - onEnter(args) { - this.key = args[0].readCString(); - this.ret = args[1]; - }, - onLeave(retval) { - const secureValue = CONFIG.secureProps[this.key]; - if (secureValue !== undefined) { - const valuePtr = Memory.allocUtf8String(secureValue); - Memory.copy(this.ret, valuePtr, secureValue.length + 1); - } - } - }); - } - - const Runtime = Java.use('java.lang.Runtime'); - Runtime.exec.overload('java.lang.String').implementation = function(cmd) { - if (cmd.startsWith("getprop ")) { - const prop = cmd.split(" ")[1]; - if (CONFIG.secureProps[prop]) { - Logger.info(`Blocked getprop command: ${cmd}`); - return null; - } - } - return this.exec(cmd); - }; - } catch (error) { - Logger.error("Error setting up build properties bypass", error); - } - } - - function bypassRootPackageCheck() { - const ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager"); - - ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(str, i) { - if (ROOT_INDICATORS.packages.has(str)) { - Logger.info(`Blocked package check: ${str}`); - str = "com.nonexistent.package"; - } - return this.getPackageInfo(str, i); - }; - - ApplicationPackageManager.getInstalledPackages.overload('int').implementation = function(flags) { - const packages = this.getInstalledPackages(flags); - const packageList = packages.toArray(); - const filteredPackages = packageList.filter(pkg => !ROOT_INDICATORS.packages.has(pkg.packageName.value)); - return Java.use("java.util.ArrayList").$new(filteredPackages); - }; - } - - function bypassShellCommands() { - try { - const ProcessBuilder = Java.use('java.lang.ProcessBuilder'); - ProcessBuilder.command.overload('java.util.List').implementation = function(commands) { - const cmdList = commands.toArray(); - if (cmdList.length > 0) { - const cmd = cmdList[0].toString(); - if (ROOT_INDICATORS.commands.has(cmd) || (cmdList.length > 1 && ROOT_INDICATORS.binaries.has(cmdList[1].toString()))) { - Logger.info(`Blocked ProcessBuilder command: ${cmdList.join(' ')}`); - return this.command(Java.use("java.util.Arrays").asList([""])); - } - } - return this.command(commands); - }; - - const Runtime = Java.use('java.lang.Runtime'); - Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) { - if (cmdArray.length > 0) { - const cmd = cmdArray[0]; - if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1]))) { - Logger.info(`Blocked Runtime.exec command array: ${cmdArray.join(' ')}`); - return this.exec([""]); - } - } - return this.exec(cmdArray); - }; - - const ProcessImpl = Java.use("java.lang.ProcessImpl"); - ProcessImpl.start.implementation = function(cmdArray, env, dir, redirects, redirectErrorStream) { - if (cmdArray.length > 0) { - const cmd = cmdArray[0].toString(); - const arg = cmdArray.length > 1 ? cmdArray[1].toString() : ""; - - if (ROOT_INDICATORS.commands.has(cmd) || ROOT_INDICATORS.binaries.has(arg)) { - Logger.info(`Blocked ProcessImpl command: ${cmdArray.join(' ')}`); - return ProcessImpl.start.call(this, [Java.use("java.lang.String").$new("")], env, dir, redirects, redirectErrorStream); - } - } - return ProcessImpl.start.call(this, cmdArray, env, dir, redirects, redirectErrorStream); - }; - } catch (error) { - Logger.error("Error setting up shell command bypass", error); - } - } - - Logger.info("Initializing root detection bypass..."); - bypassNativeFileCheck(); - bypassJavaFileCheck(); - setProp(); - bypassRootPackageCheck(); - bypassShellCommands(); - Logger.info("Root detection bypass initialized successfully"); -})(); From da710353fe4ec67820c50afb2f791a408b3df0a8 Mon Sep 17 00:00:00 2001 From: Riyad Mondol Date: Sat, 14 Jun 2025 05:08:26 +0600 Subject: [PATCH 3/7] Add files via upload --- android/root_detection_bypass.js | 336 +++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 android/root_detection_bypass.js diff --git a/android/root_detection_bypass.js b/android/root_detection_bypass.js new file mode 100644 index 0000000..b0dd8b2 --- /dev/null +++ b/android/root_detection_bypass.js @@ -0,0 +1,336 @@ +(() => { + 'use strict'; + + const CONFIG = { + fingerprint: "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys", + secureProps: { + "ro.secure": "1", + "ro.debuggable": "0", + "ro.build.type": "user", + "ro.build.tags": "release-keys" + } + }; + + const ROOT_INDICATORS = { + paths: new Set([ + "/data/local/bin/su", + "/data/local/su", + "/data/local/xbin/su", + "/dev/com.koushikdutta.superuser.daemon/", + "/sbin/su", + "/su/bin/su", + "/system/bin/su", + "/system/xbin/su", + "/system/sbin/su", + "/vendor/bin/su", + "/data/adb/su/bin/su", + "/system/bin/failsafe/su", + "/system/bin/.ext/.su", + "/system/bin/.ext/su", + "/system/bin/failsafe/su", + "/system/sd/xbin/su", + "/system/usr/we-need-root/su", + "/cache/su", + "/data/su", + "/dev/su", + "/data/adb/magisk", + "/sbin/.magisk", + "/cache/.disable_magisk", + "/dev/.magisk.unblock", + "/cache/magisk.log", + "/data/adb/magisk.img", + "/data/adb/magisk.db", + "/data/adb/magisk_simple", + "/init.magisk.rc", + "/system/app/Superuser.apk", + "/system/etc/init.d/99SuperSUDaemon", + "/system/xbin/daemonsu", + "/system/xbin/ku.sud", + "/data/adb/ksu", + "/data/adb/ksud", + "/system/xbin/busybox", + "/system/app/Kinguser.apk" + ]), + + packages: new Set([ + "com.noshufou.android.su", + "com.noshufou.android.su.elite", + "eu.chainfire.supersu", + "com.koushikdutta.superuser", + "com.thirdparty.superuser", + "com.yellowes.su", + "com.koushikdutta.rommanager", + "com.koushikdutta.rommanager.license", + "com.dimonvideo.luckypatcher", + "com.chelpus.lackypatch", + "com.ramdroid.appquarantine", + "com.ramdroid.appquarantinepro", + "com.topjohnwu.magisk", + "me.weishu.kernelsu" + ]), + + commands: new Set([ + "su", + "which su", + "whereis su", + "locate su", + "find / -name su", + "mount", + "magisk", + "/system/bin/su", + "/system/xbin/su", + "/sbin/su", + "/su/bin/su" + ]), + + binaries: new Set([ + "su", + "busybox", + "magisk", + "supersu", + "ksud", + "daemonsu" + ]) + }; + + const Logger = { + prefix: "RootBypass: ", + info(message) { + console.log(`${this.prefix}${message}`); + }, + error(message, error) { + console.error(`${this.prefix}ERROR: ${message}`, error || ""); + } + }; + + function bypassNativeFileCheck() { + const fopen = Module.findExportByName("libc.so", "fopen"); + if (fopen) { + Interceptor.attach(fopen, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + if (retval.toInt32() !== 0) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked fopen: ${this.path}`); + retval.replace(ptr(0x0)); + } + } + } + }); + } + + const access = Module.findExportByName("libc.so", "access"); + if (access) { + Interceptor.attach(access, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + if (retval.toInt32() === 0) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked access: ${this.path}`); + retval.replace(ptr(-1)); + } + } + } + }); + } + + const stat = Module.findExportByName("libc.so", "stat"); + if (stat) { + Interceptor.attach(stat, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked stat: ${this.path}`); + retval.replace(ptr(-1)); + } + } + }); + } + + const lstat = Module.findExportByName("libc.so", "lstat"); + if (lstat) { + Interceptor.attach(lstat, { + onEnter(args) { + this.path = args[0].readUtf8String(); + }, + onLeave(retval) { + const path = this.path.toLowerCase(); + if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { + Logger.info(`Blocked lstat: ${this.path}`); + retval.replace(ptr(-1)); + } + } + }); + } + } + + function bypassJavaFileCheck() { + const UnixFileSystem = Java.use("java.io.UnixFileSystem"); + UnixFileSystem.checkAccess.implementation = function(file, access) { + const filename = file.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file access check: ${filename}`); + return false; + } + return this.checkAccess(file, access); + }; + + const File = Java.use("java.io.File"); + File.exists.implementation = function() { + const filename = this.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file exists check: ${filename}`); + return false; + } + return this.exists(); + }; + + File.length.implementation = function() { + const filename = this.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked file length check: ${filename}`); + return 0; + } + return this.length(); + }; + + const FileInputStream = Java.use("java.io.FileInputStream"); + FileInputStream.$init.overload('java.io.File').implementation = function(file) { + const filename = file.getAbsolutePath(); + if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { + Logger.info(`Blocked FileInputStream creation: ${filename}`); + throw new Java.use("java.io.FileNotFoundException").$new(filename); + } + return this.$init(file); + }; + } + + function setProp() { + try { + const Build = Java.use("android.os.Build"); + const fields = { + "TAGS": "release-keys", + "TYPE": "user", + "FINGERPRINT": CONFIG.fingerprint + }; + + Object.entries(fields).forEach(([field, value]) => { + const fieldObj = Build.class.getDeclaredField(field); + fieldObj.setAccessible(true); + fieldObj.set(null, value); + }); + + const system_property_get = Module.findExportByName("libc.so", "__system_property_get"); + if (system_property_get) { + Interceptor.attach(system_property_get, { + onEnter(args) { + this.key = args[0].readCString(); + this.ret = args[1]; + }, + onLeave(retval) { + const secureValue = CONFIG.secureProps[this.key]; + if (secureValue !== undefined) { + const valuePtr = Memory.allocUtf8String(secureValue); + Memory.copy(this.ret, valuePtr, secureValue.length + 1); + } + } + }); + } + + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('java.lang.String').implementation = function(cmd) { + if (cmd.startsWith("getprop ")) { + const prop = cmd.split(" ")[1]; + if (CONFIG.secureProps[prop]) { + Logger.info(`Blocked getprop command: ${cmd}`); + return null; + } + } + return this.exec(cmd); + }; + } catch (error) { + Logger.error("Error setting up build properties bypass", error); + } + } + + function bypassRootPackageCheck() { + const ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager"); + + ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(str, i) { + if (ROOT_INDICATORS.packages.has(str)) { + Logger.info(`Blocked package check: ${str}`); + str = "com.nonexistent.package"; + } + return this.getPackageInfo(str, i); + }; + + ApplicationPackageManager.getInstalledPackages.overload('int').implementation = function(flags) { + const packages = this.getInstalledPackages(flags); + const packageList = packages.toArray(); + const filteredPackages = packageList.filter(pkg => !ROOT_INDICATORS.packages.has(pkg.packageName.value)); + return Java.use("java.util.ArrayList").$new(filteredPackages); + }; + } + + function bypassShellCommands() { + try { + const ProcessBuilder = Java.use('java.lang.ProcessBuilder'); + ProcessBuilder.command.overload('java.util.List').implementation = function(commands) { + const cmdList = commands.toArray(); + if (cmdList.length > 0) { + const cmd = cmdList[0].toString(); + if (ROOT_INDICATORS.commands.has(cmd) || (cmdList.length > 1 && ROOT_INDICATORS.binaries.has(cmdList[1].toString()))) { + Logger.info(`Blocked ProcessBuilder command: ${cmdList.join(' ')}`); + return this.command(Java.use("java.util.Arrays").asList([""])); + } + } + return this.command(commands); + }; + + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0]; + if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1]))) { + Logger.info(`Blocked Runtime.exec command array: ${cmdArray.join(' ')}`); + return this.exec([""]); + } + } + return this.exec(cmdArray); + }; + + const ProcessImpl = Java.use("java.lang.ProcessImpl"); + ProcessImpl.start.implementation = function(cmdArray, env, dir, redirects, redirectErrorStream) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0].toString(); + const arg = cmdArray.length > 1 ? cmdArray[1].toString() : ""; + + if (ROOT_INDICATORS.commands.has(cmd) || ROOT_INDICATORS.binaries.has(arg)) { + Logger.info(`Blocked ProcessImpl command: ${cmdArray.join(' ')}`); + return ProcessImpl.start.call(this, [Java.use("java.lang.String").$new("")], env, dir, redirects, redirectErrorStream); + } + } + return ProcessImpl.start.call(this, cmdArray, env, dir, redirects, redirectErrorStream); + }; + } catch (error) { + Logger.error("Error setting up shell command bypass", error); + } + } + + Logger.info("Initializing root detection bypass..."); + bypassNativeFileCheck(); + bypassJavaFileCheck(); + setProp(); + bypassRootPackageCheck(); + bypassShellCommands(); + Logger.info("Root detection bypass initialized successfully"); +})(); From 7a50ac4691da67c41cd14fb07ffa1c6938f9f273 Mon Sep 17 00:00:00 2001 From: Riyad Mondol Date: Sat, 14 Jun 2025 05:11:03 +0600 Subject: [PATCH 4/7] Update README.md --- README.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7cfc239..704504a 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,15 @@ The scripts can automatically handle: 6. Use Frida to launch the app you're interested in with the scripts injected (starting with `config.js`). Which scripts to use is up to you, but for Android a good command to start with is: ```bash frida -U \ - -l ./config.js \ - -l ./native-connect-hook.js \ - -l ./native-tls-hook.js \ - -l ./android/android-proxy-override.js \ - -l ./android/android-system-certificate-injection.js \ - -l ./android/android-certificate-unpinning.js \ - -l ./android/android-certificate-unpinning-fallback.js \ - -f $PACKAGE_ID + -l ./config.js \ + -l ./native-connect-hook.js \ + -l ./native-tls-hook.js \ + -l ./android/android-proxy-override.js \ + -l ./android/android-system-certificate-injection.js \ + -l ./android/android-certificate-unpinning.js \ + -l ./android/android-certificate-unpinning-fallback.js \ + -l ./android/root_detection_bypass.js \ + -f $PACKAGE_ID ``` 7. Explore, examine & modify all the traffic you're interested in! If you have any problems, please [open an issue](https://github.com/httptoolkit/frida-interception-and-unpinning/issues/new) and help make these scripts even better. @@ -141,7 +142,14 @@ Each script includes detailed documentation on what it does and how it works in This script allows you to configure a list of possible IP addresses and a target port, and have the process test each address, and send a message to the Frida client for the first reachable address provided. This can be useful for automated configuration processes, if you don't know which IP address is best to use to reach the proxy server (your computer) from the target device (your phone). ---- +* `android/root_detection_bypass.js` + + Disables common root detection checks across native and Java layers to prevent detection of rooted Android devices. + + This script intercepts file system access, shell commands, and package lookups for known root indicators (like `su`, Magisk, and related apps), and fakes key system properties (`ro.secure`, `ro.debuggable`, etc.) to simulate a production environment. + + It blocks suspicious behavior like file existence checks and shell command execution, helping evade detection in apps using both standard and advanced root checks. + These scripts are part of [a broader HTTP Toolkit project](https://httptoolkit.com/blog/frida-mobile-interception-funding/), funded through the [NGI Zero Entrust Fund](https://nlnet.nl/entrust), established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more on the [NLnet project page](https://nlnet.nl/project/F3-AppInterception#ack). From 318725026a9c4b2311aa9e4100bd895a2007b274 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 17 Jun 2025 19:39:55 +0200 Subject: [PATCH 5/7] Make Android root detection match our other logs --- ...s.js => android-disable-root-detection.js} | 234 ++++++++++-------- 1 file changed, 127 insertions(+), 107 deletions(-) rename android/{root_detection_bypass.js => android-disable-root-detection.js} (54%) diff --git a/android/root_detection_bypass.js b/android/android-disable-root-detection.js similarity index 54% rename from android/root_detection_bypass.js rename to android/android-disable-root-detection.js index b0dd8b2..d3331f0 100644 --- a/android/root_detection_bypass.js +++ b/android/android-disable-root-detection.js @@ -1,5 +1,11 @@ (() => { - 'use strict'; + let loggedRootDetectionWarning = false; + function logFirstRootDetection() { + if (!loggedRootDetectionWarning) { + console.log(" => Blocked possible root detection checks. Enable DEBUG_MODE for more details."); + loggedRootDetectionWarning = true; + } + } const CONFIG = { fingerprint: "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys", @@ -51,7 +57,7 @@ "/system/xbin/busybox", "/system/app/Kinguser.apk" ]), - + packages: new Set([ "com.noshufou.android.su", "com.noshufou.android.su.elite", @@ -93,16 +99,6 @@ ]) }; - const Logger = { - prefix: "RootBypass: ", - info(message) { - console.log(`${this.prefix}${message}`); - }, - error(message, error) { - console.error(`${this.prefix}ERROR: ${message}`, error || ""); - } - }; - function bypassNativeFileCheck() { const fopen = Module.findExportByName("libc.so", "fopen"); if (fopen) { @@ -114,7 +110,9 @@ if (retval.toInt32() !== 0) { const path = this.path.toLowerCase(); if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked fopen: ${this.path}`); + if (DEBUG_MODE) { + console.log(`Blocked possible root-detection: fopen ${this.path}`); + } else logFirstRootDetection(); retval.replace(ptr(0x0)); } } @@ -132,7 +130,9 @@ if (retval.toInt32() === 0) { const path = this.path.toLowerCase(); if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked access: ${this.path}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: access ${this.path}`); + } else logFirstRootDetection(); retval.replace(ptr(-1)); } } @@ -149,7 +149,9 @@ onLeave(retval) { const path = this.path.toLowerCase(); if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked stat: ${this.path}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: stat ${this.path}`); + } else logFirstRootDetection(); retval.replace(ptr(-1)); } } @@ -165,7 +167,9 @@ onLeave(retval) { const path = this.path.toLowerCase(); if (ROOT_INDICATORS.paths.has(this.path) || path.includes("magisk") || path.includes("/su") || path.endsWith("/su")) { - Logger.info(`Blocked lstat: ${this.path}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: lstat ${this.path}`); + } else logFirstRootDetection(); retval.replace(ptr(-1)); } } @@ -178,7 +182,9 @@ UnixFileSystem.checkAccess.implementation = function(file, access) { const filename = file.getAbsolutePath(); if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file access check: ${filename}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: filesystem access check for ${filename}`); + } else logFirstRootDetection(); return false; } return this.checkAccess(file, access); @@ -188,7 +194,9 @@ File.exists.implementation = function() { const filename = this.getAbsolutePath(); if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file exists check: ${filename}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: file exists check for ${filename}`); + } else logFirstRootDetection(); return false; } return this.exists(); @@ -197,7 +205,9 @@ File.length.implementation = function() { const filename = this.getAbsolutePath(); if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked file length check: ${filename}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: file length check for ${filename}`); + } else logFirstRootDetection(); return 0; } return this.length(); @@ -207,7 +217,9 @@ FileInputStream.$init.overload('java.io.File').implementation = function(file) { const filename = file.getAbsolutePath(); if (ROOT_INDICATORS.paths.has(filename) || filename.includes("magisk") || filename.includes("su")) { - Logger.info(`Blocked FileInputStream creation: ${filename}`); + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: file stream for ${filename}`); + } else logFirstRootDetection(); throw new Java.use("java.io.FileNotFoundException").$new(filename); } return this.$init(file); @@ -215,60 +227,63 @@ } function setProp() { - try { - const Build = Java.use("android.os.Build"); - const fields = { - "TAGS": "release-keys", - "TYPE": "user", - "FINGERPRINT": CONFIG.fingerprint - }; + const Build = Java.use("android.os.Build"); + const fields = { + "TAGS": "release-keys", + "TYPE": "user", + "FINGERPRINT": CONFIG.fingerprint + }; - Object.entries(fields).forEach(([field, value]) => { - const fieldObj = Build.class.getDeclaredField(field); - fieldObj.setAccessible(true); - fieldObj.set(null, value); - }); + Object.entries(fields).forEach(([field, value]) => { + const fieldObj = Build.class.getDeclaredField(field); + fieldObj.setAccessible(true); + fieldObj.set(null, value); + }); - const system_property_get = Module.findExportByName("libc.so", "__system_property_get"); - if (system_property_get) { - Interceptor.attach(system_property_get, { - onEnter(args) { - this.key = args[0].readCString(); - this.ret = args[1]; - }, - onLeave(retval) { - const secureValue = CONFIG.secureProps[this.key]; - if (secureValue !== undefined) { - const valuePtr = Memory.allocUtf8String(secureValue); - Memory.copy(this.ret, valuePtr, secureValue.length + 1); - } - } - }); - } - - const Runtime = Java.use('java.lang.Runtime'); - Runtime.exec.overload('java.lang.String').implementation = function(cmd) { - if (cmd.startsWith("getprop ")) { - const prop = cmd.split(" ")[1]; - if (CONFIG.secureProps[prop]) { - Logger.info(`Blocked getprop command: ${cmd}`); - return null; + const system_property_get = Module.findExportByName("libc.so", "__system_property_get"); + if (system_property_get) { + Interceptor.attach(system_property_get, { + onEnter(args) { + this.key = args[0].readCString(); + this.ret = args[1]; + }, + onLeave(retval) { + const secureValue = CONFIG.secureProps[this.key]; + if (secureValue !== undefined) { + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: system_property_get ${this.key}`); + } else logFirstRootDetection(); + const valuePtr = Memory.allocUtf8String(secureValue); + Memory.copy(this.ret, valuePtr, secureValue.length + 1); } } - return this.exec(cmd); - }; - } catch (error) { - Logger.error("Error setting up build properties bypass", error); + }); } + + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('java.lang.String').implementation = function(cmd) { + if (cmd.startsWith("getprop ")) { + const prop = cmd.split(" ")[1]; + if (CONFIG.secureProps[prop]) { + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: getprop ${prop}`); + } else logFirstRootDetection(); + return null; + } + } + return this.exec(cmd); + }; } function bypassRootPackageCheck() { const ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager"); - + ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(str, i) { if (ROOT_INDICATORS.packages.has(str)) { - Logger.info(`Blocked package check: ${str}`); - str = "com.nonexistent.package"; + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: package info for ${str}`); + } else logFirstRootDetection(); + str = "invalid.example.nonexistent.package"; } return this.getPackageInfo(str, i); }; @@ -282,55 +297,60 @@ } function bypassShellCommands() { - try { - const ProcessBuilder = Java.use('java.lang.ProcessBuilder'); - ProcessBuilder.command.overload('java.util.List').implementation = function(commands) { - const cmdList = commands.toArray(); - if (cmdList.length > 0) { - const cmd = cmdList[0].toString(); - if (ROOT_INDICATORS.commands.has(cmd) || (cmdList.length > 1 && ROOT_INDICATORS.binaries.has(cmdList[1].toString()))) { - Logger.info(`Blocked ProcessBuilder command: ${cmdList.join(' ')}`); - return this.command(Java.use("java.util.Arrays").asList([""])); - } + const ProcessBuilder = Java.use('java.lang.ProcessBuilder'); + ProcessBuilder.command.overload('java.util.List').implementation = function(commands) { + const cmdArray = commands.toArray(); + if (cmdArray.length > 0) { + const cmd = cmdArray[0].toString(); + if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1].toString()))) { + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: ProcessBuilder with ${cmdArray.join(' ')}`); + } else logFirstRootDetection(); + return this.command(Java.use("java.util.Arrays").asList([""])); } - return this.command(commands); - }; + } + return this.command(commands); + }; - const Runtime = Java.use('java.lang.Runtime'); - Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) { - if (cmdArray.length > 0) { - const cmd = cmdArray[0]; - if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1]))) { - Logger.info(`Blocked Runtime.exec command array: ${cmdArray.join(' ')}`); - return this.exec([""]); - } + const Runtime = Java.use('java.lang.Runtime'); + Runtime.exec.overload('[Ljava.lang.String;').implementation = function(cmdArray) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0]; + if (ROOT_INDICATORS.commands.has(cmd) || (cmdArray.length > 1 && ROOT_INDICATORS.binaries.has(cmdArray[1]))) { + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: Runtime.exec for ${cmdArray.join(' ')}`); + } else logFirstRootDetection(); + return this.exec([""]); } - return this.exec(cmdArray); - }; + } + return this.exec(cmdArray); + }; - const ProcessImpl = Java.use("java.lang.ProcessImpl"); - ProcessImpl.start.implementation = function(cmdArray, env, dir, redirects, redirectErrorStream) { - if (cmdArray.length > 0) { - const cmd = cmdArray[0].toString(); - const arg = cmdArray.length > 1 ? cmdArray[1].toString() : ""; - - if (ROOT_INDICATORS.commands.has(cmd) || ROOT_INDICATORS.binaries.has(arg)) { - Logger.info(`Blocked ProcessImpl command: ${cmdArray.join(' ')}`); - return ProcessImpl.start.call(this, [Java.use("java.lang.String").$new("")], env, dir, redirects, redirectErrorStream); - } + const ProcessImpl = Java.use("java.lang.ProcessImpl"); + ProcessImpl.start.implementation = function(cmdArray, env, dir, redirects, redirectErrorStream) { + if (cmdArray.length > 0) { + const cmd = cmdArray[0].toString(); + const arg = cmdArray.length > 1 ? cmdArray[1].toString() : ""; + + if (ROOT_INDICATORS.commands.has(cmd) || ROOT_INDICATORS.binaries.has(arg)) { + if (DEBUG_MODE) { + console.debug(`Blocked possible root detection: ProcessImpl.start for ${cmdArray.join(' ')}`); + } else logFirstRootDetection(); + return ProcessImpl.start.call(this, [Java.use("java.lang.String").$new("")], env, dir, redirects, redirectErrorStream); } - return ProcessImpl.start.call(this, cmdArray, env, dir, redirects, redirectErrorStream); - }; - } catch (error) { - Logger.error("Error setting up shell command bypass", error); - } + } + return ProcessImpl.start.call(this, cmdArray, env, dir, redirects, redirectErrorStream); + }; } - Logger.info("Initializing root detection bypass..."); - bypassNativeFileCheck(); - bypassJavaFileCheck(); - setProp(); - bypassRootPackageCheck(); - bypassShellCommands(); - Logger.info("Root detection bypass initialized successfully"); + try { + bypassNativeFileCheck(); + bypassJavaFileCheck(); + setProp(); + bypassRootPackageCheck(); + bypassShellCommands(); + console.log("== Disabled Android root detection =="); + } catch (error) { + console.error("\n !!! Error setting up root detection bypass !!!", error); + } })(); From f41596752d2ea1a0009caf1fe1fb49e6384b0e55 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 17 Jun 2025 20:03:19 +0200 Subject: [PATCH 6/7] Match Android fingerprint where possible while hiding root --- android/android-disable-root-detection.js | 27 +++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/android/android-disable-root-detection.js b/android/android-disable-root-detection.js index d3331f0..7b30640 100644 --- a/android/android-disable-root-detection.js +++ b/android/android-disable-root-detection.js @@ -7,8 +7,9 @@ } } + const BUILD_FINGERPRINT_REGEX = /^([\w.-]+\/[\w.-]+\/[\w.-]+):([\w.]+\/[\w.-]+\/[\w.-]+):(\w+\/[\w,.-]+)$/; + const CONFIG = { - fingerprint: "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys", secureProps: { "ro.secure": "1", "ro.debuggable": "0", @@ -228,10 +229,32 @@ function setProp() { const Build = Java.use("android.os.Build"); + + // We do a little work to make the minimum changes required to hide in the BUILD fingerprint, + // but otherwise keep matching the real device wherever possible. + const realFingerprint = Build.FINGERPRINT.value; + + const fingerprintMatch = BUILD_FINGERPRINT_REGEX.exec(realFingerprint); + let fixedFingerprint; + if (fingerprintMatch) { + let [, device, versions, tags] = BUILD_FINGERPRINT_REGEX.exec(realFingerprint); + tags = 'user/release-keys'; // Should always be the case in production builds + if (device.includes('generic') || device.includes('sdk') || device.includes('lineage')) { + device = 'google/raven/raven'; + } + + fixedFingerprint = `${device}:${versions}:${tags}`; + } else { + console.warn(`Unexpected BUILD fingerprint format: ${realFingerprint}`); + // This should never happen in theory (the format is standard), but just in case, + // we use this fallback fingerprint: + fixedFingerprint = "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys"; + } + const fields = { "TAGS": "release-keys", "TYPE": "user", - "FINGERPRINT": CONFIG.fingerprint + "FINGERPRINT": fixedFingerprint }; Object.entries(fields).forEach(([field, value]) => { From 2c440d377562c4b33ad12ab4047d20fcf3fb8577 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 17 Jun 2025 20:03:46 +0200 Subject: [PATCH 7/7] Document the root bypass script --- README.md | 40 +++++++++++++---------- android/android-disable-root-detection.js | 15 +++++++++ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 704504a..0303781 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ The scripts can automatically handle: * Injecting a given CA certificate into the system trust stores so they're trusted in connections by default. * Patching many (all?) known certificate pinning and certificate transparency tools, to allow interception by your CA certificate even when this is actively blocked. * On Android, as a fallback: auto-detection of remaining pinning failures, to attempt auto-patching of obfuscated certificate pinning (in fully obfuscated apps, the first request may fail, but this will trigger additional patching so that all subsequent requests work correctly). +* Disabling many common root & jailbreak detections. ## Android Getting Started Guide @@ -31,15 +32,15 @@ The scripts can automatically handle: 6. Use Frida to launch the app you're interested in with the scripts injected (starting with `config.js`). Which scripts to use is up to you, but for Android a good command to start with is: ```bash frida -U \ - -l ./config.js \ - -l ./native-connect-hook.js \ - -l ./native-tls-hook.js \ - -l ./android/android-proxy-override.js \ - -l ./android/android-system-certificate-injection.js \ - -l ./android/android-certificate-unpinning.js \ - -l ./android/android-certificate-unpinning-fallback.js \ - -l ./android/root_detection_bypass.js \ - -f $PACKAGE_ID + -l ./config.js \ + -l ./native-connect-hook.js \ + -l ./native-tls-hook.js \ + -l ./android/android-proxy-override.js \ + -l ./android/android-system-certificate-injection.js \ + -l ./android/android-certificate-unpinning.js \ + -l ./android/android-certificate-unpinning-fallback.js \ + -l ./android/disable-root-detection.js \ + -f $PACKAGE_ID ``` 7. Explore, examine & modify all the traffic you're interested in! If you have any problems, please [open an issue](https://github.com/httptoolkit/frida-interception-and-unpinning/issues/new) and help make these scripts even better. @@ -62,6 +63,7 @@ The scripts can automatically handle: frida -U \ -l ./config.js \ -l ./ios/ios-connect-hook.js \ + -l ./ios/ios-disable-detection.js \ -l ./native-tls-hook.js \ -l ./native-connect-hook.js \ -f $APP_ID @@ -128,6 +130,14 @@ Each script includes detailed documentation on what it does and how it works in Detects unhandled certificate validation failures, and attempts to handle unknown unrecognized cases with auto-generated fallback patches. This is more experimental and could be slightly unpredictable, but is very helpful for obfuscated cases, and in general will either fix pinning issues (after one initial failure) or will at least highlight code for further reverse engineering in the Frida log output. This script shares some logic with `android-certificate-unpinning.js`, and cannot be used standalone - if you want to use this script, you'll need to include the non-fallback unpinning script too. + * `android-disable-root-detection.js` + + Disables common root detection checks across native and Java layers to prevent detection of rooted Android devices. + + This script intercepts file system access, shell commands, and package lookups for known root indicators (like `su`, Magisk, and related apps), and fakes key system properties (`ro.secure`, `ro.debuggable`, etc.) to simulate a production environment. + + It blocks suspicious behavior like file existence checks and shell command execution, helping evade detection in apps using both standard and advanced root checks. + * `ios/` * `ios-connect-hook.js` @@ -136,20 +146,16 @@ Each script includes detailed documentation on what it does and how it works in This is a low-level hook that applies to _all_ network connections. This ensures that all connections are forcibly redirected to the target proxy server, even those which ignore proxy settings or make other raw socket connections. + * `ios-disable-detection.js` + + Disables JailMonkey jailbreak detection. + * `utilities/test-ip-connectivity.js` You probably don't want to use this normally as part of interception itself, but it can be very useful as part of your configuration setup. This script allows you to configure a list of possible IP addresses and a target port, and have the process test each address, and send a message to the Frida client for the first reachable address provided. This can be useful for automated configuration processes, if you don't know which IP address is best to use to reach the proxy server (your computer) from the target device (your phone). -* `android/root_detection_bypass.js` - - Disables common root detection checks across native and Java layers to prevent detection of rooted Android devices. - - This script intercepts file system access, shell commands, and package lookups for known root indicators (like `su`, Magisk, and related apps), and fakes key system properties (`ro.secure`, `ro.debuggable`, etc.) to simulate a production environment. - - It blocks suspicious behavior like file existence checks and shell command execution, helping evade detection in apps using both standard and advanced root checks. - These scripts are part of [a broader HTTP Toolkit project](https://httptoolkit.com/blog/frida-mobile-interception-funding/), funded through the [NGI Zero Entrust Fund](https://nlnet.nl/entrust), established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more on the [NLnet project page](https://nlnet.nl/project/F3-AppInterception#ack). diff --git a/android/android-disable-root-detection.js b/android/android-disable-root-detection.js index 7b30640..017931e 100644 --- a/android/android-disable-root-detection.js +++ b/android/android-disable-root-detection.js @@ -1,3 +1,18 @@ +/************************************************************************************************** + * + * This script defines a large set of root detection bypasses for Android. Hooks included here + * block detection of many known root indicators, including file paths, package names, commands, + * notably binaries, and system properties. + * + * Enable DEBUG_MODE to see debug output for each bypassed check. + * + * Source available at https://github.com/httptoolkit/frida-interception-and-unpinning/ + * SPDX-License-Identifier: AGPL-3.0-or-later + * SPDX-FileCopyrightText: Tim Perry + * SPDX-FileCopyrightText: Riyad Mondal + * + *************************************************************************************************/ + (() => { let loggedRootDetectionWarning = false; function logFirstRootDetection() {