mcpField
R
reversing-flutter-apps

reversing-flutter-apps

github.com/trilwu安全17756 次安装12 周前更新
代码仓库

关于 reversing-flutter-apps

面向移动安全测试人员的 Flutter 应用分析指南,涵盖 Dart AOT 结构恢复、流量拦截和运行时检查,帮助定位发布版中的应用逻辑与 API 行为。

主要功能

  1. 01识别 Flutter 构建模式
  2. 02用 blutter 恢复 Dart 符号
  3. 03检查对象池与反汇编结果
  4. 04转发并拦截 Flutter 流量
  5. 05用 Frida Hook Dart 函数

适用场景

  1. 01定位 Flutter 发布版中的端点
  2. 02排查 Burp 或 mitmproxy 无流量
  3. 03检查应用请求构造器与令牌处理函数

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill reversing-flutter-apps

安装后在 Claude Code 中输入/reversing-flutter-apps确认已加载。

详细介绍

逆向分析 Flutter 应用

Flutter 会同时打破标准移动应用工作流的两大环节。Dart 会通过 AOT 编译为原生快照,因此没有可供 jadx 反编译的 dex;Flutter 引擎还会自带 BoringSSL 和独立的信任存储,因此会同时忽略系统代理和用户 CA 存储,导致拦截代理看不到任何流量。这两种问题都无法从表面症状轻易判断,因此人们往往要花上数小时,才意识到自己遇到的是什么问题。

适用场景

  • 使用 jadx 查看 APK 时,发现 MainActivity 几乎为空,其他内容也很少
  • APK 中包含 lib/arm64-v8a/libflutter.so 和 libapp.so,或包含 assets/flutter_assets/
  • IPA 中包含 Frameworks/App.framework 和 Frameworks/Flutter.framework
  • 对于一个显然正在进行网络调用的应用,Burp、mitmproxy 或 Charles 却显示没有任何流量
  • 你需要还原 Dart 类名和方法名,或在发布构建中找到 API 层

不适用场景

  • 普通 Java/Kotlin Android 应用 — 使用 testing-mobile-applications
  • React Native(index.android.bundle、Hermes)— 使用 reversing-react-native-apps
  • Unity(global-metadata.dat、libil2cpp.so)— 使用 reversing-unity-il2cpp
  • 应用所调用的后端 — 能看到流量后,使用 testing-apis
  • 通用原生 .so 逆向分析 — 使用 analyzing-binaries

首先识别构建类型

构建模式决定了后续所有步骤。安装工具前先检查。

unzip -l target.apk | rg 'libflutter|libapp|flutter_assets|kernel_blob'
你看到的内容构建类型含义
libapp.so + libflutter.soAOT 发布构建常见情况。Dart 已编译为原生快照 — 本指南的主要处理路径
assets/flutter_assets/kernel_blob.binDebug / JIT容易得多:包含 Dart 内核字节码,而且可能可以访问 VM 服务
App.framework/App(iOS)AOT 发布构建与 libapp.so 相同;从已解密的 IPA 中提取
仅有 arm64-v8a—这是预期情况;blutter 面向 arm64。对 armeabi-v7a 的支持较弱
# Confirm the engine version — it gates which tools work
strings lib/arm64-v8a/libflutter.so | rg -m5 'Flutter|Dart VM version|dart-sdk'

如果存在 kernel_blob.bin,就停止并改为解包它:Debug 构建保留的信息多得多,而且如果启用了 Dart VM 服务,还能进行实时检查。发布构建才是难点,以下其余内容都假设你遇到的是这种情况。

使用 blutter 还原 Dart 结构

blutter 会解析 Dart AOT 快照,还原类名、方法名、字段名以及对象池 — 这能让你从难以阅读的 arm64 汇编转而浏览应用结构。

# blutter needs BOTH libraries: libapp.so is the snapshot, libflutter.so
# identifies the exact Dart version used to compile it
unzip -j target.apk 'lib/arm64-v8a/*' -d ./libs
python3 blutter.py ./libs ./out

你实际会用到的输出:

产物用途
pp.txt对象池转储 — 字符串常量、URL、密钥、端点。先看这里
objs.txt还原出的 Dart 对象和类
asm/应用各库的反汇编结果,已应用 Dart 符号
ida_script/将符号加载到 IDA;Ghidra 也有相应工具
blutter_frida.js针对还原出的 Dart 函数生成的 Frida Hook

你会遇到的问题是 Dart 版本不匹配。 blutter 是针对特定 Dart SDK 编译的,而快照格式会随版本变化。如果解析时出错,解决方法是使用与应用引擎版本匹配的 Dart SDK 构建 blutter,而不是尝试其他快照。先从 libflutter.so 中读取版本信息;对于全新的 Flutter 发布版本,blutter 尚未跟进时,首次运行很可能会失败。

混淆构建(flutter build --obfuscate --split-debug-info=...)会去除 Dart 名称。blutter 仍能还原结构 — 调用图、对象池、字符串常量 — 但名称已丢失。转而查看 pp.txt:URL、端点路径和错误字符串会在混淆后保留,通常足以定位 API 层,这正是你原本要找的内容。

查看流量

有两个独立的问题,必须同时解决。只修复其中一个,你仍然会面对空代理,而且不知道原因。

问题 1 — Flutter 会忽略系统代理。 Dart 的 HTTP 客户端不会读取 Android/iOS 代理设置,因此设置 Wi-Fi 代理毫无作用。改为在网络层强制转发流量:

# Redirect transparently on the device/emulator
adb shell su -c 'iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to <proxy-ip>:8080'
# or use a VPN-based tunnel (tun2socks / a VPN-mode proxy app)

问题 2 — Flutter 有自己的 CA 存储。 将你的 CA 安装为用户证书,甚至系统证书,都不会让 Flutter 信任它。以下两种方法可行:

# A. reFlutter — patches the Flutter engine to trust your proxy and to
#    reroute traffic. Repackage and re-sign afterwards.
reflutter target.apk           # prompts for the proxy IP
# outputs a patched APK; then:
apksigner sign --ks debug.keystore release.RE.apk

# B. Frida — hook the certificate check inside libflutter.so at runtime.
#    ssl_verify_peer_cert is not exported, so scripts locate it by pattern
#    scanning; the pattern is engine-version specific.
frida -U -f com.target.app -l flutter-ssl-bypass.js

如果可以重新打包,优先使用 reFlutter(它还支持转储快照和套接字级日志记录);如果应用有完整性检查,重新打包会触发检查,或者你无法重新签名,则优先使用 Frida。如果两种方法都失败,备用方案是挂钩 blutter 恢复出的 Dart HTTP 客户端函数——你会失去协议级保真度,但仍能看到请求和响应。

分析应用

获得符号和流量后:

  1. 从 pp.txt 入手。 对象池中包含基础 URL、端点路径、标头名称以及任何嵌入的密钥材料。通常几分钟内就能梳理出 API。
  2. 使用恢复出的函数进行挂钩,并以 blutter_frida.js 为起点——在请求构造器、身份验证令牌处理器和任何本地加密代码附近转储参数和返回值。
  3. 检查平台通道。 Flutter 应用会将生物识别、密钥库和支付功能交由原生代码处理;这些都是普通的 Java/Kotlin 或 Swift 代码,因此可以交给 testing-mobile-applications。
  4. 然后使用 testing-apis 正式测试 API。 上述操作都是为了找到请求;漏洞通常在另一端。

不要接受这些借口

  • “代理没有显示任何内容,所以应用一定没有使用网络。” 它确实在使用网络,只是没有使用你的代理。
  • “我把 CA 安装成系统证书了,所以 TLS 拦截应该能奏效。” Flutter 不会查询系统证书存储。
  • “jadx 什么都没显示,所以应用一定经过了高度混淆。” dex 中本来就没什么可看的。应用在 libapp.so 中。
  • “blutter 运行失败,所以这个构建无法分析。” 这几乎总是 Dart 版本不匹配。读取引擎版本,并据此重新构建 blutter。
  • “代码经过混淆,所以字符串都消失了。” 名称消失了,对象池还在。读取 pp.txt。
  • “我直接手动逆向 arm64 就行。” 没有符号的 Dart AOT 输出极难阅读,而且耗时极长。先恢复符号——这就是全部工作。

参考资料

  • testing-mobile-applications — 更全面的移动应用评估和原生通道
  • testing-apis — 流量可见后测试后端
  • analyzing-binaries — 深入分析引擎本身的原生代码
  • blutter、reFlutter、Frida/objection、jadx、apktool、apksigner

评论

支持 Markdown