初试Flutter逆向
因为某些原因,需要逆向出某软件的 sign 生成算法。一开始没注意是 Flutter 写的,解压出libapp.so
,打开 ghidra 就是一通搜索,无果看了一眼Exported Functions
,发现不太对劲,都是_kDartIsolateSnapshotInstructions
一类的函数,搜了一下才知道原来是 Flutter 写的。
问题何在
因为对 Flutter 不熟,以下内容来自于我非常浅薄的理解,可能有不准确之处。
Flutter 软件大部分逻辑都是写在 dart 里的,而 dart 代码在实际运行中都是在一个虚拟机内运行的,相当于天然就带了一层保护。
目前逆向工具也不多,比较好用的也就reFlutter,它会重新打包 apk,然后自动生成一份dump.dart
文件,里面有所有函数相对_kDartIsolateSnapshotInstructions
的偏移,还有一些静态变量(不确定)等,例如:
Library:'dart:core' Class: Object {
Random _hashCodeRnd@0150898 = sentinel ;
Function 'get:_hashCodeRnd@0150898': static static-getter. () => Random {
Code Offset: _kDartIsolateSnapshotInstructions + 0x0000000000003598
}
Function '_objectHashCode@0150898': static. (dynamic) => int {
Code Offset: _kDartIsolateSnapshotInstructions + 0x0000000000317148
}
...
}
此外还会自动将所有的请求都转发到设置的BurpSuite Proxy IP
上,也不需要配置证书什么的,还是挺方便的,但是我没有找到不启用这个功能的方法,导致我其实不需要抓包也得强行打开 burp,否则所有请求都会超时。
具体分析
抓包可以发现 sign 八成是 md5,因此在dump.dart
里搜关键词,直接就找到了关键内容:
Library:'package:******/utils/md5.dart' Class: :: {
String* appSecret = ********-****-****-****-************;
Function 'generateMD5': static. (dynamic) => dynamic {
Code Offset: _kDartIsolateSnapshotInstructions + 0x00000000002939d4
}
}
Library:'package:******/utils/md5.dart', {
Function 'generateMD5': static. (dynamic) => dynamic {
Code Offset: _kDartIsolateSnapshotInstructions + 0x00000000002939d4
}
}
一上来就是一个赤裸裸的appSecret
,想必和时间戳什么的拼接以下就是 sign 了,于是直接定位到标准库里真正计算的函数:
Function 'updateHash':. (dynamic, dynamic) => void {
Code Offset: _kDartIsolateSnapshotInstructions + 0x0000000000294160
}
然后frida hook 一下,打印出具体参数:
function hook_md5() {
// 获取地址
let kDartIsolateSnapshotInstructions = Module.findExportByName("libapp.so", "_kDartIsolateSnapshotInstructions")
let updateHash = kDartIsolateSnapshotInstructions.add(0x0000000000294160); // 加上偏移量
Interceptor.attach(updateHash, {
// 打印参数
onEnter(args) {
try {
console.log("updateHash arg\n", hexdump(args[0]), "\n");
} catch (error) {
// 不知道为什么直接打印args会报错,也没有深究
console.log("updateHash arg\n", args[0], "\n");
}
},
// 打印返回值
onLeave : function(retval){
try {
console.log("updateHash return\n", hexdump(retval), "\n");
} catch (error) {
console.log("updateHash return\n", retval, "\n");
}
}
})
}
setImmediate(() => {
hook_md5();
})
结果完全就是md5(timestamp+appSecret)
,非常朴素。
参考
基本上完全是从Flutter APP逆向实践-初级篇学的,尤其是脚本,非常感谢。
上一篇:迁移并使用zola重写博客