Translated ['src/mobile-pentesting/android-app-pentesting/flutter.md'] t

This commit is contained in:
Translator 2025-05-20 05:38:07 +00:00
parent f3187b8423
commit 3756eca7a8

View File

@ -0,0 +1,74 @@
# Flutter
{{#include ../../banners/hacktricks-training.md}}
# 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流量
这是这篇[博客文章](https://sensepost.com/blog/2025/intercepting-https-communication-in-flutter-going-full-hardcore-mode-with-frida/)的摘要。
### 为什么在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<br>`dart_boringssl_rev` → BoringSSL `87f316d7…`
在这里找到[get_snapshot_hash.py](https://github.com/Impact-I/reFlutter/blob/main/scripts/get_snapshot_hash.py)。
### 目标: `ssl_crypto_x509_session_verify_cert_chain()`
* 位于BoringSSL内部的**`ssl_x509.cc`**。
* **返回`bool`** 一个`true`就足以绕过整个证书链检查。
* 每个CPU架构都有相同的函数只有操作码不同。
### 选项A 使用**reFlutter**进行二进制补丁
1. **克隆**应用的Flutter版本的确切引擎和Dart源代码。
2. **正则补丁**两个热点:
* 在`ssl_x509.cc`中,强制`return 1;`
* (可选)在`socket_android.cc`中,硬编码一个代理(`"10.0.2.2:8080"`)。
3. **重新编译**libflutter.so将其放回APK/IPA中签名安装。
4. **预补丁构建**的常见版本在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`
## 参考
- [https://sensepost.com/blog/2025/intercepting-https-communication-in-flutter-going-full-hardcore-mode-with-frida/](https://sensepost.com/blog/2025/intercepting-https-communication-in-flutter-going-full-hardcore-mode-with-frida/)