When reverse engineering mobile applications, Flutter apps present unique challenges compared to traditional native apps.
In this guide, I’ll walk through the complete process of extracting and analyzing Flutter application code from APK files.
There are two main components you might be interested in:
- Native Flutter plugins - These contain platform-specific code implementing features like App Attest for iOS and Play Integrity API for Android. They expose functions via Platform Channels that can be called by Flutter code.
- Flutter application code - The Dart code that runs the app logic, which is typically identical between iOS and Android versions.
Here, we’ll focus on the Flutter application code, since the native plugins are trivial to dump and read using jadx.
Flutter reverse-engineering is a moving target. In this post, I’m just showing what worked for me :).
Note on Dynamic analysis
We won’t be covering dynamic analysis today.
Getting the APK of your target app
My favorite way of getting an APK is to install it on a phone, and then pulling it.
First, install the target app on your development phone via Aptoide or Google Play Store.
Then extract the APK:
adb shell pm list packagesadb shell pm path <package.name># Save the output paths to a text file and run "adb pull" on each path.# This will give you a bunch of APKs that you'll need to merge.You’ll often get multiple APK files, that you can merge like so:
cd pulled # this folder should contain all the .apk that you want to mregeapkeditor m -i ./ -o ../pulled_merged.apkThis produces a single merged APK in ../pulled_merged.apk.
Extracting the code with blutter
First, install blutter:
cd blutter
# Install Python dependenciesuv venvsource .venv/bin/activate.fishuv pip install requestsuv pip install pyelftoolsRun Blutter on the APK:
mkdir out# Prioritize system's ninja over depot_tools' (in case you're doing some Chromium development on the side)fish_add_path /usr/bin# This will compile some C++ components, and you might have to install some dependentiesuv run blutter.py ./pulled_merged.apk out/Troubleshooting blutter C++ compilation errors
Ensure you’re using the vanilla ninja build tool from your system rather than the one from depot_tools (in case you’re working on Chromium on the side :)).
Reading the decompiled code
Reading the code with your bare hands
You will get the following directories in ./out:
asm/*: libapp assemblies with symbolsblutter_frida.js: the frida script template for the target applicationobjs.txt: complete (nested) dump of Object from Object Poolpp.txt: all Dart objects in Object Pool
The interesting part is ./asm/*, which will tell you your app structure’s and logic.
Reading the code with IDA Pro
Blutter also generates a Python script that can be used with IDA to add symbols to libapp.so.
Sadly, it doesn’t support Ghidra yet.
For now, reading the decompiled output from the asm folder in the Blutter output is possible; it just takes a lot of patience.
Conclusion
In 2026, Flutter reverse-engineering is still a pain.
I am not sure how well IDA Pro works, but I assume it’s good.
If one wanted to significantly improve things for everyone, they could write an integration between Blutter and Ghidra.