f3rb123/kill_flutter
GitHub: f3rb123/kill_flutter
一款跨版本的 Flutter SSL Pinning 绕过工具,通过动态分析 Flutter 引擎二进制文件中的 BoringSSL 证书校验函数并生成即用型 Frida 脚本,实现对任意版本 Flutter 应用流量的拦截。
Stars: 1 | Forks: 0
# 干掉 Fl!utter 🔪

## 背景
几个月前,在一次常规的 Flutter 应用渗透测试中,常见的 SSL pinning 绕过方法全都失效了——常用的 Frida 脚本和 reFlutter,都没能将流量导入 Burp。这让我陷入了对 Flutter *为何*如此难以拦截的深度探究,而这款工具就是探究的成果。
## 为什么 Flutter 与众不同
Flutter 不使用手机常规的网络栈。它自带了编译进原生文件的网络引擎(BoringSSL)——在 Android 上是 `libflutter.so`,在 iOS 上是 `Flutter` 框架。所有的证书校验都在这个编译后的文件内部进行。
这也是为什么像 **Objection** 和 **SSL Kill Switch** 这样的操作系统级绕过工具不起作用的原因——它们 hook 的是系统信任 API,而 Flutter 从不调用这些 API。它直接在自己的引擎内部走向 BoringSSL。
所以在面对 Flutter 时,你只剩下两种真正的选择——而在现代版本中,这两种方法都失效了。
## 为什么常规工具会失效
### 公开的 Frida 脚本
这些脚本在**硬编码偏移量**处 hook 证书校验函数,该偏移量是通过逆向工程某个特定版本的 Flutter 引擎得出的。问题在于:每个版本中的偏移量都是不同的。Flutter 不断发布新版本,每个引擎版本的编译方式也不同,因此该函数每次都会移动到一个新的地址。为旧版本编写的脚本会指向错误的位置,匹配不到任何内容,hook 永远无法生效。脚本并没有失效——是它底层的二进制文件发生了移动。
### reFlutter
很长一段时间里,这都是 Flutter 的首选工具,并且它确实管用。它从应用中读取快照哈希,将其与已知 Flutter 引擎版本的表格进行匹配,然后重新编译一个打过补丁的引擎来替换。但是那个表格必须针对每个 Flutter 版本手动更新,如今已经落后了——在较新的版本中,哈希值无法被识别,它会报告该引擎不受支持。
### 共同点
这两个工具都绑定到了特定的 Flutter 版本——一个是通过硬编码偏移量,另一个是通过查找表。Flutter 的发布速度超出了它们的更新速度,因此两者都会随着时间推移而衰退,并在当前的应用上失效。
## 更深层的问题
引擎二进制文件已被剥离——没有函数名,也没有标签。用手工方式查找证书校验函数意味着要在 Ghidra 或 IDA 中耗费数小时,而且由于偏移量在每个版本中都会改变,你必须为每个新版本重新进行这项工作。
## K!ll Fl!utter 的工作原理有何不同
它不使用硬编码偏移量或版本表,而是利用在每个 Flutter 版本中保持不变的属性,**在每一个二进制文件中重新查找**该函数:
1. **字符串锚点** — BoringSSL 的校验函数总是引用两个固定的字符串:`ssl_client` 和 `ssl_server`。这些字符串内置在 BoringSSL 自己的源码中,存在于所有编译过的 Flutter 二进制文件中。
2. **ADRP+ADD 指令扫描** — ARM64 总是使用 `ADRP+ADD` 指令对来加载字符串地址。这是架构层面的常量,并非 Flutter 特有的模式。扫描指向锚点字符串的指令对即可定位函数主体。
3. **序言回溯** — ARM64 函数总是以栈设置指令(`STP x29,x30` 或 `SUB sp`)开始。从锚点向后回溯到该指令,就能得出准确的函数起始位置。
由此,它可以计算出该特定二进制文件中证书校验函数的准确**偏移量**。因为它每次都会重新计算偏移量,所以 Frida hook 能够精准作用于任何版本——**无需手动逆向工程,无需 Ghidra,无需版本表,也无需不断进行更新。**
```
APK / IPA
└── Extract Flutter engine binary (libflutter.so / Flutter framework)
└── Find ssl_client + ssl_server string anchors
└── Scan ADRP+ADD instruction pairs referencing both
└── Walk back to ARM64 function prologue
└── Offset calculated → Frida script generated
└── iptables redirect → traffic hits Burp
```
## 流程
1. 将其指向一个 APK 或 IPA
2. 它会提取 Flutter 引擎文件
3. 它会找到证书校验函数并计算其偏移量
4. 它会生成一个即用型的 Frida 脚本,强制使校验通过
5. 它会打印出将流量路由到你的代理的确切命令(Flutter 会忽略代理设置,因此它使用内核级的重定向)
将其指向某个应用,就能获得一个可用的 Frida 脚本和可直接复制粘贴的命令。
## 可以绕过哪些 Pinning
✅ 默认的 Flutter `HttpClient` (dart:io) 证书验证
✅ `dio` 包的 SSL pinning
✅ 基于 Flutter HTTP 栈构建的自定义证书验证器
✅ 任何最终会调用 `ssl_crypto_x509_session_verify_cert_chain` 的 pinning
❌ mTLS / 客户端证书 pinning(服务器要求提供客户端证书)
❌ Flutter 之外的 Android/iOS 原生证书 pinning
❌ Root / 越狱检测(属于另一个独立问题)
## 环境要求
| 要求 | 说明 |
|---|---|
| Python 3 | 任何较新的版本 |
| `frida-tools` | `pip install frida-tools` |
| `aapt` | Android SDK build tools(仅限 Android,用于包名检测) |
| 已 Root 的 Android **或** 已越狱的 iOS | Frida + iptables 必需 |
| Burp Suite | 社区版或专业版 |
## 安装说明
```
git clone https://github.com/f3rb/kill_flutter
cd kill_flutter
pip install frida-tools
```
## 使用方法
```
# 帮助
python3 kill_flutter.py -h
# Android APK
python3 kill_flutter.py app.apk -i 192.168.1.10 -p 8080
# iOS IPA
python3 kill_flutter.py app.ipa -i 192.168.1.10 -p 8080 --device-ip 192.168.1.50
# 自定义输出目录
python3 kill_flutter.py app.apk -i 192.168.1.10 -o /tmp/pentest
# 强制指定 platform(如果扩展名不明确)
python3 kill_flutter.py app.apk --platform android -i 192.168.1.10
```
## 选项
| 参数 | 说明 | 默认值 |
|---|---|---|
| `app` | APK 或 IPA 的路径 | 必填 |
| `-i, --ip` | 你的机器 IP 地址 | `` |
| `-p, --port` | Burp Suite 监听端口 | `8080` |
| `-o, --output` | 生成文件的输出目录 | 应用所在目录 |
| `--platform` | 强制指定平台:`android` 或 `ios` | 自动检测 |
| `--device-ip` | 用于 SSH iptables 的 iOS 设备 IP | `` |
| `-h, --help` | 显示帮助信息 | — |
## 输出
该工具运行一次即可生成所需的所有内容:
- `flutter_bypass.js` — 内置偏移量的即用型 Frida 脚本
- 可复制粘贴的 iptables 命令(Android 通过 adb / iOS 通过 SSH)
- 自动填充了包名的可复制粘贴 Frida 启动命令
```
[*] Platform : ANDROID
[+] Package : com.example.flutterapp
[+] ssl_client @ ['0x1a1d75']
[+] ssl_server @ ['0x1ab471']
[*] Scanning ADRP+ADD refs... (may take a moment)
[+] SSL verify offset: 0x740cc8
[+] Frida script saved: /path/to/flutter_bypass.js
[3] Launch Frida:
frida -U -f com.example.flutterapp -l "/path/to/flutter_bypass.js"
```
## Burp Suite 设置
1. Proxy → Listeners → 在 `8080` 端口添加监听器
2. Bind address → **All interfaces** (`0.0.0.0`)
3. Request handling → ✅ **Support invisible proxying**
4. Intercept → **Off**
## 还原
**Android:**
```
adb shell su -c "iptables -t nat -D OUTPUT -p tcp --dport 443 -j DNAT --to-destination :8080"
adb shell su -c "iptables -t nat -D OUTPUT -p tcp --dport 80 -j DNAT --to-destination :8080"
# 或者直接:
adb reboot
```
**iOS:**
```
ssh root@ "iptables -t nat -D OUTPUT -p tcp --dport 443 -j DNAT --to-destination :8080"
ssh root@ "iptables -t nat -D OUTPUT -p tcp --dport 80 -j DNAT --to-destination :8080"
# 或者直接重启设备
```
## 它是如何找到函数的 — 技术细节
Flutter 的引擎二进制文件已被完全剥离。函数 `ssl_crypto_x509_session_verify_cert_chain` 无法通过名称找到,因此只能通过行为来定位:
**字符串锚点** — BoringSSL 源码包含:
```
const char *peer = SSL_is_server(ssl) ? "ssl_client" : "ssl_server";
```
这些字符串是该函数独有的,并且存在于每个版本中。通过字节扫描可以找到它们的文件偏移量。
**段解析** — ARM64 指令编码的是虚拟地址,而不是文件偏移量。该工具会解析 ELF(Android)或 Mach-O(iOS)段头,以构建文件偏移量与虚拟地址的映射关系,从而确保指令扫描的正确性。
**ADRP+ADD 扫描** — 它会扫描可执行段中立即数与每个字符串虚拟地址的低 12 位相匹配的 `ADD` 指令,然后验证前一个 `ADRP` 是否指向了正确的 4 KB 页面。这样就能定位到加载这两个字符串的代码。
**序言回溯** — 从同址引用处开始,它会向后回溯到第一条函数序言指令。这就是校验函数的起始位置——也就是内置到 Frida 脚本中的偏移量。
**Hook** — 在运行时,ASLR 会对库的基地址进行随机化处理,但偏移量是固定的。`module.base + offset` 始终能解析到该函数:
```
var addr = m.base.add(offset);
Interceptor.attach(addr, {
onLeave: function(retval) {
retval.replace(0x1); // force verification success
}
});
```
**流量重定向** — Flutter 直接发起 TCP 连接,忽略了系统代理,因此内核级的 iptables DNAT 会将所有发往 443/80 的出站流量重定向到 Burp,而不管应用自身的行为如何。
## 参考资料
- [PT Swarm — Fork Bomb for Flutter (reFlutter 内部机制)](https://swarm.ptsecurity.com/fork-bomb-for-flutter/)
- [SensePost — 使用 Frida 拦截 Flutter 中的 HTTPS](https://sensepost.com/blog/2025/intercepting-https-communication-in-flutter-going-full-hardcore-mode-with-frida/)
- [NVISO — 拦截 Flutter 流量](https://blog.nviso.eu/2022/08/18/intercept-flutter-traffic-on-ios-and-android-http-https-dio-pinning/)
- [reFlutter](https://github.com/ptswarm/reFlutter)
- [BoringSSL 源码 — ssl_x509.cc](https://github.com/google/boringssl/blob/master/ssl/ssl_x509.cc)
## 免责声明
本工具仅供**授权的安全测试使用**。请仅在您拥有明确书面测试许可的应用上使用。作者不对因使用本工具而造成的任何滥用或损坏负责。
## 作者
**f3rb** — 进攻性安全 | 移动端渗透测试 | 工具开发
标签:Docker支持, Flutter, Frida, SSL Pinning绕过, StruQ, 云资产清单, 目录枚举, 移动安全, 逆向工具, 逆向工程