Bypass Talsec RASP and Root Detection

by
4 views 5883815f...

Description

This Frida script bypasses Talsec (FreeRASP) security mechanisms in Flutter-based Android applications by neutralizing the event reporting channel (talsec.app/freerasp/events), disabling root detection (via File and Runtime.exec), debugger checks (Debug.isDebuggerConnected), and exit/kill-based shutdowns (System.exit, Process.killProcess). Useful for dynamic analysis, reverse engineering, or testing protected apps in a controlled environment.

How to Use

Download the script and run it with Frida CLI:

Download Script

Then run with Frida:

frida -U -f YOUR_PACKAGE_NAME -l bypass-talsec-rasp-and-root-detection.js

Replace YOUR_PACKAGE_NAME with the target app's package name.

Source Code

JavaScript
console.log("[.] Starting Flutter Talsec Bypass Script...");

Java.perform(function() {

    /**
     * ───────────────────────────────────────────────
     * 1. BYPASS EVENT CHANNEL TALSEC (Flutter Plugin)
     * ───────────────────────────────────────────────
     * Neutralizes 'talsec.app/freerasp/events' EventChannel
     * so no threat events are propagated to Dart side.
     */
    try {
        const EventChannel = Java.use('io.flutter.plugin.common.EventChannel');
        const StreamHandler = Java.use('io.flutter.plugin.common.EventChannel$StreamHandler');

        EventChannel.setStreamHandler.implementation = function(handler) {
            let channelName = null;
            let obfuscatedFieldName = null;

            try {
                const fields = this.getClass().getDeclaredFields();
                for (let i = 0; i < fields.length; i++) {
                    const field = fields[i];
                    field.setAccessible(true);
                    const potentialName = field.get(this);
                    if (potentialName && potentialName.toString() === 'talsec.app/freerasp/events') {
                        channelName = potentialName.toString();
                        obfuscatedFieldName = field.getName();
                        break;
                    }
                }
            } catch (e) {
                console.log('[-] Failed to inspect EventChannel fields: ' + e.message);
            }

            if (channelName) {
                console.log(`[+] Found Talsec event channel ('${obfuscatedFieldName}'). Neutralizing stream handler.`);

                const MyStreamHandler = Java.registerClass({
                    name: 'com.example.MyStreamHandler',
                    implements: [StreamHandler],
                    methods: {
                        onListen: function(args, events) {
                            console.log('[+] Talsec StreamHandler.onListen called. Swallowing events.');
                        },
                        onCancel: function(args) {
                            console.log('[+] Talsec StreamHandler.onCancel called.');
                        }
                    }
                });

                this.setStreamHandler(MyStreamHandler.$new());
                return;
            }

            // If not Talsec, proceed as usual
            this.setStreamHandler(handler);
        };
    } catch (err) {
        console.log('[-] Failed to hook EventChannel: ' + err.message);
    }


    /**
     * ───────────────────────────────────────────────
     * 2. ROOT DETECTION BYPASS - FILE PATHS
     * ───────────────────────────────────────────────
     * Override File(String path) constructor to fake
     * existence of known root binaries.
     */
    try {
        var File = Java.use('java.io.File');
        var suPaths = [
            "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su",
            "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su",
            "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su",
            "/su/bin/su", "/su/xbin/su", "/su/sbin/su", "/system/su",
            "/system/usr/we-need-root/su", "/cache/su", "/data/su", "/dev/su"
        ];

        File.$init.overload('java.lang.String').implementation = function(path) {
            if (suPaths.indexOf(path) > -1) {
                console.log('[+] Bypassing root check for file: ' + path);
                return this.$init.call(this, '/nonexistent');
            }
            return this.$init.call(this, path);
        };
    } catch (err) {
        console.log('[-] Root detection bypass (File) failed: ' + err.message);
    }


    /**
     * ───────────────────────────────────────────────
     * 3. DEBUGGER DETECTION BYPASS
     * ───────────────────────────────────────────────
     * Prevent app from detecting attached debugger.
     */
    try {
        var Debug = Java.use('android.os.Debug');
        Debug.isDebuggerConnected.implementation = function() {
            console.log('[+] Bypassing Debug.isDebuggerConnected()');
            return false;
        };
    } catch (err) {
        console.log('[-] Debugger detection bypass failed: ' + err.message);
    }


    /**
     * ───────────────────────────────────────────────
     * 4. EXIT PREVENTION HOOKS
     * ───────────────────────────────────────────────
     * Prevent the app from forcefully exiting.
     */
    try {
        const System = Java.use('java.lang.System');
        System.exit.implementation = function(status) {
            console.log(`[+] Bypassing System.exit(${status})`);
        };
    } catch (err) {
        console.log('[-] System.exit bypass failed: ' + err.message);
    }

    try {
        const Process = Java.use('android.os.Process');
        Process.killProcess.implementation = function(pid) {
            console.log(`[+] Bypassing Process.killProcess(${pid})`);
        };
    } catch (err) {
        console.log('[-] Process.killProcess bypass failed: ' + err.message);
    }


    /**
     * ───────────────────────────────────────────────
     * 5. ROOT DETECTION BYPASS - RUNTIME EXEC
     * ───────────────────────────────────────────────
     * Prevent Runtime.exec("su") from succeeding.
     */
    try {
        const Runtime = Java.use('java.lang.Runtime');
        const exec = Runtime.exec.overload('java.lang.String');

        exec.implementation = function(command) {
            if (command.includes('su')) {
                console.log(`[+] Bypassing root check (Runtime.exec): ${command}`);
                throw Java.use('java.io.IOException').$new('Cannot run program "su", no such file or directory');
            }
            return exec.call(this, command);
        };
    } catch (err) {
        console.log('[-] Runtime.exec bypass failed: ' + err.message);
    }

});
Share this script:
Twitter LinkedIn

Comments

Login or Sign up to leave a comment.
Loading comments...