MachineCase/blutter-macos
GitHub: MachineCase/blutter-macos
Stars: 2 | Forks: 0
# blutter-macos
Patches and scripts to run [blutter](https://github.com/worawit/blutter) on macOS standalone Dart AOT binaries (`dart compile exe`).
Blutter supports Android `libapp.so` and iOS `App.framework`. This extends it to macOS standalones, where the snapshot is embedded as an `LC_NOTE` inside the outer binary rather than in a separate file.
See the write-up: [machinecase.github.io/posts/dart-reverse-macos](https://machinecase.github.io/posts/dart-reverse-macos/)
## How it works
`dart compile exe` produces a single Mach-O that contains the Dart VM runtime (what you see in Binary Ninja) and the compiled app snapshot (what you want to analyze) embedded as opaque data in an `LC_NOTE` named `__dart_app_snap`.
The scripts extract the inner Mach-O and wrap it in a synthetic ELF so blutter can parse it using its existing ELF code path.
## Usage
# 1. Extract inner Mach-O and create ELF wrapper
python3 scripts/extract_snapshot.py ./binary /tmp/analysis/
# 2. Apply patches to blutter
cd /path/to/blutter
git apply /path/to/blutter-macos/patches/macos_standalone_aot.patch
# 3. Run blutter
python3 blutter.py \
/tmp/analysis/dart_snapshot.so \
/tmp/analysis/blutter_out \
--dart-version 3.11.4_macos_arm64
# 4. Triage
grep "String:" /tmp/analysis/blutter_out/pp.txt | grep -v "dart:"
# 5. Import symbols into Binary Ninja
# Open inner.macho, then in Python Console:
exec(open('scripts/import_symbols_bn.py').read())
## Patches
Four files in blutter need changes:
- `scripts/CMakeLists.txt` — add `macos` as valid `TARGET_OS` with correct defines
- `dartvm_fetch_build.py` — macOS standalone uses `no-compressed-pointers`
- `blutter/src/ElfHelper.cpp` — detect ELF magic before Mach-O path, fix `MH_MAGIC_64` case, uncomment `mach_o.h` include
- `blutter/src/Disassembler_arm64.h` — move `CSREG_DART_HEAP` outside `#ifdef DART_COMPRESSED_POINTERS`
## Tested
Dart 3.11.4, macOS ARM64 (Apple Silicon).