Reversing an Android sample which uses Flutter

  1. Reverse engineer’s angle. Read this part if you want to hear how I struggled to reverse the app.
  2. Malware analyst’s angle. Read this part to learn if the app is malicious or not.

Reverse engineering Flutter-based Android apps

How do I detect the app uses Flutter?

There are two cases.

  • If the app is in debug mode, you are lucky. Unzip the APK and look for the code in ./assets/flutter_assets/kernel_blob.bin [1]
  • If the app is in release mode (which is the case for the suspicious sample), you will find libflutter.so in ./lib/ subdirectories.

Where is the Dart code?

Don’t waste your time reversing the dalvik bytecode. I personally wasted time decrypting a Base64 AES encrypted dynamically loaded DEX… and landed inside Google Ads…

Output of : readelf -s libapp.so
Parsing the snapshots of the app. The first one is the VM isolate. Both use version 2.13.

Tools to reverse Dart

There are basically 3 tools to reverse Dart:

  • Darter [5]: this is a Python toolkit to parse libapp.so. It works for Flutter 2.5. Example of use here. Unfortunately, we have 2.13 which is significantly newer.
  • Doldrums [6]: this tool is meant to parse libapp.so and dump all classes of the isolate snapshots. Exactly what I am looking for, except it works for Flutter 2.10. There’s a fork currently focusing on 2.13. It isn’t finished yet. I tried to fix errors for my sample, by quickly moving out of issues it encountered, but I got no interesting decompiled output in the end (meaning my “quick fix” is too quick, and there’s more to be done to get it to work).
  • reFlutter [7]: this framework operates differently. The idea is to patch the sample and use a patched version of the Flutter library. Then, to write Frida hooks and dynamically analyze calls to the patched library.

To reFlutter … or not

Patching the application is easy: run reFlutter to generate the patched application (select option 2), then align it (zipalign) and sign it (apksigner).

Patching the sample with reFlutter — select option 2 for dynamic analysis of the sample
Function 'get:zra': getter const. null {Code Offset: _kDartIsolateSnapshotInstructions + 0x000000000000c1a4

}
function hookFunc() {
// _kDartIsolateSnapshotInstructions (c000) + code offset (c1a4)
var dumpOffset = '0x181a4'
var argBufferSize = 150
var address = Module.findBaseAddress('libapp.so')
console.log('\n\nbaseAddress: ' + address.toString())
...

Analyzing the reFlutter dump

Even if the reFlutter dump does not contain what I am after (Dart decompiled code), it nevertheless contains valuable information: the list of all libraries, classes, objects and functions.

This is the list of methods of the internal Dart:_http library
Obfuscated functions names of library “cuf”

Malware analyst’s angle

So, the fact is we don’t have any good tool to decompile Dart from libapp.so + the sample has some form of obfuscation. We’re not totally done yet: strings outputs interesting strings.

Notice the URLs going to amelimoncompte[.]blogpost[.]com

What’s the goal?

So, the sample is a somewhat useless but non malicious front-end to understand or head to the French national health system. What’s the point in creating such an app?!

Applications developed by “santotosapps” in Google Play Store. Notice how each app look alike: a large rectangular icon with simple upper case font.

References

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
@cryptax

@cryptax

162 Followers

Mobile and IoT malware researcher. The postings on this account are solely my own opinion and do not represent my employer.