The native binary challenge: Analyzing Dart code

Unlike React Native, which bundles JavaScript, Flutter compiles Dart code directly into a native library (like libapp.so on Android). If you try to decompile this library with standard tools like JADX, you will only see the native wrapper code, not your Dart logic.

To analyze the app, we use tools like reFlutter or Ghidra. The reFlutter tool patches the Flutter engine inside the APK, allowing us to inspect the Dart class structure and export all API endpoints.

Once we identify the memory offsets for key functions, we use Frida scripts to hook into the runtime. This allows us to view variables, change return values, and extract cryptographic keys in memory.

Pentest finding

Frida hook bypasses pin validation in Flutter wallet

On a Flutter-based mobile wallet app, the transaction approval PIN was checked locally before triggering the API. We used a Frida script to hook the validation method inside libapp.so. By replacing the native return value with a hardcoded true, we bypassed the local PIN entry screen and authorized payments without knowing the code.

Defeating Flutter SSL Pinning

Flutter does not use the host operating system's network stack. Instead, Dart compiles its own HTTP library (BoringSSL). Because of this, standard Android proxy settings and system trust certificates are ignored by the app.

To capture the network traffic, we use custom Frida scripts that target the BoringSSL validation offsets. By locating the verification functions in the compiled Dart engine and patching them at runtime, we force the application to send all traffic through our Burp Suite proxy.

// Example Frida logic to bypass BoringSSL check in Flutter (simplified)
var target_function_offset = 0x1a2b3c; // Offset for ssl_verify_peer_cert
Interceptor.replace(Module.findExportByName("libflutter.so", "ssl_verify_peer_cert") || 
                    Module.getBaseAddress("libflutter.so").add(target_function_offset), 
    new NativeCallback(function () {
        console.log("[SSL Verify] Bypass triggered");
        return 0; // Return verification success
    }, 'int', []));

Securing your Flutter application

To protect your Flutter application from dynamic analysis, make sure you implement these controls:

Get your Flutter app audited

Flutter apps are complex to audit because of their native compilation. Automated scanners will miss most binary vulnerabilities and logic flaws. You need manual penetration testing.

At Simpa Labs, we specialize in reverse-engineering mobile binaries in Nigeria and globally. We will check your APIs, test your local storage, and audit your Dart code to make sure it is secure.

Book a Flutter Pentest