Introduction to Flutter
Flutter is a mobile application development framework launched and open-source by Google, focusing on cross platform, high fidelity and high performance. Developers can develop apps through Dart language, and a set of code can run on iOS and Android platforms at the same time. Flutter provides rich components and interfaces, and developers can quickly add native extensions to flutter. At the same time, fluent also uses the native engine to render the view.
Flutter grab
- Disable Flutter SSL
Principle: Hook session_verify_cert_chain returns 0x1
function hook_ssl_verify_result(address){ Interceptor.attach(address, { onEnter: function(args) { }, onLeave: function(retval){ retval.replace(0x1); console.log('Retval: ' + retval + " Done..."); } }); } /** * frida -U xxx -l hook_ssl_verify_result.js * You need to actively call this function disablePinning() */ function disablePinning(){ var m = Process.findModuleByName('libflutter.so'); // 32-bit so var pattern = '2d e9 f0 4f a3 b0 81 46 50 20 10 70' // 64 bit so // var pattern = "FF 03 05 D1 FD 7B 0F A9 9A E3 05 94 08 0A 80 52 48 00 00 39 16 54 40 F9 56 07 00 B4 C8 02 40 F9 08 07 00 B4"; var res = Memory.scan(m.base, m.size, pattern, { onMatch: function(address, size) { hook_ssl_verify_result(address.add(0x01)); }, onError: function(reason){ console.log('[!] There was an error scanning memory'); }, onComplete: function(){ console.log('[*] DisablePinning All done ...'); } }); }
-
Traffic proxy forwarding
Slide right to enter settings - > select network WiFi - > set host name and port
(Note: there is no need to modify Wi Fi configuration manually)->Filter default value: select filter all - > Edit filter rule (+, local agent connect all, select application, save)
-
Packet capture analysis
Burp - > proxy - > Options - > Add - > host and port
Note: you need to install the burp certificate into the system certificate
Fluent reverse analysis
tool
Doldrums
Parse libapp So class symbols, function offset values, etc., without specific code, can only be used for auxiliary analysis
Android
IOS
- Reverse analysis auxiliary script
- backward analysis
Fluent compiles Dart language into native arm code. For details, please refer to Deeply understand the compilation principle and optimization of fluent,Fluent machine code generation gen_snapshot.
Use MachOView to view the final app from dart code The symbol table in the framework is as follows, which does not contain useful business function information.
At the same time, the author has not found a reverse tool for fluent app, the reverse ecology is not perfect, and it is difficult to reverse for fluent app. stay Shuttle app reverse In this article, taking the Hello world code block as an example, the author analyzes Dart sdk, snapshot analysis and RawOject, which provides ideas for the reverse of fluent app.
In view of the current challenges of reverse shuttle, it is difficult to analyze its business code logic. Therefore, when meeting the general development specifications, the consideration of additional security measures for Dart can be postponed, but it needs continuous attention.
At the same time, in the process of analyzing the Flutter architecture, the author found that the useful information related to the application can be peeped through the Flutter Plugin, so we need to pay attention to the rational use of the channel.
Flutter Plugin
Flutter Plugin is the primary communication channel between fulter and.
On the fluent side, the MethodChannel API can send messages corresponding to method calls.
On the host platform iOS, FlutterMethodChannel iOS API You can receive method calls and return results to call iOS native code. Such as the keychain used to store sensitive data( flutter_secure_storage ), authentication related functions TouchID and FaceID( local_auth ), apple login( flutter_apple_sign_in Plugin),SSL Pinning(ssl_pinning_plugin )Wait for Plugin.
Because the FlutterMethodChannel is implemented by OC, you can hook the call of this class in the way of hook OC, so as to obtain possible useful information at runtime.
Flutter Plugin hook
Check the Flutter
When the APP is running, the application will load the required modules, listed by the author's demo app. The loaded modules are:
/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Runner /Library/MobileSubstrate/MobileSubstrate.dylib /usr/lib/libsqlite3.dylib /System/Library/Frameworks/AVFoundation.framework/AVFoundation /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/FMDB.framework/FMDB /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/Flutter.framework/Flutter /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/MTBBarcodeScanner.framework/MTBBarcodeScanner /System/Library/Frameworks/QuartzCore.framework/QuartzCore /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/ai_barcode.framework/ai_barcode /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/device_info.framework/device_info /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/flutter_custom_dialog.framework/flutter_custom_dialog /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/flutter_secure_storage.framework/flutter_secure_storage /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/package_info.framework/package_info /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/path_provider.framework/path_provider /private/var/containers/Bundle/Application/70288CAB-186A-453E-8FBA-B00FEF608CC0/Runner.app/Frameworks/sqflite.framework/sqflite
In frames / fluent Framework / flutermmodule is the entry point. By checking whether the module is loaded, we can judge whether the application adopts Flutter technology.
function hasFlutter() { var modules = Process.enumerateModules() for (var i = 0; i < modules.length; i++) { var oneModule = modules[i] if (oneModule.path.endsWith('flutter')) { return true } } return false }
hook plugin
The following codes are used Frida Frame, hook.
//code from https://gist.github.com/AICDEV/630feed7583561ec9f9421976e836f90 // https://api.flutter.dev/objcdoc/Classes/FlutterMethodChannel.html#/c:objc(cs)FlutterMethodChannel(im)invokeMethod:arguments: function traceFlutterMethodCall() { var className = "FlutterMethodCall" var methodName = "+ methodCallWithMethodName:arguments:" var hook = ObjC.classes[className][methodName]; try { Interceptor.attach(hook.implementation, { onEnter: function (args) { this.className = ObjC.Object(args[0]).toString(); this.methodName = ObjC.selectorAsString(args[1]); console.log(this.className + ":" + this.methodName); console.log("method: " + ObjC.Object(args[2]).toString()); console.log("args: " + ObjC.Object(args[3]).toString()); } }) } catch (err) { console.log("error in trace FlutterMethodCall"); console.log(err); } }
Flutter methodcall is the class name and "+ methodCallWithMethodName:arguments:" is the method name. This information can be found on the Official documents Found in; It can also be obtained by traversing all flutter related functions through frida tool; It can also be viewed using tools such as MachOView.
In the Demo app, the author uses flutter_secure_storage Plugin implements the write operation to keychain. The code is as follows:
SecureStorage.set("key", "AF4ItDx/2aUDKDk/s+Mdi3aGUJ0wTmMRBvMzMEg/yor6dGiQUEPDypQx5vNnfa+/")
Through frida hook FlutterMethodCall, the output is as follows:
FlutterMethodCall:methodCallWithMethodName:arguments: method: write args: { key = "key"; options = "<null>"; value = "AF4ItDx/2aUDKDk/s+Mdi3aGUJ0wTmMRBvMzMEg/yor6dGiQUEPDypQx5vNnfa+/"; }