Breaking Flutter: A Pentester’s Guide to Dart, Snapshots, and TLS Bypasses

5 min read

May 4, 2025

Breaking Flutter: A Pentester’s Guide to Dart, Snapshots, and TLS Bypasses

Table of contents

Hey everyone!
Hope you're doing great.

Last week, I shared some key Kerberos attack techniques for pentesters.
This time, we’re switching gears to something more mobile: Flutter, and specifically, how to break it.

Lately, I’ve been auditing several Flutter apps and wanted to share some tips I’ve discovered during the process.
Whether you’re analyzing a Flutter app during a mobile engagement or just curious about how Flutter works under the hood, this post will give you practical techniques to reverse and poke at them like a pro.

Let’s jump in.

Quick Theory: How Flutter Apps Actually Work

Before diving into recon techniques, it’s important to understand what makes Flutter apps different under the hood and why reversing them isn't as straightforward as with regular Android apps.

Flutter uses Dart and AOT Compilation

Flutter apps are written in Dart. When building for release (production), Dart code is compiled ahead of time (AOT) into native code. On Android, this results in a native shared object called libapp.so, which contains the app’s business logic. This means:

  • There’s no .dex or .smali representation of the Dart code.
  • Tools like jadx won’t show the actual business logic.
  • You'll need to analyze native libraries directly or inspect Dart snapshots in non-release builds.

The Flutter Engine is Embedded

Every Flutter app bundles the Flutter engine, which lives in a shared object called libflutter.so. This handles rendering, input, animation, and communication between Dart and native code.

  • libflutter.so is shared across all Flutter apps.
  • It doesn't include project-specific logic, but it's useful when hooking native functionality with Frida.

Communication Happens via Platform Channels

Flutter uses platform channels (e.g., MethodChannel, EventChannel) to communicate between Dart and the native Android or iOS layer. These channels are critical when you want to hook authentication, storage, or cryptographic operations, as Dart often delegates those to native code.

Snapshots in Debug and Profile Builds

In debug or profile builds, libapp.so might not be present. Instead, the app runs using Dart snapshot files that are interpreted at runtime:

  • kernel_blob.bin
  • isolate_snapshot_data
  • vm_snapshot_data

These files can still expose class names, symbols, and logic structure. However, you’ll need specific tools or scripts to extract anything meaningful from them.

Recon Techniques for Flutter Apps

Before jumping into traffic interception, it’s often a good idea to understand the app’s structure, logic, and surface area. Flutter apps complicate this due to their native compilation, but there are still effective techniques you can use to break them open.

Full APK Decompilation with apkx

apkx automates the extraction of all APK internals, including DEX, resources, native libs, and converts the DEX to JAR for easy navigation. Great starting point to explore native libraries and any embedded Java/Kotlin logic.

apkx target.apk

Static Analysis with MobSF

MobSF gives you a fast overview of the app: permissions, activities, trackers, exposed components, and network endpoints. Even with Flutter, this helps uncover basic misconfigurations or embedded secrets.

Native Reversing with Ghidra

Flutter’s Dart code is usually compiled into libapp.so, which holds the AOT-compiled logic of the app. Tools like jadx won’t help much here. Instead, load the native library into Ghidra to reverse engineer low-level logic, look for method names, strings, and identify Flutter plugins or obfuscated behavior.

Dart Snapshot Inspection

Sometimes you’ll find files like kernel_blob.bin, isolate_snapshot_data, or vm_snapshot_data inside the APK. These contain compiled Dart bytecode. With custom tools or scripts, you can try to extract readable Dart symbols or identify class/function names.

Manual Recon with jadx

While most business logic is in Dart, many Flutter apps still include Java-based plugins (e.g. for network or crypto). jadx is useful for inspecting those native interfaces, especially when combined with Frida hooks later on.

How to Intercept Traffic from Non-Proxy Aware Flutter Apps

So, you install the Flutter app you want to test, set up your proxy, route your device’s traffic through your Kali box... and nothing. No requests in Burp, no useful logs. What’s going on?

The issue?
Flutter apps are often non-proxy aware, meaning they completely ignore your system proxy settings.

I plan to write a dedicated article on this soon, but here’s a quick overview of how to handle it:

Set up an OpenVPN server

This allows you to tunnel all traffic from the target device through a VPN that redirects requests to your Burp proxy.

Create a controlled Wi-Fi access point

Use a device like a Kali box or Raspberry Pi to host a rogue access point. Then configure iptables or redir to transparently forward traffic to your proxy.

Once you have traffic properly routed, you’ll most likely encounter TLS pinning. That’s where Frida becomes essential.

Use this Frida script to disable Flutter’s TLS verification

NVISO’s Flutter TLS Bypass
GitHub: https://github.com/NVISOsecurity/disable-flutter-tls-verification

This script often works out of the box and patches the Flutter engine to disable certificate validation. However, in my experience, it tends to work more reliably on iOS than on Android. Your mileage may vary depending on the Flutter version and the target device.

Custom plugins may require extra work

Sometimes the app uses a plugin that handles its own TLS logic. In those cases, the generic Frida patch won’t be enough. Use tools like jadx to explore the code and locate certificate pinning implementations.

One plugin I’ve run into frequently is:
https://github.com/diefferson/http_certificate_pinning

To bypass it, you can try a Frida script like this one:
https://codeshare.frida.re/@incogbyte/android-mix-sslunpin-bypass/

Important: the class name used in the original repo is now diefferson.http_certificate_pinning.HttpCertificatePinningPlugin.
Most public Frida bypasses still reference the old class name HttpCertificatePinning, so if the script fails, check for that.

Optional: Try ReFlutter for Dart snapshot extraction

You can also try ReFlutter to extract and reconstruct Dart snapshot files like isolate_snapshot_data or kernel_blob.bin.
It attempts to rebuild the original Dart code into a readable form.

That said, I haven’t had much luck getting useful output from it in practice, especially with recent versions of Flutter. Still, it’s worth trying in case you get lucky.

Final Thoughts

That’s it for this post. Flutter may look different on the surface, but with the right tools and mindset, it becomes just another platform you can analyze and break effectively.

As I mentioned last week, the blog post for this week is focused on Slither’s API. It covers how to use it to create custom detectors and analyze smart contracts in depth.
You can check it out here: Slither API Deep Dive.

Let me know what you'd like to see next, especially if you're into mobile or smart contract hacking.

References

For setting up traffic interception with Burp and OpenVPN, check out this detailed guide:
Intercepting HTTP Traffic with OpenVPN on Android – InfoSec Writeups

The OWASP Mobile Security Testing Guide also covers this technique here:
OWASP MASTG – MASTG-TECH-0109

Chapters

Botón Anterior
Kerberos Tactics Every Pentester Should Know

Previous Issue

Inside the Request: From Basic SSRF to Internal Takeover

Next Issue

Enjoyed the article?

Subscribe to the newsletter and get technical insights, cybersecurity tips, and development content straight to your inbox. Or support my work with a coffee ☕ if you found it useful!

📫 Subscribe now ☕ Buy me a coffee