Flutter
Reading time: 5 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
Flutter
Flutter是谷歌的跨平台UI工具包,允许开发者编写单一的Dart代码库,引擎(本地C/C++)将其转换为Android和iOS的特定平台机器代码。引擎捆绑了Dart VM、BoringSSL、Skia等,并作为共享库libflutter.so(Android)或Flutter.framework(iOS)发布。所有实际的网络操作(DNS、套接字、TLS)都发生在这个库内部,而不是在通常的Java/Kotlin Swift/Obj-C层。这种孤立的设计是通常的Java级Frida钩子在Flutter应用中失败的原因。
在Flutter中拦截HTTPS流量
这是这篇博客文章的摘要。
为什么在Flutter中拦截HTTPS很棘手
- SSL/TLS验证位于BoringSSL的两层下方,因此Java SSL固定绕过不会触及它。
- BoringSSL在libflutter.so内部使用其自己的 CA存储;将你的Burp/ZAP CA导入Android的系统存储不会改变任何东西。
- libflutter.so中的符号是剥离和混淆的,隐藏了证书验证功能,使动态工具无法使用。
确定确切的Flutter栈
知道版本可以让你重建或模式匹配正确的二进制文件。
步骤 | 命令 / 文件 | 结果 |
---|---|---|
获取快照哈希 | bash\npython3 get_snapshot_hash.py libapp.so\n | adb4292f3ec25… |
映射哈希 → 引擎 | enginehash列表在reFlutter中 | Flutter 3 · 7 · 12 + 引擎提交 1a65d409… |
拉取依赖提交 | 在该引擎提交中的DEPS文件 | • dart_revision → Dart v2 · 19 · 6• dart_boringssl_rev → BoringSSL 87f316d7… |
在这里找到get_snapshot_hash.py。
目标: ssl_crypto_x509_session_verify_cert_chain()
- 位于BoringSSL内部的**
ssl_x509.cc
**。 - 返回
bool
– 一个true
就足以绕过整个证书链检查。 - 每个CPU架构都有相同的函数;只有操作码不同。
选项A – 使用reFlutter进行二进制补丁
- 克隆应用的Flutter版本的确切引擎和Dart源代码。
- 正则补丁两个热点:
- 在
ssl_x509.cc
中,强制return 1;
- (可选)在
socket_android.cc
中,硬编码一个代理("10.0.2.2:8080"
)。
- 重新编译libflutter.so,将其放回APK/IPA中,签名,安装。
- 预补丁构建的常见版本在reFlutter GitHub发布中提供,以节省数小时的构建时间。
选项B – 使用Frida进行实时钩取(“硬核”路径)
由于符号被剥离,你需要对加载的模块进行模式扫描以获取其前几个字节,然后动态更改返回值。
javascript
// attach & locate libflutter.so
var flutter = Process.getModuleByName("libflutter.so");
// x86-64 pattern of the first 16 bytes of ssl_crypto_x509_session_verify_cert_chain
var sig = "55 41 57 41 56 41 55 41 54 53 48 83 EC 38 C6 02";
Memory.scan(flutter.base, flutter.size, sig, {
onMatch: function (addr) {
console.log("[+] found verifier at " + addr);
Interceptor.attach(addr, {
onLeave: function (retval) { retval.replace(0x1); } // always 'true'
});
},
onComplete: function () { console.log("scan done"); }
});
请运行它:
bash
frida -U -f com.example.app -l bypass.js
移植提示
- 对于 arm64-v8a 或 armv7,从 Ghidra 中获取函数的前 ~32 字节,转换为以空格分隔的十六进制字符串,并替换
sig
。 - 每个 Flutter 版本保持 一个模式,将它们存储在备忘单中以便快速重用。
通过代理强制流量
Flutter 本身 忽略设备代理设置。最简单的选项:
- Android Studio 模拟器: 设置 ▶ 代理 → 手动。
- 物理设备: 恶意 Wi-Fi AP + DNS 欺骗,或 Magisk 模块编辑
/etc/hosts
。