Flutter 简介
Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展。同时 Flutter还使用 Native引擎渲染视图。
Flutter 抓包
- Disable Flutter SSL
原理: Hook session_verify_cert_chain 返回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
* 需要主动调用该函数disablePinning()
*/
function disablePinning(){
var m = Process.findModuleByName('libflutter.so');
// 32位so
var pattern = '2d e9 f0 4f a3 b0 81 46 50 20 10 70'
// 64位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 ...');
}
});
}
-
流量代理转发
右滑进入设置->选择网络WIFI->设置主机名、端口
(注意: Wi-Fi配置那里不需要手动修改)->过滤默认值选择过滤全部->编辑过滤规则(+、本地代理连全部、选择应用程序、保存) -
抓包分析
burp->proxy->options->add->主机、端口
注意: 需要将burp证书安装到系统证书里面
Flutter 逆向分析
工具
Doldrums
解析libapp.so类符号,函数偏移值等,无具体代码,仅可用于辅助分析
Android
IOS
逆向分析辅助脚本
逆向分析思路
类似于JNI,Flutter与原生需要有通讯的桥梁,这个桥梁在IOS称为Flutter Plugin
- Flutter Plugin
Flutter Plugin是Fultter和原生通讯渠道。
在Flutter端,MethodChannel API 可以发送与方法调用相对应的消息。
在宿主平台iOS上, FlutterMethodChannel iOS API
可以接收方法调用并返回结果,实现调用iOS原生代码。如存储敏感数据时使用的keychain(flutter_secure_storage
),身份认证相关功能TouchID和FaceID(local_auth
),苹果登录(flutter_apple_sign_in Plugin
),SSL Pinning(ssl_pinning_plugin
)等Plugin。
由于FlutterMethodChannel
是由OC实现,因此可以采用hook OC的方式,hook该类的调用,从而在运行时获取到可能有用的信息。
- Flutter Plugin hook
- 检查Flutter
APP在运行时,应用会加载的需要的module,以笔者的demo app为列子,已加载的module有:
/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
以Frameworks/Flutter.framework/Flutter
module为切入点,通过检查是否加载该module,从而判断该应用是否采用了Flutter技术。
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
以下代码采用Frida框架,进行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);
}
}
FlutterMethodCall
为类名,"+ methodCallWithMethodName:arguments:"
为方法名。该信息可在Flutter的官方文档中找到;也可通过frida工具,遍历所有flutter相关的函数得到;也可使用MachOView等工具查看。
笔者Demo app中,采用flutter_secure_storage
Plugin, 实现向keychain的write操作,代码如下:
SecureStorage.set("key", "AF4ItDx/2aUDKDk/s+Mdi3aGUJ0wTmMRBvMzMEg/yor6dGiQUEPDypQx5vNnfa+/")
通过frida hook FlutterMethodCall
, 输出如下:
FlutterMethodCall:methodCallWithMethodName:arguments:
method: write
args: {
key = "key";
options = "<null>";
value = "AF4ItDx/2aUDKDk/s+Mdi3aGUJ0wTmMRBvMzMEg/yor6dGiQUEPDypQx5vNnfa+/";
}