[](https://github.com/Impact-I/reFlutter/stargazers)
<p align="center"><img src="https://user-images.githubusercontent.com/87244850/135659542-22bb8496-bf26-4e25-b7c1-ffd8fc0cea10.png" width="75%"/></p>
**Read more on the blog:** <https://swarm.ptsecurity.com/fork-bomb-for-flutter/>
This framework helps with Flutter apps reverse engineering using the patched version of the Flutter library which is already compiled and ready for app repacking. This library has snapshot deserialization process modified to allow you perform dynamic analysis in a convenient way.
Key features:
- `socket.cc` is patched for traffic monitoring and interception;
- `dart.cc` is modified to print classes, functions and some fields;
- display absolute code offset for functions;
- contains minor changes for successful compilation;
- if you would like to implement your own patches, manual Flutter code changes are supported using a specially crafted `Dockerfile`.
### Supported engines
- Android: arm64, arm32;
- iOS: arm64;
- Release: Stable, Beta
### Install
```
# Linux, Windows, MacOS
pip3 install reflutter==0.8.6
```
### Usage
```console
impact@f:~$ reflutter main.apk
Please enter your Burp Suite IP: <input_ip>
SnapshotHash: 8ee4ef7a67df9845fba331734198a953
The resulting apk file: ./release.RE.apk
Please sign the apk file
impact@f:~$ reflutter main.ipa
```
### Traffic interception
You need to specify the IP of your Burp Suite Proxy Server located in the same network where the device with the Flutter application is. Then configure the Proxy in `BurpSuite -> Listener Proxy -> Options tab`:
- Add port: `8083`
- Bind to address: `All interfaces`
- Request handling: Support invisible proxying = `True`
<p align="center"><img src="https://user-images.githubusercontent.com/87244850/135753172-20489ef9-0759-432f-b2fa-220607e896b8.png" width="84%"/></p>
No certificate installation or root access is required for Android. reFlutter also allows bypassing some of the Flutter certificate pinning implementations.
> ⚠️ **Note:** Starting from Flutter version **3.24.0** (snapshot hash: `80a49c7111088100a233b2ae788e1f48`), the hardcoded proxy IP and port have been removed. You now need to configure your proxy directly on the device.
#### On Android
Use ADB to configure the device’s proxy:
```bash
adb -s <device> shell "settings put global http_proxy <proxy_ip:port>"
```
Sign, align, and install the APK. Optionally configure **TunProxy** to route traffic through Burp Suite.
#### On iOS
Sign and install the IPA. Configure **Potatso** to use your Burp Suite proxy server.
### Usage on Android
The resulting apk must be aligned and signed. A recommended tool is [uber-apk-signer](https://github.com/patrickfav/uber-apk-signer/releases/tag/v1.2.1):
```bash
java -jar uber-apk-signer.jar --allowResign -a release.RE.apk
```
Run the app on a device. Determine `_kDartIsolateSnapshotInstructions` via binary search. reFlutter writes the dump file to the app's root folder and sets 777 permissions. Retrieve it using:
```bash
adb -d shell "cat /data/data/<PACKAGE_NAME>/dump.dart" > dump.dart
```
<details>
<summary>file contents</summary>
```dart
Library:'package:anyapp/navigation/DeepLinkImpl.dart' Class: Navigation extends Object {
String* DeepUrl = anyapp://evil.com/ ;
...
```
</details>
### Usage on iOS
After running `reflutter main.ipa`, execute the app on device. The dump file path is printed to Xcode console logs:
```
Current working dir: /private/var/mobile/Containers/Data/Application/<UUID>/dump.dart
```
Retrieve the file from the device.
<p align="center"><img src="https://user-images.githubusercontent.com/87244850/135860648-a13ba3fd-93d2-4eab-bd38-9aa775c3178f.png" width="100%"/></p>
### Frida
```
frida-tools==13.7.1
frida==16.7.19
```
Use dump offsets in the Frida [script](https://github.com/Impact-I/reFlutter/blob/main/frida.js):
```bash
frida -U -f <package> -l frida.js
```
To find `_kDartIsolateSnapshotInstructions`:
```bash
readelf -Ws libapp.so
```
Look for the `Value` field.
### To Do
- [x] Display absolute code offset for functions;
- [ ] Extract more strings and fields;
- [x] Add socket patch;
- [ ] Extend engine support to Debug using Fork and Github Actions;
- [ ] Improve detection of `App.framework` and `libapp.so` inside zip archive
### Build Engine
Engines are built using [GitHub Actions](https://github.com/Impact-I/reFlutter/actions) based on data in [enginehash.csv](https://github.com/Impact-I/reFlutter/blob/main/enginehash.csv). Snapshot hash is retrieved from:
```
https://storage.googleapis.com/flutter_infra_release/flutter/<hash>/android-arm64-release/linux-x64.zip
```
<details>
<summary>release</summary>
[](https://github.com/Impact-I/reFlutter/actions)
</details>
### Custom Build
Manual Flutter code patching is supported using Docker:
```bash
git clone https://github.com/Impact-I/reFlutter && cd reFlutter
docker build -t reflutter -f Dockerfile .
```
Run with:
```bash
docker run -it -v "$(pwd):/t" -e HASH_PATCH=<Snapshot_Hash> -e COMMIT=<Engine_commit> reflutter
```
Example:
```bash
docker run -it -v "$(pwd):/t" -e HASH_PATCH=aa64af18e7d086041ac127cc4bc50c5e -e COMMIT=d44b5a94c976fbb65815374f61ab5392a220b084 reflutter
```
#### Example: Build Android ARM64 (Linux/Windows)
```bash
docker run -e WAIT=300 -e x64=0 -e arm=0 -e HASH_PATCH=<Snapshot_Hash> -e COMMIT=<Engine_commit> --rm -iv${PWD}:/t reflutter
```
Flags:
- `-e x64=0`: disables x64 build
- `-e arm64=0`: disables arm64 build
- `-e arm=0`: disables arm32 build
- `-e WAIT=300`: time in seconds to modify source before build
- `-e HASH_PATCH`: snapshot hash from `enginehash.csv`
- `-e COMMIT`: engine commit hash
---
Raw data
{
"_id": null,
"home_page": "https://github.com/Impact-I/reFlutter",
"name": "reflutter",
"maintainer": null,
"docs_url": null,
"requires_python": ">3.9",
"maintainer_email": null,
"keywords": "distutils setuptools egg pip requirements",
"author": "impact",
"author_email": "routeros7.1@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/41/0d/4d4a48a927afc9457a5ffc47b3b75dfbeea4cbef0e7c3ac85ec690cc3452/reflutter-0.8.6.tar.gz",
"platform": "any",
"description": "[](https://github.com/Impact-I/reFlutter/stargazers)\n\n<p align=\"center\"><img src=\"https://user-images.githubusercontent.com/87244850/135659542-22bb8496-bf26-4e25-b7c1-ffd8fc0cea10.png\" width=\"75%\"/></p>\n\n**Read more on the blog:** <https://swarm.ptsecurity.com/fork-bomb-for-flutter/>\n\nThis framework helps with Flutter apps reverse engineering using the patched version of the Flutter library which is already compiled and ready for app repacking. This library has snapshot deserialization process modified to allow you perform dynamic analysis in a convenient way.\n\nKey features:\n\n- `socket.cc` is patched for traffic monitoring and interception;\n- `dart.cc` is modified to print classes, functions and some fields;\n- display absolute code offset for functions;\n- contains minor changes for successful compilation;\n- if you would like to implement your own patches, manual Flutter code changes are supported using a specially crafted `Dockerfile`.\n\n### Supported engines\n\n- Android: arm64, arm32;\n- iOS: arm64;\n- Release: Stable, Beta\n\n### Install\n\n```\n# Linux, Windows, MacOS\npip3 install reflutter==0.8.6\n```\n\n### Usage\n\n```console\nimpact@f:~$ reflutter main.apk\n\nPlease enter your Burp Suite IP: <input_ip>\n\nSnapshotHash: 8ee4ef7a67df9845fba331734198a953\nThe resulting apk file: ./release.RE.apk\nPlease sign the apk file\n\nimpact@f:~$ reflutter main.ipa\n```\n\n### Traffic interception\n\nYou need to specify the IP of your Burp Suite Proxy Server located in the same network where the device with the Flutter application is. Then configure the Proxy in `BurpSuite -> Listener Proxy -> Options tab`:\n\n- Add port: `8083`\n- Bind to address: `All interfaces`\n- Request handling: Support invisible proxying = `True`\n\n<p align=\"center\"><img src=\"https://user-images.githubusercontent.com/87244850/135753172-20489ef9-0759-432f-b2fa-220607e896b8.png\" width=\"84%\"/></p>\n\nNo certificate installation or root access is required for Android. reFlutter also allows bypassing some of the Flutter certificate pinning implementations.\n\n> \u26a0\ufe0f **Note:** Starting from Flutter version **3.24.0** (snapshot hash: `80a49c7111088100a233b2ae788e1f48`), the hardcoded proxy IP and port have been removed. You now need to configure your proxy directly on the device.\n\n#### On Android\n\nUse ADB to configure the device\u2019s proxy:\n\n```bash\nadb -s <device> shell \"settings put global http_proxy <proxy_ip:port>\"\n```\n\nSign, align, and install the APK. Optionally configure **TunProxy** to route traffic through Burp Suite.\n\n#### On iOS\n\nSign and install the IPA. Configure **Potatso** to use your Burp Suite proxy server.\n\n### Usage on Android\n\nThe resulting apk must be aligned and signed. A recommended tool is [uber-apk-signer](https://github.com/patrickfav/uber-apk-signer/releases/tag/v1.2.1):\n\n```bash\njava -jar uber-apk-signer.jar --allowResign -a release.RE.apk\n```\n\nRun the app on a device. Determine `_kDartIsolateSnapshotInstructions` via binary search. reFlutter writes the dump file to the app's root folder and sets 777 permissions. Retrieve it using:\n\n```bash\nadb -d shell \"cat /data/data/<PACKAGE_NAME>/dump.dart\" > dump.dart\n```\n\n<details>\n<summary>file contents</summary>\n\n```dart\nLibrary:'package:anyapp/navigation/DeepLinkImpl.dart' Class: Navigation extends Object {\nString* DeepUrl = anyapp://evil.com/ ;\n...\n```\n\n</details>\n\n### Usage on iOS\n\nAfter running `reflutter main.ipa`, execute the app on device. The dump file path is printed to Xcode console logs:\n\n```\nCurrent working dir: /private/var/mobile/Containers/Data/Application/<UUID>/dump.dart\n```\n\nRetrieve the file from the device.\n\n<p align=\"center\"><img src=\"https://user-images.githubusercontent.com/87244850/135860648-a13ba3fd-93d2-4eab-bd38-9aa775c3178f.png\" width=\"100%\"/></p>\n\n### Frida\n\n```\nfrida-tools==13.7.1\nfrida==16.7.19\n```\n\nUse dump offsets in the Frida [script](https://github.com/Impact-I/reFlutter/blob/main/frida.js):\n\n```bash\nfrida -U -f <package> -l frida.js\n```\n\nTo find `_kDartIsolateSnapshotInstructions`:\n\n```bash\nreadelf -Ws libapp.so\n```\n\nLook for the `Value` field.\n\n### To Do\n\n- [x] Display absolute code offset for functions;\n- [ ] Extract more strings and fields;\n- [x] Add socket patch;\n- [ ] Extend engine support to Debug using Fork and Github Actions;\n- [ ] Improve detection of `App.framework` and `libapp.so` inside zip archive\n\n### Build Engine\n\nEngines are built using [GitHub Actions](https://github.com/Impact-I/reFlutter/actions) based on data in [enginehash.csv](https://github.com/Impact-I/reFlutter/blob/main/enginehash.csv). Snapshot hash is retrieved from:\n\n```\nhttps://storage.googleapis.com/flutter_infra_release/flutter/<hash>/android-arm64-release/linux-x64.zip\n```\n\n<details>\n<summary>release</summary>\n\n[](https://github.com/Impact-I/reFlutter/actions)\n\n</details>\n\n### Custom Build\n\nManual Flutter code patching is supported using Docker:\n\n```bash\ngit clone https://github.com/Impact-I/reFlutter && cd reFlutter\ndocker build -t reflutter -f Dockerfile .\n```\n\nRun with:\n\n```bash\ndocker run -it -v \"$(pwd):/t\" -e HASH_PATCH=<Snapshot_Hash> -e COMMIT=<Engine_commit> reflutter\n```\n\nExample:\n\n```bash\ndocker run -it -v \"$(pwd):/t\" -e HASH_PATCH=aa64af18e7d086041ac127cc4bc50c5e -e COMMIT=d44b5a94c976fbb65815374f61ab5392a220b084 reflutter\n```\n\n#### Example: Build Android ARM64 (Linux/Windows)\n\n```bash\ndocker run -e WAIT=300 -e x64=0 -e arm=0 -e HASH_PATCH=<Snapshot_Hash> -e COMMIT=<Engine_commit> --rm -iv${PWD}:/t reflutter\n```\n\nFlags:\n\n- `-e x64=0`: disables x64 build\n- `-e arm64=0`: disables arm64 build\n- `-e arm=0`: disables arm32 build\n- `-e WAIT=300`: time in seconds to modify source before build\n- `-e HASH_PATCH`: snapshot hash from `enginehash.csv`\n- `-e COMMIT`: engine commit hash\n\n---\n",
"bugtrack_url": null,
"license": "GPLv3+",
"summary": "Reverse Flutter",
"version": "0.8.6",
"project_urls": {
"Homepage": "https://github.com/Impact-I/reFlutter"
},
"split_keywords": [
"distutils",
"setuptools",
"egg",
"pip",
"requirements"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "827dc9f5ec0a90e7a219856def1acad92f2375852141a90d8fd2871281eaefb3",
"md5": "5bdb72bfd5ac3658ecb5441d83f9a13a",
"sha256": "93a7a9269668da74c16ad7385865ed05edac39044a28d238d4504765bf70a94f"
},
"downloads": -1,
"filename": "reflutter-0.8.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5bdb72bfd5ac3658ecb5441d83f9a13a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">3.9",
"size": 24719,
"upload_time": "2025-08-16T22:10:38",
"upload_time_iso_8601": "2025-08-16T22:10:38.709827Z",
"url": "https://files.pythonhosted.org/packages/82/7d/c9f5ec0a90e7a219856def1acad92f2375852141a90d8fd2871281eaefb3/reflutter-0.8.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "410d4d4a48a927afc9457a5ffc47b3b75dfbeea4cbef0e7c3ac85ec690cc3452",
"md5": "fd33f0fccd3bd1e401a7f7d72519d046",
"sha256": "de19aaae644b1aa8c950056892c7b5780b76c0b28c0e2bf790019b7a570f6115"
},
"downloads": -1,
"filename": "reflutter-0.8.6.tar.gz",
"has_sig": false,
"md5_digest": "fd33f0fccd3bd1e401a7f7d72519d046",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">3.9",
"size": 26966,
"upload_time": "2025-08-16T22:10:41",
"upload_time_iso_8601": "2025-08-16T22:10:41.458622Z",
"url": "https://files.pythonhosted.org/packages/41/0d/4d4a48a927afc9457a5ffc47b3b75dfbeea4cbef0e7c3ac85ec690cc3452/reflutter-0.8.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-16 22:10:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Impact-I",
"github_project": "reFlutter",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "reflutter"
}