This framework helps reverse engineer Flutter apps using patched version of Flutter library which is already compiled and ready for app repacking. There are changes made to snapshot deserialization process that 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;- contains minor changes for successfull compilation;
- if you would like to implement your own patches there is manual Flutter code change is supported using specially crafted
Dockerfile
Supported engines
- Android: arm64, arm32;
- IOS: arm64 (Unstable);
- Release: Stable, Beta
Install
# Linux, Windows, MacOS
pip install reflutter
pip3 install reflutter
Usage
impact@f:~$ reflutter main.apk
Please enter your Burp Suite IP:
SnapshotHash: 8ee4ef7a67df9845fba331734198a953
The resulting apk file: ./release.RE.apk
Please sign the apk file
Configure Proxy in Burp Suite -> *:8083
Request Handling -> Support Invisible Proxying -> true
impact@f:~$ reflutter main.ipa
Traffic interception
You need to specify the IP of your Burp Suite relative to your local network on which the device with the flutter application is located. Next, you must configure the Proxy in BurpSuite -> Listener Proxy -> Options tab
- Add port:
8083
- Bind to address:
All interfaces
- Request handling: Support invisible proxying =
True
You don't need to install any certificates. On an Android device, you don't need root access. This also bypasses some of the flutter certificate pinning implementations.
Usage on Android
The resulting apk must be aligned and signed. I am using uber-apk-signer java -jar uber-apk-signer.jar --allowResign -a release.RE.apk
. To see what code is loaded through DartVM, you must run the application on the device. You need LogCat you can use Android Studio with reflutter keyword search or use adb logcat
Output Example
impact@f:~$ adb logcat -e reflutter | sed 's/.*DartVM//' >> reflutter.txt
code output
Library:'package:anyapp/navigation/DeepLinkImpl.dart' Class: Navigation extends Object {
String* DeepUrl = anyapp://evil.com/ ;
Function 'Navigation.': constructor. (dynamic, dynamic, dynamic, dynamic) => NavigationInteractor {
}
Function 'initDeepLinkHandle':. (dynamic) => Future<void>* {
}
Function '_navigateDeepLink@547106886':. (dynamic, dynamic, {dynamic navigator}) => void {
}
}
Library:'package:anyapp/auth/navigation/AuthAccount.dart' Class: AuthAccount extends Account {
PlainNotificationToken* _instance = sentinel;
Function 'getAuthToken':. (dynamic, dynamic, dynamic, dynamic) => Future<AccessToken*>* {
}
Function 'checkEmail':. (dynamic, dynamic) => Future<bool*>* {
}
Function 'validateRestoreCode':. (dynamic, dynamic, dynamic) => Future<bool*>* {
}
Function 'sendSmsRestorePassword':. (dynamic, dynamic) => Future<bool*>* {
}
}
Usage on IOS
stub
XCode
To Do
- Display absolute code offset for functions;
- Extract more strings and fields;
- Add socket patch;
- Extend engine support to Debug using Fork and Github Actions;
- Improve detection of
App.framework
andlibapp.so
inside zip archive
Build Engine
The engines are built using reFlutter in Github Actions to build the desired version, commits and hash snapshots are used from this table. The hash of the snapshot is extracted from storage.googleapis.com/flutter_infra_release/flutter/
Custom Build
If you would like to implement your own patches there is manual Flutter code change is supported using specially crafted Docker
sudo docker pull ptswarm/reflutter
# Linux, Windows
EXAMPLE BUILD ANDROID ARM64:
sudo docker run -e WAIT=300 -e x64=0 -e arm=0 -e HASH_PATCH=
-e COMMIT=
--rm -iv${PWD}:/t ptswarm/reflutter
FLAGS:
-e x64=0
-e arm=0
-e WAIT=300
-e HASH_PATCH=[Snapshot_Hash]
-e COMMIT=[Engine_commit]