reFlutter

Impact-IGPL-3.0活跃维护

用 Python 写的 Flutter 应用逆向框架,能绕过 SSL Pinning,方便做移动端安全测试和漏洞赏金挖掘。

Flutter Reverse Engineering Framework

ios-v3-0451907c2eaa8467e848c0067bfe8ed4发布于 2026-09-22 23:22 UTC2,797star +1 / 7 天294fork同步于 2026-11-10 11:43 UTC

怎么上手

由 README 提炼,执行前请确认
pip3 install reflutter
reflutter main.apk
硬件要求按 README 说明

README 未说明显存或 CPU 要求;支持 Android arm64/arm32/x64 与 iOS arm64 引擎,运行时脚本需 frida-server 17.x(Android 15/16)。

有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

替换或运行时插桩 Flutter 引擎,用于抓包和函数偏移导出的逆向框架

用 Python 写的 Flutter 应用逆向框架,能绕过 SSL Pinning,方便做移动端安全测试和漏洞赏金挖掘。

核心能力

  • 替换为预编译补丁引擎,绕过 boringssl 证书校验
  • 导出 dump.dart 记录函数名、类与指令镜像偏移
  • 生成 frida.js 与 IDA/Ghidra 命名脚本
  • 用 frida-ssl.js 运行时禁用 TLS 校验,无需重打包
  • 支持 Shorebird 应用识别与运行时 dump

容易踩的坑

重打包后必须自行签名对齐,如用 uber-apk-signer;Shorebird 应用不能用 -p 导出 dump,需改用 scripts/frida-dump.js;frida-ssl.js 需要未 strip 的引擎(Shorebird 或 debug/profile 构建),普通 release APK 不适用

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本ios-v3-0451907c2eaa8467e848c0067bfe8ed4
  1. android-v3-0451907c2eaa8467e848c0067bfe8ed4Android v3 – 0451907c2eaa8467e848c0067bfe8ed42026-09-22 · 2026-09-22 23:23 UTC
    查看更新说明

    reFlutter Android engine build (v3). Snapshot hash: 0451907c2eaa8467e848c0067bfe8ed4

  2. ios-v3-0451907c2eaa8467e848c0067bfe8ed4iOS v3 – 0451907c2eaa8467e848c0067bfe8ed4最新正式版2026-09-22 · 2026-09-22 23:22 UTC

    reFlutter iOS engine build (v3). Snapshot hash: 0451907c2eaa8467e848c0067bfe8ed4

  3. android-v2-0451907c2eaa8467e848c0067bfe8ed4Android v2 – 0451907c2eaa8467e848c0067bfe8ed42026-09-22 · 2026-09-22 23:22 UTC
    查看更新说明

    reFlutter Android engine build (v2). Snapshot hash: 0451907c2eaa8467e848c0067bfe8ed4

  4. ios-v2-0451907c2eaa8467e848c0067bfe8ed4iOS v2 – 0451907c2eaa8467e848c0067bfe8ed42026-09-22 · 2026-09-22 23:20 UTC
    查看更新说明

    reFlutter iOS engine build (v2). Snapshot hash: 0451907c2eaa8467e848c0067bfe8ed4

  5. ios-v3-ace654289f5abc240509fc941453ebc5iOS v3 – ace654289f5abc240509fc941453ebc52026-06-15 · 2026-06-15 03:49 UTC
    查看更新说明

    reFlutter iOS engine build (v3). Snapshot hash: ace654289f5abc240509fc941453ebc5

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    stars

    Read more on the blog: https://swarm.ptsecurity.com/fork-bomb-for-flutter/

    reFlutter reverse-engineers Flutter apps by swapping the app's engine for a prebuilt patched one (repack mode) or by instrumenting the app's own engine at runtime (attach mode). What you get:

    • Traffic interception — boringssl certificate verification patched to succeed unconditionally, so Burp (or any proxy) sees the traffic; bypasses several Flutter certificate-pinning implementations. No root or certificate installation needed on Android.
    • Dump mode — a dump.dart JSONL with every function's name, class, library, static-ness, parameter count and code offset into the Dart instructions image, ready for Frida hooking or IDA/Ghidra naming (scripts/dump2disasm.py).
    • Runtime routes where repacking can't reach: a runtime SSL bypass for engines that ship unstripped, and a runtime dumper for Shorebird apps (whose private Dart fork makes patched-engine builds impossible).
    • Manual engine patching via a crafted Dockerfile if you want your own changes.

    Supported engines

    • Android: arm64, arm32, x64 (x64 assets: Flutter >= 3.41);
    • iOS: arm64;
    • Release and profile builds, Stable and Beta channels — coverage is keyed by snapshot hash in enginehash.csv;
    • Pre-monorepo-merge engines (<= 3.27) are built from the archived flutter/engine repo — the 3.24.x assets ship with the same pipeline.

    Install

    # Linux, Windows, MacOS
    pip3 install reflutter
    

    Quick start

    $ reflutter main.apk
    
    Please enter your Burp Suite IP: <input_ip>
    
    SnapshotHash: 8ee4ef7a67df9845fba331734198a953
    The resulting apk file: ./release.RE.apk
    Please sign the apk file
    

    Sign and align the APK — uber-apk-signer works well:

    java -jar uber-apk-signer.jar --allowResign -a release.RE.apk
    

    For an IPA, sign and install the result as usual; the tool prints a reminder.

    Options:

    • -p, --patch-dump — dump mode: the repacked engine emits dump.dart (JSONL: classes/methods/offsets) on start, and the tool writes a ready frida.js next to the output instead of the proxy instructions. Shorebird apps cannot use -p (their private Dart fork's snapshots don't run in patched engines) — dump those at runtime with scripts/frida-dump.js instead (see Shorebird builds).
    • -n, --no-interact — never prompt for a Burp IP (implies 127.0.0.1); useful for old engines in CI.
    • -b <Snapshot_Hash>, --build-engine — engine build mode: print the engine commit for a snapshot hash and (when run inside an engine checkout) apply the reFlutter source patches. See Build Engine.

    Traffic interception

    Point the app at a proxy on the same network. Configure the Burp listener:

    • Add port: 8083, bind to All interfaces;
    • Request handling: Support invisible proxying = True.

    Android — set the device proxy, then install the repacked APK:

    adb -s <device> shell "settings put global http_proxy <proxy_ip:port>"
    

    Optionally route everything through Burp with TunProxy.

    iOS — install the signed IPA and configure Potatso (or any per-app proxy tool) to use your Burp listener.

    ⚠️ Proxy routing by era: engines up to and including Flutter 3.24.x (snapshot hash 80a49c7111088100a233b2ae788e1f48) carry a hardcoded proxy IP that gets patched in place. From 3.27.x on, the hardcoded IP is gone — configure the proxy directly on the device as shown above.

    Dump mode

    Run with -p, start the app, and pull the JSONL dump:

    reflutter -p main.apk && java -jar uber-apk-signer.jar --allowResign -a release.RE.apk
    adb shell "cat /data/data/<PACKAGE_NAME>/dump.dart" > dump.dart
    

    On iOS the dump lands in the app container; the console log prints the exact path.

    {"method_name":"_handleRequest","offset":"0x00000000000a8740","library_url":"package:anyapp/api/client.dart","class_name":"ApiClient","is_static":"false","parameter_count":"2"}
    

    Offsets are relative to the Dart instructions image start (_kDartIsolateSnapshotInstructions / _kDartSnapshotText), not the ELF base. Two ways to use them:

    • Frida — the auto-written frida.js resolves the instructions symbol automatically (newer Dart exports _kDartSnapshotText, older _kDartIsolateSnapshotInstructions) and hooks an offset you fill in:

      frida -U -f <package> -l frida.js
      

      Works across Frida 14–17; prefer recent frida-server (16.x servers predate Android 15+ and cannot inject there — use 17.x).

    • Static analysis — generate naming scripts for IDA and Ghidra:

      python3 scripts/dump2disasm.py dump.dart
      

    Runtime routes (no repack)

    frida-ssl.js disables TLS verification without repacking at all by patching boringssl inside the loaded libflutter.so:

    frida -U -f <package> -l frida-ssl.js
    

    It resolves the internal-linkage verification function from .symtab, so it needs an engine that still carries a symbol table: Shorebird engines (ship unstripped, ~150 MB) and debug/profile builds qualify. Stock release APKs ship stripped engines — the bucket's symbols.zip is a separate link whose addresses do not transfer — so for those use reFlutter repack mode, which swaps in a prebuilt engine with the bypass compiled in. arm, arm64 and x64 are handled per-ISA; other arches abort without writing anything. Requires frida-server 17.x on Android 15/16 (16.x kills system_server there; 17.9.9 verified on API 36).

    Shorebird builds

    Apps built with Shorebird use a patched Flutter engine whose snapshot hash differs from the vanilla release it is based on. reFlutter identifies these automatically (a hash found only in enginehash_sb.csv identifies a Shorebird app even when flutter_assets/shorebird.yaml is absent).

    Traffic interception works like any other app — reflutter app.apk/ipa — but with no engine build behind it: Shorebird's own engine artifact is fetched from their public bucket, boringssl's certificate-chain verification is patched to succeed unconditionally (a pure-Python ELF/Mach-O walk — symbol table to file offset to a per-ISA patch — after which the ~150 MB of shipped symbols are dropped, since Android's linker only reads program headers), and the app is repacked with it.

    Dump mode runs at runtime instead — our patched engines cannot run Shorebird snapshots (their code lives in patchable regions understood only by their private Dart fork's loader — verified empirically), but the engine Shorebird ships inside the APK is unstripped. scripts/frida-dump.js hooks the app's own libflutter.so at FunctionDeserializationCluster::PostLoad — the exact splice point of the engine patch — and replays its JSONL dump by reading raw Dart object layouts, deriving the instructions-image base at runtime:

    frida -D <device> -f <package> -l scripts/frida-dump.js
    adb pull /data/data/<package>/dump.dart .
    python3 scripts/dump2disasm.py dump.dart
    

    Requires an arm64 AOT app and the stock, unrepacked engine (repacked copies are stripped — the script fails loudly there). Offsets use the same instructions-image convention as engine dumps; names carry the raw Class@12345 form (strictly more information than the engine patch's scrubbed names); parameter_count is unreliable on Shorebird snapshots. Validated live: 6,957 functions, offsets arm64-spot-checked against the APK's instructions image, consumed downstream by dump2disasm.

    Notes: Android requires the engine artifact to carry a symbol table — recent revisions (Aug 2025+) ship with one; some older revisions are stripped and fail loudly. iOS requires a dSYM from the same build; dSYM availability varies by engine revision. The resulting IPA must be re-signed, as the tool's output already instructs.

    Profile and Debug builds

    Profile apps carry the same snapshot hash as their release counterparts (verified across engines — the hash covers the VM sources, not the runtime mode), so they work with the regular release engine assets; scripts/gen_enginehash.py --profile re-verifies this as new engines ship.

    Debug builds are genuinely different (JIT kernel snapshots, no AOT libapp.so, debug artifacts embed the engine commit rather than a snapshot hash) — there is nothing to repack, and nothing to dump. For traffic analysis use frida-ssl.js, which runs on any engine that keeps its symbol table, debug builds included.


    Maintainers

    Build Engine

    Engines are built with scripts/local-release (macOS; builds the traffic and dump variants for iOS + Android arm64/arm/x64, verifies every patch landed, and uploads the release assets), keyed by the snapshot hashes in enginehash.csv. The engine commit for a snapshot hash resolves via reflutter -b <Snapshot_Hash>. Pre-monorepo-merge engines (<= 3.27) are fetched from the archived flutter/engine repo and built with the matching gclient layout — the era needs a handful of toolchain compatibility patches (dead mirror pins, a libcxx roll against newer macOS SDKs), all applied automatically by the build. Backfill past hashes with scripts/backfill '<hash> ...'.

    Hash-list refresh

    scripts/update-enginehash refreshes the three CSVs — run it manually whenever you want the lists current; it is incremental and idempotent (seconds when nothing changed). On an always-on machine you can install a weekly launchd agent instead:

    scripts/install-enginehash-agent   # Mondays 04:23; removal command printed
    

    Custom Build

    Manual Flutter code patching is supported using Docker:

    git clone https://github.com/Impact-I/reFlutter && cd reFlutter
    docker build -t reflutter -f Dockerfile .
    

    Run with:

    docker run -it -v "$(pwd):/t" -e HASH_PATCH=<Snapshot_Hash> -e COMMIT=<Engine_commit> reflutter
    

    Flags:

    • -e x64=0 / -e arm64=0 / -e arm=0: disable that arch's build
    • -e WAIT=300: time in seconds to modify source before build
    • -e HASH_PATCH: snapshot hash from enginehash.csv
    • -e COMMIT: engine commit hash