9 Commits
Author SHA1 Message Date
pancake 788644990e Better structure to reduce locs 2026-07-05 16:06:34 +02:00
pancake c0569e58e3 Use the script to sync with the missing 21 versions of Dart 2026-07-03 21:01:41 +02:00
pancake 5cf313c681 Refactor version metadata: single offsets.json, remove CID fields from DartVerLayout
- Consolidate all version metadata into offsets.json as the single source
  of truth (hashes, version profiles, offset arrays)
- Remove CID fields (cid_class, cid_function, cid_code, cid_string, ...)
  from DartVerLayout struct — all CID lookups now go through dart_cid.c's
  cid_tables[] via dart_cid_get()
- Remove CID fast-path switch from dart_cid_get(); always use cid_tables[]
- Replace l->cid_* references in dart_pool_parse.c and dart_pool_names.c
  with dart_cid_get(l, DART_CID_*) calls
- Remove CID fallback assignments from dart_pick_layout_by_hash()
- Delete obsolete scripts/derive_offsets.py and scripts/gen_offsets.sh
- Add `make gen` target to regenerate C files from offsets.json
- Update doc/learn.md, doc/support.md, INFO.md, and test expectations
2026-07-03 20:33:44 +02:00
pancake 553d583298 Dont remove rconfig vars on fini when building the plugin incore 2026-07-03 18:24:33 +02:00
Abhi 78013b15e1 Add support for Dart 3.11.x and 3.12.x snapshot profiles
- Update snapshot hash mapping for Dart 3.11.5, 3.12.0, and 3.12.1.
- Add CID and layout profiles for the new versions.
- Document that snapshot hashes are shared across patch-release groups.
- Update documentation and test expectations.
2026-06-29 19:13:54 +05:30
pancake 20d18a1694 Add hash for Dart 3.1.3 2026-06-27 19:05:06 +02:00
pancake 06adc8d617 Use R_NEW instead of calloc 2026-06-27 19:03:57 +02:00
pancake a86cf02636 Alphabetically sort the commandline flags 2026-06-25 02:07:43 +02:00
pancake 91c3e94630 Allow to override the DartVersion from cli (-D)
* Useful for hacked binaries and fuzzy analysis for unknown/unsupported builds
2026-06-25 02:04:25 +02:00
26 changed files with 1858 additions and 2809 deletions

No files matched your search

+12 -11
View File
@@ -4,7 +4,7 @@ Overview
- Goal: Extract real Dart function names and entrypoints from Flutter/Dart AOT snapshots (libapp.so) without relying on afl/aflj or the Dart VM.
- Tools:
- r2flutter: Small C utility that loads `libapp.so` with radare2, locates AOT snapshots, and decodes the ObjectPool to emit names + addresses.
- scripts/gen_offsets.sh: Generates a per-snapshot-hash offsets file (`r2flutter/offsets.json`) to keep the decoder stable across Dart versions.
- scripts/update-dart-version: Unified script that pulls the Dart SDK, computes the snapshot hash, extracts CID values, and updates all tables.
- Key property: r2flutter builds standalone (no Dart VM headers/libs) and does not parse afl output.
Repo Layout (relevant parts)
@@ -17,14 +17,14 @@ Repo Layout (relevant parts)
- third_party/dartvm/: Vendored VM sources (headers only) to document snapshot/cluster formats used by the decoder (no linking).
- arm64-v8a/: Example directory with libapp.so/libflutter.so for testing.
- scripts/
- gen_offsets.sh: Generates `r2flutter/offsets.json` keyed by snapshot hash using only local binaries + curl (when needed for future enhancement).
- update-dart-version: Unified script to add new Dart versions (pulls SDK, computes hash, extracts CIDs, updates all tables).
- blutter/: Standalone C++ reference implementation (with VM linkage) used as conceptual reference. r2flutter must not depend on it.
Quick Start
- Requirements: radare2 development headers (pkg-config), make, a libapp.so and libflutter.so pair.
- Generate offsets for your libapp:
- `./scripts/gen_offsets.sh r2flutter/arm64-v8a`
- This produces `r2flutter/offsets.json` keyed by snapshot hash (read from VM snapshot data in libapp.so).
- `./scripts/update-dart-version --hash <snapshot-hash> <dart-version>`
- This produces `r2flutter/offsets.json` keyed by snapshot hash.
- Build and run r2flutter:
- `make -C r2flutter`
- `./bin/r2flutter r2flutter/arm64-v8a r2flutter/out`
@@ -59,13 +59,14 @@ Usage in radare2 sessions (Android ELF and iOS Mach-O)
- You’ll see `method.*` flags and comments across the binary.
Maintaining for New Dart Versions
1) Generate/Update offsets.json:
- Run: `./scripts/gen_offsets.sh <dir-with-libapp+libflutter>`
- This produces a new `hash → { compressed_word_size, heap_object_tag }` entry in `r2flutter/offsets.json`.
- For deeper stability (field offsets), enhance `gen_offsets.sh` to:
- `curl` the VM sources for the detected Dart version/commit (e.g., class_id.h, object.h, app_snapshot.cc).
- Parse constants and offsets to compute a richer layout JSON.
- Commit the updated offsets.json.
1) Add a new Dart version:
- Run: `./scripts/update-dart-version <dart-version>`
- This pulls the Dart SDK from GitHub, computes the snapshot hash (MD5 of VM source files),
extracts CID values from class_id.h, and updates both `offsets.json` and `src/lib/dart_version.c`.
- For a local SDK checkout: `./scripts/update-dart-version --sdk-dir /path/to/dart-sdk <version>`
- To add a hash manually (no SDK pull): `./scripts/update-dart-version --hash <md5> <version>`
- To regenerate all tables from known data: `./scripts/update-dart-version --regenerate`
- Commit the updated offsets.json and dart_version.c.
2) Decoder tuning:
- If the clustered snapshot changes (e.g., new EntryType or field order), adjust the decoder logic in `dart_pool_parse.c` referencing `third_party/dartvm/` sources.
- Avoid adding a runtime dependency: keep vendored snapshots sources only as references (no linking).
+4
View File
@@ -36,6 +36,10 @@ INC_VER = $(SRC_DIR)/../include/r2flutter/r2flutter_version.h
all: $(BIN_FILE) $(INC_VER)
# Regenerate C files from offsets.json (the single source of truth)
gen:
python3 scripts/update-dart-version --generate
$(INC_VER):
./configure
+8 -1
View File
@@ -54,9 +54,9 @@ Usage: bin/r2flutter [options] <libapp_path_or_dir>
Modifiers:
-h Show help
-j Output in JSON format
-n Heuristic fallback for unknown functions; may assign wrong names
-q Compact output; suppress non-essential detail
-r Output r2 commands for the selected action
-n Heuristic fallback for unknown functions; may assign wrong names
-v Verbose (stderr debug info)
-vv More verbose (dump headers)
-V Show version
@@ -79,6 +79,7 @@ Actions:
-z Print reliable ObjectPool-referenced strings (-q prints values only)
-zz Print all fuzzy/carved extracted strings (-xzz includes refs/ax in -r)
Options:
-D <hash|version> Override Dart snapshot profile for analysis
-l <N> Limit output to N items
-m <file> Load Flutter obfuscation map JSON
```
@@ -92,6 +93,10 @@ first (`libapp.so`), then iOS (`Frameworks/App.framework/App`).
`-n` is intentionally opt-in. It consumes `package:` and `dart:` strings from the data image as a sequential fallback for otherwise unnamed functions, so it can produce plausible but incorrect names when the string order does not match the instruction table.
`-D` forces the Dart profile used for layout/CID decoding without patching the
input binary. Pass either a known 32-byte snapshot hash or a supported Dart
version such as `3.8.1`.
`-S` emits a best-effort recovered component report, not a complete dependency
inventory. JSON output uses `format: "r2flutter-recovered-sbom"` and
`complete: false`; package versions are usually `null` unless explicit packaged
@@ -122,6 +127,7 @@ r2flutter -A analyze and apply flags/comments
r2flutter -AA analyze with field extraction enabled
r2flutter -AAA run Dart-aware code analysis and recover refs/comments
r2flutter -C apply Dart classes, fields, methods and types
r2flutter -D 3.8.1 override Dart snapshot profile for analysis
r2flutter -jS print recovered components/SBOM as JSON
r2flutter -r -p map a synthetic ObjectPool and set anal.gp/x27
```
@@ -130,6 +136,7 @@ Plugin config keys:
- `r2flutter.mapfile`: Flutter obfuscation map JSON path
- `r2flutter.namepool`: enable heuristic name-pool fallback
- `r2flutter.profile`: override Dart profile by snapshot hash or Dart version
## Dependencies
+14 -3
View File
@@ -125,7 +125,7 @@ If you need to extract version-specific logic from the Dart SDK source :
## Summary
**You do NOT need to download anything at runtime.** The version hash in the snapshot header (32-byte ASCII at offset 0x04) maps to a finite set of constraint profiles that can be statically defined. unflutter proves this works for all Dart versions from 2.10.0 to 3.10.7 without any runtime SDK compilation or network downloads .
**You do NOT need to download anything at runtime.** The version hash in the snapshot header (32-byte ASCII at offset 0x04) maps to a finite set of constraint profiles that can be statically defined. unflutter proves this works for all Dart versions from 2.10.0 to 3.12.1 without any runtime SDK compilation or network downloads .
The only time you'd need dynamic updates is when Flutter releases a new version with breaking snapshot format changes - which happens infrequently and follows a predictable release cycle (stable, beta, dev channels) .
@@ -136,7 +136,7 @@ The only time you'd need dynamic updates is when Flutter releases a new version
r2flutter implements Option 1 (Static Constraint Tables) from this document. The implementation in `src/lib/dart_pool_parse.c` includes:
### Hash-to-Version Mapping
- 40+ known snapshot hashes from Flutter 1.22.x (Dart 2.10.0) to Flutter 3.38.x (Dart 3.10.7)
- 40+ known snapshot hashes from Flutter 1.22.x (Dart 2.10.0) to Flutter 3.41.x (Dart 3.12.1)
- Sources: unflutter version.go, reFlutter enginehash.csv, blutter precompiled SDKs
### Version Profiles
@@ -154,7 +154,18 @@ Each supported Dart version has a profile with:
| 2.13.0 | Int32 CID | Split canonical/non-canonical clusters |
| 2.14.0-2.17.6 | CID Shift1 | `(cid << 1) \| canonical` |
| 2.18.0-3.3.0 | CID Shift1 | Various CID changes |
| 3.4.3-3.10.7 | ObjectHeader | CID at bits 12-31 |
| 3.4.3-3.12.1 | ObjectHeader | CID at bits 12-31 |
Unknown hashes fall back to v3.9.2 profile with ObjectHeader encoding.
## Snapshot Hashes Are Shared Within Patch-Groups
A snapshot hash typically covers a group of patch releases within a minor line,
but not necessarily the entire minor version. For example, Dart 3.0.0-3.0.2 share
one hash while 3.0.3-3.0.7 use a different one; Dart 3.11.0-3.11.1 share a hash
separate from 3.11.3-3.11.5; Dart 3.12.0 and 3.12.1 each have distinct hashes.
The version string in the mapping table uses the latest known patch in the group
(e.g., `3.1.3` for the 3.1.x group, `3.11.5` for the 3.11.3-3.11.5 group).
The snapshot format (CID table, tag encoding, layout) is identical across all
patch versions sharing the same hash.
+92 -1
View File
@@ -573,7 +573,7 @@ The `instruction_table_data_offset` field points into the Data Image.
The 32-byte ASCII MD5 hash at offset 0x14 identifies the exact Dart VM version and snapshot format. This hash maps to a finite set of constraint profiles that can be statically defined.
r2flutter maintains 40+ known snapshot hashes from Flutter 1.22.x (Dart 2.10.0) to Flutter 3.38.x (Dart 3.10.7).
r2flutter maintains 40+ known snapshot hashes from Flutter 1.22.x (Dart 2.10.0) to Flutter 3.41.x (Dart 3.12.1).
### Version Profiles Include:
- Tag encoding style (CID-Int32, CID-Shift1, ObjectHeader)
@@ -1036,3 +1036,94 @@ mapping. On the `mafia` fixture, `-f` recovers many
`method.IsarCoreBindings.isar_*` Dart wrappers and `-z` recovers `libisar.so`
plus `isar_*` strings, but the fixture does not ship `libisar.so`, so no final
native vaddr is available statically; keep obfuscation-expanded semantic names heap-owned (`char *`) so lookup keys are not truncated.
## Snapshot Profile Overrides
The snapshot hash embedded in a binary normally selects the Dart layout profile,
but patched samples can carry a misleading hash. `-D <hash|version>` overrides
the profile used by r2flutter analysis without modifying the input binary. A
32-byte hash is treated as the effective snapshot hash; a Dart version string
such as `3.8.1` selects the static profile for that version.
## Offset Table Management
**Finding**: The offset arrays (`code_entry_point_offsets`, `code_owner_offsets`,
`function_name_offsets`) are **identical across the known Dart versions**
(`2.10.0`-`3.12.2`). They are stored once under a top-level `defaults` key in
`offsets.json` and hardcoded as fallback in `init_layout_hints ()` in
`dart_pool_names.c`.
**Maintenance workflow**:
1. **Adding a new Dart version** (pulls SDK, computes hash, extracts CIDs):
`./scripts/update-dart-version 3.13.0`
2. **Adding from a local SDK checkout**:
`./scripts/update-dart-version --sdk-dir /path/to/dart-sdk 3.13.0`
3. **Adding a hash manually** (no SDK pull):
`./scripts/update-dart-version --hash <md5> 3.13.0`
4. **Regenerating all tables** from known data:
`./scripts/update-dart-version --generate`
5. **Syncing stable Dart SDK tags**:
`./scripts/update-dart-version --sync-stable-tags --min-version 2.10.0`
6. **List known versions**:
`./scripts/update-dart-version --list`
**Data sources**:
- `offsets.json` — the source of truth. `hashes` maps snapshot MD5 values to
exact Dart version strings, while `profiles` is range-keyed by the first
version that introduced a layout/CID tuple.
- `src/lib/dart_version.c` — generated `known_hashes[]` plus range-start
`version_profiles[]`.
- `src/lib/dart_cid.c` — generated range-start CID tables.
- `third_party/sdk/runtime/vm/class_id.h` — Dart SDK source defining CID enum
values.
**Key insight**: A Dart version `V` uses the profile with the greatest
range-start key `<= V`. Most new Dart patch releases therefore add only one
line under `hashes`; a new `profiles` line is needed only when the layout or CID
table actually changes. Unknown hashes still use the hardcoded modern fallback.
## The `first` Android Fixture Uses ObjectHeader Tags
The `test/bins/android/first` snapshot hash `f91b8b03bf7f30a5e983fd19b23d978d`
maps to Dart `2.18.2`, but its serialized heap objects use ObjectHeader CID
bits. For example, the tagged object `0x1651` points at `0x1650`, whose header
decodes CID `93` only via `(header >> 12) & 0xfffff`; interpreting it as
`CID_SHIFT1` makes `-O` report an unresolved raw value. Keep the `2.18.2`
profile as `OBJECT_HEADER` unless another fixture proves a hash-specific split
is needed. The standalone `dart-lang/sdk` `2.18.2` tag also has a different CID
table (`String=90`, `NumPredefinedCids=159`) from this Flutter-engine fixture,
so the generator keeps `2.18.2` on the `3.9.2`-shaped fallback CID table used by
the sample. This is documented as a Flutter-engine snapshot quirk, not as
standalone Dart SDK `2.18.2` CID data.
## Dart SDK Stable Tag Refresh
Running `scripts/update-dart-version --sync-stable-tags --min-version 2.10.0`
against `dart-lang/sdk` found 118 stable numeric tags from `2.10.0` through
`3.12.2`. In expanded form those tags collapse to 19 range profiles and 61
distinct hashes. The duplicate-hash aliases all had matching CID signatures, so
a hash can still map to one representative version without losing CID
correctness for explicit version overrides.
The only profile mismatch against the current inference rules is still
`2.18.2`: the source-derived default would be `CID_SHIFT1`, but the in-tree
Android fixture needs `OBJECT_HEADER`. Keep preserving existing profiles during
batch syncs unless a fixture proves the inferred profile is better. The same
fixture also needs a CID-table alias because the standalone SDK tag's CID table
does not match the Flutter-engine snapshot.
The previous sync parser did not understand Dart `3.12.x`'s `CLASS_ID_LIST`
macro form and emitted an empty CID table for `3.12.0+`. The parser now expands
that macro form; Dart `3.12.x` floors to the same modern CID family as `3.9.x`
(`String=93`, `ObjectPool=23`, `NumPredefinedCids=175`).
Older tags `2.10.0` through `2.14.4` do not contain `runtime/vm/app_snapshot.cc`
or `runtime/vm/app_snapshot.h`. The generator reports those missing hash inputs
and computes the MD5 from the files present in that tag, matching the existing
script behavior for local SDK checkouts.
+14 -8
View File
@@ -17,8 +17,8 @@ instruction tables, and strings directly.
| Mach-O details | Thin Mach-O64 and fat Mach-O/fat64; arm64 slice is preferred. LC_NOTE owner `__dart_app_snap` is detected and the embedded Dart Mach-O payload is extracted to a temporary file. |
| Architecture | ARM64/AArch64 is the real target. Instruction-table entrypoints are based on ARM64 code offsets, PP tracking uses `x27`, and the radare2 analysis pass understands AArch64 registers/op metadata. |
| Snapshot kind | Clustered Dart AOT snapshots with magic `0xdcdcf5f5`, 32-byte snapshot hashes, feature strings, and unsigned varint header fields. |
| Dart layouts | In-tree profiles cover Dart `2.10.0` through `3.10.7`, roughly Flutter `1.22.x` through `3.38.x`. |
| Unknown hashes | First tries `r2flutter/offsets.json` or `offsets.json`; otherwise uses v3.9.2-shaped ObjectHeader defaults while reporting the Dart version as `unknown`. |
| Dart layouts | In-tree profiles cover Dart `2.10.0` through `3.12.1`, roughly Flutter `1.22.x` through `3.41.x`. |
| Unknown hashes | Falls back to hardcoded default offsets (8/24/16/32 for entry points, 56 for owner, 24/8 for names) + v3.9.2-shaped ObjectHeader defaults while reporting the Dart version as `unknown`. |
| Obfuscation maps | Flutter/Dart `--save-obfuscation-map` JSON arrays are supported with `-m <file>` or `e r2flutter.mapfile=<file>` in the plugin. |
## Layout Profiles
@@ -44,7 +44,7 @@ The CID column is compacted as:
| 2.18.0 | 3.3.x | `CID_SHIFT1` | 4 | 5 | 159 | `5/7/17/90/91/92/87/59/21` | SuspendState added. |
| 2.19.0 | 3.7.x | `CID_SHIFT1` | 4 | 5 | 176 | `5/7/17/92/93/94/89/60/21` | RecordType/Record added. |
| 3.0.5 | 3.10.x - 3.12.x | `CID_SHIFT1` | 4 | 5 | 177 | `5/7/18/93/94/95/90/61/22` | WeakArray added. |
| 3.1.0 | 3.13.x | `CID_SHIFT1` | 4 | 5 | 176 | `5/7/18/92/93/94/89/60/22` | TypeRef removed. |
| 3.1.3 | 3.13.x | `CID_SHIFT1` | 4 | 5 | 176 | `5/7/18/92/93/94/89/60/22` | TypeRef removed. |
| 3.2.5 | 3.16.x | `CID_SHIFT1` | 4 | 5 | 176 | `5/7/18/92/93/94/89/60/22` | PoolType swapped. |
| 3.3.0 | 3.19.x | `CID_SHIFT1` | 4 | 5 | 176 | `5/7/18/92/93/94/89/60/22` | Last Shift1 profile in-tree. |
| 3.4.3 | 3.22.x | `OBJECT_HEADER` | 4 | 5 | 174 | `5/7/18/92/93/94/89/60/22` | ObjectHeader tag encoding begins. |
@@ -54,6 +54,9 @@ The CID column is compacted as:
| 3.8.1 | 3.32.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Same modern profile family. |
| 3.9.2 | 3.35.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Unknown-hash fallback baseline. |
| 3.10.7 | 3.38.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Newest in-tree profile. |
| 3.11.5 | 3.39.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Same modern profile family. |
| 3.12.0 | 3.41.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Same modern profile family. |
| 3.12.1 | 3.41.x | `OBJECT_HEADER` | 4 | 5 | 175 | `5/7/18/93/94/95/90/61/23` | Same modern profile family. |
All profiles use heap object tag `1`, default alignment `16`, and instruction
table capacity `20000` before feature-flag or `offsets.json` adjustments.
@@ -73,7 +76,7 @@ These hashes are mapped directly by `src/lib/dart_version.c`.
| 2.18.0 | `b0e899ec5a90e4661501f0b69e9dd70f`, `b6d0a1f034d158b0d37b51d559379697`, `8e50e448b241be23b9e990094f4dca39`, `6a9b5a03a7e784a4558b10c769f188d9` |
| 2.19.0 | `adb4292f3ec25074ca70abcd2d5c7251`, `501ef5cbd64ca70b6b42672346af6a8a` |
| 3.0.5 | `90b56a561f70cd55e972cb49b79b3d8b`, `aa64af18e7d086041ac127cc4bc50c5e`, `36b0375d284ee2af0d0fffc6e6e48fde`, `16ad76edd19b537bf6ea64fdd31977a7` |
| 3.1.0 | `7dbbeeb8ef7b91338640dca3927636de` |
| 3.1.3 | `7dbbeeb8ef7b91338640dca3927636de` |
| 3.2.5 | `f71c76320d35b65f1164dbaa6d95fe09` |
| 3.3.0 | `ee1eb666c76a5cb7746faf39d0b97547` |
| 3.4.3 | `d20a1be77c3d3c41b2a5accaee1ce549` |
@@ -83,11 +86,14 @@ These hashes are mapped directly by `src/lib/dart_version.c`.
| 3.8.1 | `830f4f59e7969c70b595182826435c19` |
| 3.9.2 | `97ff04a728735e6b6b098bdf983faaba` |
| 3.10.7 | `1ce86630892e2dca9a8543fdb8ed8e22` |
| 3.11.5 | `78da37fed6bf1489361a312568249f3f` |
| 3.12.0 | `41be3daaabd524b8aa7423bc24584957` |
| 3.12.1 | `ace654289f5abc240509fc941453ebc5` |
`offsets.json` can enrich or override a hash with `compressed_word_size`,
`heap_object_tag`, `max_alignment`, `it_cap`, `code_entry_point_offsets`,
`code_owner_offsets`, and `function_name_offsets`. The code looks for it first
under `r2flutter/offsets.json`, then in the current directory as `offsets.json`.
`include/r2flutter/dart_offsets.h` contains the hash→compressed_word_size lookup
table and the default offset arrays, compiled statically into r2flutter. No
external JSON file is needed at runtime. The header is auto-generated by
`scripts/update-dart-version`.
## Snapshot Discovery
+88
View File
@@ -0,0 +1,88 @@
// Auto-generated from offsets.json by scripts/update-dart-version
// Hash to compressed_word_size lookup table
#ifndef R2C_DART_OFFSETS_H
#define R2C_DART_OFFSETS_H
#include <stdint.h>
// Hash entry: snapshot MD5 hash (32 hex chars) + compressed_word_size
typedef struct {
const char hash[33];
int compressed_word_size;
} DartHashEntry;
static const DartHashEntry dart_hash_entries[] = {
{ "0c7f1aa25fc597a7b3b9a19ed390afa1", 8 }, // Dart 2.13.0
{ "0eb277b50d6ce4069261c69150ce52c9", 4 }, // Dart 2.17.0
{ "1441d6b13b8623fa7fbf61433abebd31", 4 }, // Dart 2.17.6
{ "16ad76edd19b537bf6ea64fdd31977a7", 4 }, // Dart 3.0.5
{ "1ce86630892e2dca9a8543fdb8ed8e22", 4 }, // Dart 3.10.7
{ "24d9d411c2f90c8fbe8907f99e89d4b0", 8 }, // Dart 2.15.0
{ "2858c2c0920495f00b9bce9edf6a8cd9", 4 }, // Dart 3.6.2
{ "287683014dfbd311f6400c655c97a26d", 4 }, // Dart 2.18.6
{ "30c051cb9192f6d6812be3f0b87a6356", 4 }, // Dart 3.6.0
{ "3318fe66091c0ffbb64faec39976cb7d", 8 }, // Dart 2.16.0
{ "34f6eec64e9371856eaaa278ccf56538", 8 }, // Dart 2.13.0
{ "36b0375d284ee2af0d0fffc6e6e48fde", 4 }, // Dart 3.0.5
{ "41be3daaabd524b8aa7423bc24584957", 4 }, // Dart 3.12.0
{ "501ef5cbd64ca70b6b42672346af6a8a", 4 }, // Dart 2.19.0
{ "5191d02bb1d36a9f8609aa7495894e76", 4 }, // Dart 3.1.0
{ "6093345773c65683f60c20c8e62cbe4a", 8 }, // Dart 2.16.0
{ "617d044d9faa87a98c29f8aad5d2f220", 4 }, // Dart 3.0.3
{ "659a72e41e3276e882709901c27de33d", 8 }, // Dart 2.14.0
{ "6a9b5a03a7e784a4558b10c769f188d9", 4 }, // Dart 2.18.0
{ "71dcc635f2e5dca494525aa13ca9006b", 4 }, // Dart 3.5.0
{ "77b867742ae1ace67fbbb9a9a0d0334e", 4 }, // Dart 3.3.0
{ "77bd0a83c49bfc555a44a0740f15003a", 4 }, // Dart 2.18.0
{ "78da37fed6bf1489361a312568249f3f", 4 }, // Dart 3.11.5
{ "7a5b240780941844bae88eca5dbaa7b8", 8 }, // Dart 2.13.0
{ "7b96ef6dda75bdd1d70be8c2f7cb814e", 8 }, // Dart 2.15.0
{ "7dbbeeb8ef7b91338640dca3927636de", 4 }, // Dart 3.1.3
{ "80a49c7111088100a233b2ae788e1f48", 4 }, // Dart 3.5.0
{ "830f4f59e7969c70b595182826435c19", 4 }, // Dart 3.8.1
{ "8e50e448b241be23b9e990094f4dca39", 4 }, // Dart 2.18.0
{ "8ee4ef7a67df9845fba331734198a953", 8 }, // Dart 2.10.0
{ "90b56a561f70cd55e972cb49b79b3d8b", 4 }, // Dart 3.0.5
{ "97ff04a728735e6b6b098bdf983faaba", 4 }, // Dart 3.9.2
{ "9cf77f4405212c45daf608e1cd646852", 8 }, // Dart 2.14.0
{ "9d6362266b78e4198f784da1a28fd82b", 8 }, // Dart 3.2.0
{ "a0cb0c928b23bc17a26e062b351dc44d", 4 }, // Dart 2.17.6
{ "aa64af18e7d086041ac127cc4bc50c5e", 4 }, // Dart 3.0.5
{ "ace654289f5abc240509fc941453ebc5", 4 }, // Dart 3.12.1
{ "adb4292f3ec25074ca70abcd2d5c7251", 4 }, // Dart 2.19.0
{ "adf563436d12ba0d50ea5beb7f3be1bb", 8 }, // Dart 2.16.0
{ "afcf461a16dfa5e88f88a2aa68764c99", 4 }, // Dart 2.19.0
{ "b0e899ec5a90e4661501f0b69e9dd70f", 4 }, // Dart 2.18.0
{ "b6d0a1f034d158b0d37b51d559379697", 4 }, // Dart 2.18.0
{ "bae16a6858d8c0fe2c437b275eb807cd", 4 }, // Dart 3.7.0
{ "c03fb294bfdaca2b44c552ad35e52d45", 8 }, // Dart 2.14.0
{ "cda356e9bae476c70de33809fd92e009", 4 }, // Dart 3.5.0
{ "ce5d37cf26ea4faac543cd216f3b96d1", 4 }, // Dart 3.0.0
{ "d20a1be77c3d3c41b2a5accaee1ce549", 8 }, // Dart 3.4.3
{ "d56742caf7b3b3f4bd2df93a9bbb5503", 8 }, // Dart 2.16.0
{ "d91c0e6f35f0eb2e44124e8f42aa44a7", 4 }, // Dart 3.7.0
{ "d979fa911b038a8682e98cc8c8569261", 8 }, // Dart 2.10.0
{ "ded6ef11c73fdc638d6ff6d3ad22a67b", 4 }, // Dart 2.17.6
{ "e036be9d5df68283e1a043e348fa7ff4", 8 }, // Dart 2.12.0
{ "e4a09dbf2bb120fe4674e0576617a0dc", 8 }, // Dart 2.13.0
{ "e727fae79fb45aac639252a9453b785e", 4 }, // Dart 2.19.1
{ "ee1eb666c76a5cb7746faf39d0b97547", 4 }, // Dart 3.3.0
{ "f10776149bf76be288def3c2ca73bdc1", 8 }, // Dart 2.15.0
{ "f71c76320d35b65f1164dbaa6d95fe09", 8 }, // Dart 3.2.5
{ "f91b8b03bf7f30a5e983fd19b23d978d", 4 }, // Dart 2.18.2
{ "f956f595844a2f845a55707faaaa51e4", 4 }, // Dart 3.6.2
{ "fa07b8a2d866963d1117ecdcea9287c8", 4 }, // Dart 3.8.0
{ "fe53c4fdba846005b70514aec3840296", 8 }, // Dart 3.4.0
};
#define DART_HASH_ENTRIES_COUNT 61
// Default offset arrays (identical across all known Dart versions)
#define DART_DEFAULT_EP_OFFSETS { 8, 24, 16, 32 }
#define DART_DEFAULT_EP_OFFSETS_COUNT 4
#define DART_DEFAULT_OWNER_OFFSETS { 56 }
#define DART_DEFAULT_OWNER_OFFSETS_COUNT 1
#define DART_DEFAULT_NAME_OFFSETS { 24, 8 }
#define DART_DEFAULT_NAME_OFFSETS_COUNT 2
#endif // R2C_DART_OFFSETS_H
+3
View File
@@ -160,6 +160,9 @@ typedef void(*DartPoolFunctionCallback)(const char *name, ut64 addr, ut64 size,
// Main API - all functions take DartCtx*
// ============================================================================
bool dart_ctx_set_profile_override(DartCtx *ctx, const char *spec);
const char *dart_ctx_effective_version(DartCtx *ctx);
const char *dart_ctx_effective_hash(DartCtx *ctx);
int dart_pool_enumerate(DartCtx *ctx, const char *libapp_path, DartPoolFunctionCallback on_fn, void *user, ut64 *out_base, ut64 *out_heap_base);
char *dart_pool_dump_header(DartCtx *ctx, int fmt);
char *dart_pool_dump_header_ext(DartCtx *ctx, int fmt);
+3
View File
@@ -41,7 +41,10 @@ typedef struct {
ut64 container_payload_offset;
ut64 container_payload_size;
ut64 container_macho_offset;
char snapshot_hash_actual[33];
char snapshot_hash[33];
char snapshot_hash_override[33];
char dart_version_override[32];
const DartVerLayout *layout;
int compressed_word_size;
HtUP *name_by_ep;
+8 -13
View File
@@ -16,10 +16,11 @@ extern "C" {
typedef enum {
DART_TAG_STYLE_CID_INT32 = 0, // v2.10-2.13: raw int32 CID
DART_TAG_STYLE_CID_SHIFT1 = 1, // v2.14-3.3: (cid << 1) | canonical
DART_TAG_STYLE_OBJECT_HEADER = 2 // v3.4.3+: ObjectHeader with ClassIdTag at bits 12-31
DART_TAG_STYLE_OBJECT_HEADER = 2 // v3.4.3+ and known 2.18.2 exception
} DartTagStyle;
// Version layout information for Dart snapshots
// CID values are stored in dart_cid.c's cid_tables[] and accessed via dart_cid_get()
typedef struct {
char hash[33];
const char *dart_version;
@@ -29,24 +30,14 @@ typedef struct {
ut64 it_cap;
DartTagStyle tag_style;
int header_fields;
int cid_class;
int cid_function;
int cid_code;
int cid_string;
int cid_one_byte_string;
int cid_two_byte_string;
int cid_array;
int cid_mint;
int cid_object_pool;
int num_predefined_cids;
} DartVerLayout;
// Lookup Dart version from a snapshot hash (MD5)
// Returns NULL if hash is not recognized
const char *dart_version_from_hash(const char *hash);
// Lookup version profile from a Dart version string
// Returns NULL if version is not recognized
// Lookup version profile from a Dart version string using floor semantics.
// Returns NULL if the version string is not a dotted numeric version.
const DartVerLayout *dart_profile_from_version(const char *version);
// Pick a layout structure based on hash, with fallback to defaults
@@ -59,6 +50,10 @@ void dart_ver_layout_free(DartVerLayout *layout);
void dart_version_set_verbose(int level);
// Compare dotted Dart SDK versions numerically.
// Returns -1, 0, 1, or -2 when either input is not a dotted numeric version.
int dart_version_compare(const char *a, const char *b);
#ifdef __cplusplus
}
#endif
+87 -742
View File
@@ -1,746 +1,91 @@
{
"arch": "arm64",
"defaults": {
"code_entry_point_offsets": [8, 24, 16, 32],
"code_owner_offsets": [56],
"function_name_offsets": [24, 8]
},
"profiles": {
"2.10.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_INT32", "header_fields": 4, "typed_data_internal_base": 108, "typed_data_internal_limit": 150, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "CLASS": 4, "PATCH_CLASS": 5, "FUNCTION": 6, "CLOSURE_DATA": 7, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 77, "CODE": 16, "OBJECT_POOL": 20, "PC_DESCRIPTORS": 21, "CODE_SOURCE_MAP": 22, "COMPRESSED_STACK_MAPS": 23, "EXCEPTION_HANDLERS": 25, "CONTEXT": 26, "CONTEXT_SCOPE": 27, "SINGLE_TARGET_CACHE": 29, "UNLINKED_CALL": 30, "MONOMORPHIC_SMIABLE_CALL": 31, "CALL_SITE_DATA": 32, "ICDATA": 33, "MEGAMORPHIC_CACHE": 34, "SUBTYPE_TEST_CACHE": 35, "LOADING_UNIT": 36, "LANGUAGE_ERROR": 39, "UNHANDLED_EXCEPTION": 40, "INSTANCE": 42, "LIBRARY_PREFIX": 43, "TYPE_ARGUMENTS": 44, "TYPE": 46, "TYPE_REF": 47, "TYPE_PARAMETER": 48, "CLOSURE": 49, "MINT": 53, "DOUBLE": 54, "FLOAT32X4": 57, "INT32X4": 58, "FLOAT64X2": 59, "TYPED_DATA": 61, "EXTERNAL_TYPED_DATA": 62, "TYPED_DATA_VIEW": 63, "CAPABILITY": 66, "RECEIVE_PORT": 67, "SEND_PORT": 68, "STACK_TRACE": 69, "REGEXP": 70, "WEAK_PROPERTY": 71, "FUTURE_OR": 74, "USER_TAG": 75, "TRANSFERABLE_TYPED_DATA": 76, "ARRAY": 78, "IMMUTABLE_ARRAY": 79, "GROWABLE_OBJECT_ARRAY": 56, "STRING": 80, "ONE_BYTE_STRING": 81, "TWO_BYTE_STRING": 82, "NUM_PREDEFINED_CIDS": 156}},
"2.12.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_INT32", "header_fields": 4, "typed_data_internal_base": 100, "typed_data_internal_limit": 142, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "CLASS": 4, "PATCH_CLASS": 5, "FUNCTION": 6, "CLOSURE_DATA": 7, "FFI_TRAMPOLINE_DATA": 8, "FIELD": 9, "SCRIPT": 10, "LIBRARY": 11, "NAMESPACE": 12, "KERNEL_PROGRAM_INFO": 13, "WEAK_SERIALIZATION_REFERENCE": 74, "CODE": 14, "OBJECT_POOL": 17, "PC_DESCRIPTORS": 18, "CODE_SOURCE_MAP": 19, "COMPRESSED_STACK_MAPS": 20, "EXCEPTION_HANDLERS": 22, "CONTEXT": 23, "CONTEXT_SCOPE": 24, "SINGLE_TARGET_CACHE": 25, "UNLINKED_CALL": 26, "MONOMORPHIC_SMIABLE_CALL": 27, "CALL_SITE_DATA": 28, "ICDATA": 29, "MEGAMORPHIC_CACHE": 30, "SUBTYPE_TEST_CACHE": 31, "LOADING_UNIT": 32, "LANGUAGE_ERROR": 35, "UNHANDLED_EXCEPTION": 36, "INSTANCE": 38, "LIBRARY_PREFIX": 39, "TYPE_ARGUMENTS": 40, "TYPE": 42, "FUNCTION_TYPE": 43, "TYPE_REF": 44, "TYPE_PARAMETER": 45, "CLOSURE": 46, "MINT": 50, "DOUBLE": 51, "FLOAT32X4": 54, "INT32X4": 55, "FLOAT64X2": 56, "TYPED_DATA": 58, "EXTERNAL_TYPED_DATA": 59, "TYPED_DATA_VIEW": 60, "CAPABILITY": 63, "RECEIVE_PORT": 64, "SEND_PORT": 65, "STACK_TRACE": 66, "REGEXP": 67, "WEAK_PROPERTY": 68, "FUTURE_OR": 71, "USER_TAG": 72, "TRANSFERABLE_TYPED_DATA": 73, "ARRAY": 75, "IMMUTABLE_ARRAY": 76, "GROWABLE_OBJECT_ARRAY": 53, "STRING": 77, "ONE_BYTE_STRING": 78, "TWO_BYTE_STRING": 79, "NUM_PREDEFINED_CIDS": 148}},
"2.13.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_INT32", "header_fields": 5, "typed_data_internal_base": 100, "typed_data_internal_limit": 142, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "CLASS": 4, "PATCH_CLASS": 5, "FUNCTION": 6, "CLOSURE_DATA": 7, "FFI_TRAMPOLINE_DATA": 8, "FIELD": 9, "SCRIPT": 10, "LIBRARY": 11, "NAMESPACE": 12, "KERNEL_PROGRAM_INFO": 13, "WEAK_SERIALIZATION_REFERENCE": 14, "CODE": 15, "OBJECT_POOL": 18, "PC_DESCRIPTORS": 19, "CODE_SOURCE_MAP": 20, "COMPRESSED_STACK_MAPS": 21, "EXCEPTION_HANDLERS": 23, "CONTEXT": 24, "CONTEXT_SCOPE": 25, "SINGLE_TARGET_CACHE": 26, "UNLINKED_CALL": 27, "MONOMORPHIC_SMIABLE_CALL": 28, "CALL_SITE_DATA": 29, "ICDATA": 30, "MEGAMORPHIC_CACHE": 31, "SUBTYPE_TEST_CACHE": 32, "LOADING_UNIT": 33, "LANGUAGE_ERROR": 36, "UNHANDLED_EXCEPTION": 37, "INSTANCE": 39, "LIBRARY_PREFIX": 40, "TYPE_ARGUMENTS": 41, "TYPE": 43, "FUNCTION_TYPE": 44, "TYPE_REF": 45, "TYPE_PARAMETER": 46, "CLOSURE": 47, "MINT": 51, "DOUBLE": 52, "FLOAT32X4": 55, "INT32X4": 56, "FLOAT64X2": 57, "TYPED_DATA": 59, "EXTERNAL_TYPED_DATA": 60, "TYPED_DATA_VIEW": 61, "CAPABILITY": 64, "RECEIVE_PORT": 65, "SEND_PORT": 66, "STACK_TRACE": 67, "REGEXP": 68, "WEAK_PROPERTY": 69, "FUTURE_OR": 72, "USER_TAG": 73, "TRANSFERABLE_TYPED_DATA": 74, "ARRAY": 75, "IMMUTABLE_ARRAY": 76, "GROWABLE_OBJECT_ARRAY": 54, "STRING": 77, "ONE_BYTE_STRING": 78, "TWO_BYTE_STRING": 79, "NUM_PREDEFINED_CIDS": 148}},
"2.14.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 104, "typed_data_internal_limit": 146, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "CLASS": 4, "PATCH_CLASS": 5, "FUNCTION": 6, "TYPE_PARAMETERS": 7, "CLOSURE_DATA": 8, "FFI_TRAMPOLINE_DATA": 9, "FIELD": 10, "SCRIPT": 11, "LIBRARY": 12, "NAMESPACE": 13, "KERNEL_PROGRAM_INFO": 14, "WEAK_SERIALIZATION_REFERENCE": 15, "CODE": 16, "OBJECT_POOL": 20, "PC_DESCRIPTORS": 21, "CODE_SOURCE_MAP": 22, "COMPRESSED_STACK_MAPS": 23, "EXCEPTION_HANDLERS": 25, "CONTEXT": 26, "CONTEXT_SCOPE": 27, "SENTINEL": 28, "SINGLE_TARGET_CACHE": 29, "UNLINKED_CALL": 30, "MONOMORPHIC_SMIABLE_CALL": 31, "CALL_SITE_DATA": 32, "ICDATA": 33, "MEGAMORPHIC_CACHE": 34, "SUBTYPE_TEST_CACHE": 35, "LOADING_UNIT": 36, "LANGUAGE_ERROR": 39, "UNHANDLED_EXCEPTION": 40, "INSTANCE": 42, "LIBRARY_PREFIX": 43, "TYPE_ARGUMENTS": 44, "TYPE": 46, "FUNCTION_TYPE": 47, "TYPE_REF": 48, "TYPE_PARAMETER": 49, "CLOSURE": 50, "MINT": 54, "DOUBLE": 55, "FLOAT32X4": 58, "INT32X4": 59, "FLOAT64X2": 60, "TYPED_DATA": 62, "EXTERNAL_TYPED_DATA": 63, "TYPED_DATA_VIEW": 64, "CAPABILITY": 67, "RECEIVE_PORT": 68, "SEND_PORT": 69, "STACK_TRACE": 70, "REGEXP": 71, "WEAK_PROPERTY": 72, "FUTURE_OR": 74, "USER_TAG": 75, "TRANSFERABLE_TYPED_DATA": 76, "ARRAY": 79, "IMMUTABLE_ARRAY": 80, "GROWABLE_OBJECT_ARRAY": 57, "STRING": 81, "ONE_BYTE_STRING": 82, "TWO_BYTE_STRING": 83, "NUM_PREDEFINED_CIDS": 152}},
"2.15.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 106, "typed_data_internal_limit": 148, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 48, "TYPE_REF": 49, "TYPE_PARAMETER": 50, "CLOSURE": 51, "MINT": 55, "DOUBLE": 56, "FLOAT32X4": 58, "INT32X4": 59, "FLOAT64X2": 60, "TYPED_DATA": 62, "EXTERNAL_TYPED_DATA": 63, "TYPED_DATA_VIEW": 64, "CAPABILITY": 67, "RECEIVE_PORT": 68, "SEND_PORT": 69, "STACK_TRACE": 70, "REGEXP": 71, "WEAK_PROPERTY": 72, "FUTURE_OR": 74, "USER_TAG": 75, "TRANSFERABLE_TYPED_DATA": 76, "ARRAY": 81, "IMMUTABLE_ARRAY": 82, "GROWABLE_OBJECT_ARRAY": 83, "STRING": 84, "ONE_BYTE_STRING": 85, "TWO_BYTE_STRING": 86, "NUM_PREDEFINED_CIDS": 154}},
"2.16.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 6, "typed_data_internal_base": 106, "typed_data_internal_limit": 148, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 48, "TYPE_REF": 49, "TYPE_PARAMETER": 50, "CLOSURE": 51, "MINT": 55, "DOUBLE": 56, "FLOAT32X4": 58, "INT32X4": 59, "FLOAT64X2": 60, "TYPED_DATA": 62, "EXTERNAL_TYPED_DATA": 63, "TYPED_DATA_VIEW": 64, "CAPABILITY": 67, "RECEIVE_PORT": 68, "SEND_PORT": 69, "STACK_TRACE": 70, "REGEXP": 71, "WEAK_PROPERTY": 72, "FUTURE_OR": 74, "USER_TAG": 75, "TRANSFERABLE_TYPED_DATA": 76, "ARRAY": 81, "IMMUTABLE_ARRAY": 82, "GROWABLE_OBJECT_ARRAY": 83, "STRING": 84, "ONE_BYTE_STRING": 85, "TWO_BYTE_STRING": 86, "NUM_PREDEFINED_CIDS": 154}},
"2.17.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 6, "typed_data_internal_base": 110, "typed_data_internal_limit": 152, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 52, "TYPE_REF": 53, "TYPE_PARAMETER": 54, "CLOSURE": 55, "MINT": 59, "DOUBLE": 60, "FLOAT32X4": 62, "INT32X4": 63, "FLOAT64X2": 64, "TYPED_DATA": 66, "EXTERNAL_TYPED_DATA": 67, "TYPED_DATA_VIEW": 68, "CAPABILITY": 71, "RECEIVE_PORT": 72, "SEND_PORT": 73, "STACK_TRACE": 74, "REGEXP": 75, "WEAK_PROPERTY": 76, "WEAK_REFERENCE": 77, "FUTURE_OR": 79, "USER_TAG": 80, "TRANSFERABLE_TYPED_DATA": 81, "ARRAY": 86, "IMMUTABLE_ARRAY": 87, "GROWABLE_OBJECT_ARRAY": 88, "STRING": 89, "ONE_BYTE_STRING": 90, "TWO_BYTE_STRING": 91, "NUM_PREDEFINED_CIDS": 158}},
"2.18.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 111, "typed_data_internal_limit": 153, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 52, "TYPE_REF": 53, "TYPE_PARAMETER": 54, "CLOSURE": 55, "MINT": 59, "DOUBLE": 60, "FLOAT32X4": 62, "INT32X4": 63, "FLOAT64X2": 64, "TYPED_DATA": 66, "EXTERNAL_TYPED_DATA": 67, "TYPED_DATA_VIEW": 68, "CAPABILITY": 71, "RECEIVE_PORT": 72, "SEND_PORT": 73, "STACK_TRACE": 74, "SUSPEND_STATE": 75, "REGEXP": 76, "WEAK_PROPERTY": 77, "WEAK_REFERENCE": 78, "FUTURE_OR": 80, "USER_TAG": 81, "TRANSFERABLE_TYPED_DATA": 82, "ARRAY": 87, "IMMUTABLE_ARRAY": 88, "GROWABLE_OBJECT_ARRAY": 89, "STRING": 90, "ONE_BYTE_STRING": 91, "TWO_BYTE_STRING": 92, "NUM_PREDEFINED_CIDS": 159}},
"2.18.2": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "OBJECT_HEADER", "header_fields": 5, "typed_data_internal_base": 112, "typed_data_internal_limit": 168, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 23, "PC_DESCRIPTORS": 24, "CODE_SOURCE_MAP": 25, "COMPRESSED_STACK_MAPS": 26, "EXCEPTION_HANDLERS": 28, "CONTEXT": 29, "CONTEXT_SCOPE": 30, "SENTINEL": 31, "SINGLE_TARGET_CACHE": 32, "UNLINKED_CALL": 35, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 36, "MEGAMORPHIC_CACHE": 37, "SUBTYPE_TEST_CACHE": 38, "LOADING_UNIT": 39, "LANGUAGE_ERROR": 42, "UNHANDLED_EXCEPTION": 43, "INSTANCE": 45, "LIBRARY_PREFIX": 46, "TYPE_ARGUMENTS": 47, "TYPE": 49, "FUNCTION_TYPE": 50, "RECORD_TYPE": 51, "TYPE_PARAMETER": 52, "CLOSURE": 57, "MINT": 61, "DOUBLE": 62, "FLOAT32X4": 64, "INT32X4": 65, "FLOAT64X2": 66, "RECORD": 67, "TYPED_DATA": 69, "EXTERNAL_TYPED_DATA": 70, "TYPED_DATA_VIEW": 71, "CAPABILITY": 74, "RECEIVE_PORT": 75, "SEND_PORT": 76, "STACK_TRACE": 77, "SUSPEND_STATE": 78, "REGEXP": 79, "WEAK_PROPERTY": 80, "WEAK_REFERENCE": 81, "FUTURE_OR": 83, "USER_TAG": 84, "TRANSFERABLE_TYPED_DATA": 85, "MAP": 86, "CONST_MAP": 87, "SET": 88, "CONST_SET": 89, "ARRAY": 90, "IMMUTABLE_ARRAY": 91, "GROWABLE_OBJECT_ARRAY": 92, "STRING": 93, "ONE_BYTE_STRING": 94, "TWO_BYTE_STRING": 95, "NUM_PREDEFINED_CIDS": 175}, "note": "Uses fallback CIDs from 3.9.2 for the in-tree Flutter engine snapshot; not standalone Dart SDK 2.18.2 CIDs."},
"2.18.3": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 111, "typed_data_internal_limit": 153, "typed_data_stride": 3, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 52, "TYPE_REF": 53, "TYPE_PARAMETER": 54, "CLOSURE": 55, "MINT": 59, "DOUBLE": 60, "FLOAT32X4": 62, "INT32X4": 63, "FLOAT64X2": 64, "TYPED_DATA": 66, "EXTERNAL_TYPED_DATA": 67, "TYPED_DATA_VIEW": 68, "CAPABILITY": 71, "RECEIVE_PORT": 72, "SEND_PORT": 73, "STACK_TRACE": 74, "SUSPEND_STATE": 75, "REGEXP": 76, "WEAK_PROPERTY": 77, "WEAK_REFERENCE": 78, "FUTURE_OR": 80, "USER_TAG": 81, "TRANSFERABLE_TYPED_DATA": 82, "ARRAY": 87, "IMMUTABLE_ARRAY": 88, "GROWABLE_OBJECT_ARRAY": 89, "STRING": 90, "ONE_BYTE_STRING": 91, "TWO_BYTE_STRING": 92, "NUM_PREDEFINED_CIDS": 159}},
"2.19.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 113, "typed_data_internal_limit": 169, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "CODE": 17, "OBJECT_POOL": 21, "PC_DESCRIPTORS": 22, "CODE_SOURCE_MAP": 23, "COMPRESSED_STACK_MAPS": 24, "EXCEPTION_HANDLERS": 26, "CONTEXT": 27, "CONTEXT_SCOPE": 28, "SENTINEL": 29, "SINGLE_TARGET_CACHE": 30, "UNLINKED_CALL": 31, "MONOMORPHIC_SMIABLE_CALL": 32, "CALL_SITE_DATA": 33, "ICDATA": 34, "MEGAMORPHIC_CACHE": 35, "SUBTYPE_TEST_CACHE": 36, "LOADING_UNIT": 37, "LANGUAGE_ERROR": 40, "UNHANDLED_EXCEPTION": 41, "INSTANCE": 43, "LIBRARY_PREFIX": 44, "TYPE_ARGUMENTS": 45, "TYPE": 47, "FUNCTION_TYPE": 48, "RECORD_TYPE": 49, "TYPE_REF": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 176}},
"3.0.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 114, "typed_data_internal_limit": 170, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_REF": 51, "TYPE_PARAMETER": 52, "CLOSURE": 57, "MINT": 61, "DOUBLE": 62, "FLOAT32X4": 64, "INT32X4": 65, "FLOAT64X2": 66, "RECORD": 67, "TYPED_DATA": 69, "EXTERNAL_TYPED_DATA": 70, "TYPED_DATA_VIEW": 71, "CAPABILITY": 74, "RECEIVE_PORT": 75, "SEND_PORT": 76, "STACK_TRACE": 77, "SUSPEND_STATE": 78, "REGEXP": 79, "WEAK_PROPERTY": 80, "WEAK_REFERENCE": 81, "FUTURE_OR": 83, "USER_TAG": 84, "TRANSFERABLE_TYPED_DATA": 85, "MAP": 86, "CONST_MAP": 87, "SET": 88, "CONST_SET": 89, "ARRAY": 90, "IMMUTABLE_ARRAY": 91, "GROWABLE_OBJECT_ARRAY": 92, "STRING": 93, "ONE_BYTE_STRING": 94, "TWO_BYTE_STRING": 95, "NUM_PREDEFINED_CIDS": 177}},
"3.1.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 113, "typed_data_internal_limit": 169, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 176}},
"3.2.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 113, "typed_data_internal_limit": 169, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 176}},
"3.3.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "CID_SHIFT1", "header_fields": 5, "typed_data_internal_base": 113, "typed_data_internal_limit": 169, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 176}},
"3.4.0": {"cws": 8, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "OBJECT_HEADER", "header_fields": 5, "typed_data_internal_base": 111, "typed_data_internal_limit": 167, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 174}},
"3.5.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "OBJECT_HEADER", "header_fields": 5, "typed_data_internal_base": 111, "typed_data_internal_limit": 167, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 22, "PC_DESCRIPTORS": 23, "CODE_SOURCE_MAP": 24, "COMPRESSED_STACK_MAPS": 25, "EXCEPTION_HANDLERS": 27, "CONTEXT": 28, "CONTEXT_SCOPE": 29, "SENTINEL": 30, "SINGLE_TARGET_CACHE": 31, "UNLINKED_CALL": 32, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 35, "MEGAMORPHIC_CACHE": 36, "SUBTYPE_TEST_CACHE": 37, "LOADING_UNIT": 38, "LANGUAGE_ERROR": 41, "UNHANDLED_EXCEPTION": 42, "INSTANCE": 44, "LIBRARY_PREFIX": 45, "TYPE_ARGUMENTS": 46, "TYPE": 48, "FUNCTION_TYPE": 49, "RECORD_TYPE": 50, "TYPE_PARAMETER": 51, "CLOSURE": 56, "MINT": 60, "DOUBLE": 61, "FLOAT32X4": 63, "INT32X4": 64, "FLOAT64X2": 65, "RECORD": 66, "TYPED_DATA": 68, "EXTERNAL_TYPED_DATA": 69, "TYPED_DATA_VIEW": 70, "CAPABILITY": 73, "RECEIVE_PORT": 74, "SEND_PORT": 75, "STACK_TRACE": 76, "SUSPEND_STATE": 77, "REGEXP": 78, "WEAK_PROPERTY": 79, "WEAK_REFERENCE": 80, "FUTURE_OR": 82, "USER_TAG": 83, "TRANSFERABLE_TYPED_DATA": 84, "MAP": 85, "CONST_MAP": 86, "SET": 87, "CONST_SET": 88, "ARRAY": 89, "IMMUTABLE_ARRAY": 90, "GROWABLE_OBJECT_ARRAY": 91, "STRING": 92, "ONE_BYTE_STRING": 93, "TWO_BYTE_STRING": 94, "NUM_PREDEFINED_CIDS": 174}},
"3.6.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "OBJECT_HEADER", "header_fields": 5, "typed_data_internal_base": 112, "typed_data_internal_limit": 168, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 23, "PC_DESCRIPTORS": 24, "CODE_SOURCE_MAP": 25, "COMPRESSED_STACK_MAPS": 26, "EXCEPTION_HANDLERS": 28, "CONTEXT": 29, "CONTEXT_SCOPE": 30, "SENTINEL": 31, "SINGLE_TARGET_CACHE": 32, "UNLINKED_CALL": 33, "MONOMORPHIC_SMIABLE_CALL": 34, "CALL_SITE_DATA": 35, "ICDATA": 36, "MEGAMORPHIC_CACHE": 37, "SUBTYPE_TEST_CACHE": 38, "LOADING_UNIT": 39, "LANGUAGE_ERROR": 42, "UNHANDLED_EXCEPTION": 43, "INSTANCE": 45, "LIBRARY_PREFIX": 46, "TYPE_ARGUMENTS": 47, "TYPE": 49, "FUNCTION_TYPE": 50, "RECORD_TYPE": 51, "TYPE_PARAMETER": 52, "CLOSURE": 57, "MINT": 61, "DOUBLE": 62, "FLOAT32X4": 64, "INT32X4": 65, "FLOAT64X2": 66, "RECORD": 67, "TYPED_DATA": 69, "EXTERNAL_TYPED_DATA": 70, "TYPED_DATA_VIEW": 71, "CAPABILITY": 74, "RECEIVE_PORT": 75, "SEND_PORT": 76, "STACK_TRACE": 77, "SUSPEND_STATE": 78, "REGEXP": 79, "WEAK_PROPERTY": 80, "WEAK_REFERENCE": 81, "FUTURE_OR": 83, "USER_TAG": 84, "TRANSFERABLE_TYPED_DATA": 85, "MAP": 86, "CONST_MAP": 87, "SET": 88, "CONST_SET": 89, "ARRAY": 90, "IMMUTABLE_ARRAY": 91, "GROWABLE_OBJECT_ARRAY": 92, "STRING": 93, "ONE_BYTE_STRING": 94, "TWO_BYTE_STRING": 95, "NUM_PREDEFINED_CIDS": 175}},
"3.9.0": {"cws": 4, "heap_object_tag": 1, "max_alignment": 16, "it_cap": 20000, "tag_style": "OBJECT_HEADER", "header_fields": 5, "typed_data_internal_base": 112, "typed_data_internal_limit": 168, "typed_data_stride": 4, "cids": {"ILLEGAL": 0, "NATIVE_POINTER": 1, "CLASS": 5, "PATCH_CLASS": 6, "FUNCTION": 7, "TYPE_PARAMETERS": 8, "CLOSURE_DATA": 9, "FFI_TRAMPOLINE_DATA": 10, "FIELD": 11, "SCRIPT": 12, "LIBRARY": 13, "NAMESPACE": 14, "KERNEL_PROGRAM_INFO": 15, "WEAK_SERIALIZATION_REFERENCE": 16, "WEAK_ARRAY": 17, "CODE": 18, "OBJECT_POOL": 23, "PC_DESCRIPTORS": 24, "CODE_SOURCE_MAP": 25, "COMPRESSED_STACK_MAPS": 26, "EXCEPTION_HANDLERS": 28, "CONTEXT": 29, "CONTEXT_SCOPE": 30, "SENTINEL": 31, "SINGLE_TARGET_CACHE": 32, "UNLINKED_CALL": 35, "MONOMORPHIC_SMIABLE_CALL": 33, "CALL_SITE_DATA": 34, "ICDATA": 36, "MEGAMORPHIC_CACHE": 37, "SUBTYPE_TEST_CACHE": 38, "LOADING_UNIT": 39, "LANGUAGE_ERROR": 42, "UNHANDLED_EXCEPTION": 43, "INSTANCE": 45, "LIBRARY_PREFIX": 46, "TYPE_ARGUMENTS": 47, "TYPE": 49, "FUNCTION_TYPE": 50, "RECORD_TYPE": 51, "TYPE_PARAMETER": 52, "CLOSURE": 57, "MINT": 61, "DOUBLE": 62, "FLOAT32X4": 64, "INT32X4": 65, "FLOAT64X2": 66, "RECORD": 67, "TYPED_DATA": 69, "EXTERNAL_TYPED_DATA": 70, "TYPED_DATA_VIEW": 71, "CAPABILITY": 74, "RECEIVE_PORT": 75, "SEND_PORT": 76, "STACK_TRACE": 77, "SUSPEND_STATE": 78, "REGEXP": 79, "WEAK_PROPERTY": 80, "WEAK_REFERENCE": 81, "FUTURE_OR": 83, "USER_TAG": 84, "TRANSFERABLE_TYPED_DATA": 85, "MAP": 86, "CONST_MAP": 87, "SET": 88, "CONST_SET": 89, "ARRAY": 90, "IMMUTABLE_ARRAY": 91, "GROWABLE_OBJECT_ARRAY": 92, "STRING": 93, "ONE_BYTE_STRING": 94, "TWO_BYTE_STRING": 95, "NUM_PREDEFINED_CIDS": 175}}
},
"hashes": {
"f91b8b03bf7f30a5e983fd19b23d978d": {
"hash": "f91b8b03bf7f30a5e983fd19b23d978d",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"notes": "Generic arm64 AOT fallback with source-backed Code/Function offsets; version still unknown",
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"8ee4ef7a67df9845fba331734198a953": {
"hash": "8ee4ef7a67df9845fba331734198a953",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"e4a09dbf2bb120fe4674e0576617a0dc": {
"hash": "e4a09dbf2bb120fe4674e0576617a0dc",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"34f6eec64e9371856eaaa278ccf56538": {
"hash": "34f6eec64e9371856eaaa278ccf56538",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"7a5b240780941844bae88eca5dbaa7b8": {
"hash": "7a5b240780941844bae88eca5dbaa7b8",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"9cf77f4405212c45daf608e1cd646852": {
"hash": "9cf77f4405212c45daf608e1cd646852",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"659a72e41e3276e882709901c27de33d": {
"hash": "659a72e41e3276e882709901c27de33d",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"f10776149bf76be288def3c2ca73bdc1": {
"hash": "f10776149bf76be288def3c2ca73bdc1",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"24d9d411c2f90c8fbe8907f99e89d4b0": {
"hash": "24d9d411c2f90c8fbe8907f99e89d4b0",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"d56742caf7b3b3f4bd2df93a9bbb5503": {
"hash": "d56742caf7b3b3f4bd2df93a9bbb5503",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"3318fe66091c0ffbb64faec39976cb7d": {
"hash": "3318fe66091c0ffbb64faec39976cb7d",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"adf563436d12ba0d50ea5beb7f3be1bb": {
"hash": "adf563436d12ba0d50ea5beb7f3be1bb",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"1441d6b13b8623fa7fbf61433abebd31": {
"hash": "1441d6b13b8623fa7fbf61433abebd31",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"a0cb0c928b23bc17a26e062b351dc44d": {
"hash": "a0cb0c928b23bc17a26e062b351dc44d",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"ded6ef11c73fdc638d6ff6d3ad22a67b": {
"hash": "ded6ef11c73fdc638d6ff6d3ad22a67b",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"b0e899ec5a90e4661501f0b69e9dd70f": {
"hash": "b0e899ec5a90e4661501f0b69e9dd70f",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"b6d0a1f034d158b0d37b51d559379697": {
"hash": "b6d0a1f034d158b0d37b51d559379697",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"8e50e448b241be23b9e990094f4dca39": {
"hash": "8e50e448b241be23b9e990094f4dca39",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"6a9b5a03a7e784a4558b10c769f188d9": {
"hash": "6a9b5a03a7e784a4558b10c769f188d9",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"adb4292f3ec25074ca70abcd2d5c7251": {
"hash": "adb4292f3ec25074ca70abcd2d5c7251",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"501ef5cbd64ca70b6b42672346af6a8a": {
"hash": "501ef5cbd64ca70b6b42672346af6a8a",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"90b56a561f70cd55e972cb49b79b3d8b": {
"hash": "90b56a561f70cd55e972cb49b79b3d8b",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"aa64af18e7d086041ac127cc4bc50c5e": {
"hash": "aa64af18e7d086041ac127cc4bc50c5e",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"36b0375d284ee2af0d0fffc6e6e48fde": {
"hash": "36b0375d284ee2af0d0fffc6e6e48fde",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"16ad76edd19b537bf6ea64fdd31977a7": {
"hash": "16ad76edd19b537bf6ea64fdd31977a7",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"7dbbeeb8ef7b91338640dca3927636de": {
"hash": "7dbbeeb8ef7b91338640dca3927636de",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"f71c76320d35b65f1164dbaa6d95fe09": {
"hash": "f71c76320d35b65f1164dbaa6d95fe09",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"ee1eb666c76a5cb7746faf39d0b97547": {
"hash": "ee1eb666c76a5cb7746faf39d0b97547",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"d20a1be77c3d3c41b2a5accaee1ce549": {
"hash": "d20a1be77c3d3c41b2a5accaee1ce549",
"compressed_word_size": 8,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"80a49c7111088100a233b2ae788e1f48": {
"hash": "80a49c7111088100a233b2ae788e1f48",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"cda356e9bae476c70de33809fd92e009": {
"hash": "cda356e9bae476c70de33809fd92e009",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"2858c2c0920495f00b9bce9edf6a8cd9": {
"hash": "2858c2c0920495f00b9bce9edf6a8cd9",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"f956f595844a2f845a55707faaaa51e4": {
"hash": "f956f595844a2f845a55707faaaa51e4",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"d91c0e6f35f0eb2e44124e8f42aa44a7": {
"hash": "d91c0e6f35f0eb2e44124e8f42aa44a7",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"830f4f59e7969c70b595182826435c19": {
"hash": "830f4f59e7969c70b595182826435c19",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"97ff04a728735e6b6b098bdf983faaba": {
"hash": "97ff04a728735e6b6b098bdf983faaba",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
},
"1ce86630892e2dca9a8543fdb8ed8e22": {
"hash": "1ce86630892e2dca9a8543fdb8ed8e22",
"compressed_word_size": 4,
"heap_object_tag": 1,
"max_alignment": 16,
"it_cap": 20000,
"code_entry_point_offsets": [
8,
24,
16,
32
],
"code_owner_offsets": [
56
],
"function_name_offsets": [
24,
8
]
}
"8ee4ef7a67df9845fba331734198a953": "2.10.0",
"d979fa911b038a8682e98cc8c8569261": "2.10.0",
"e036be9d5df68283e1a043e348fa7ff4": "2.12.0",
"0c7f1aa25fc597a7b3b9a19ed390afa1": "2.13.0",
"34f6eec64e9371856eaaa278ccf56538": "2.13.0",
"7a5b240780941844bae88eca5dbaa7b8": "2.13.0",
"e4a09dbf2bb120fe4674e0576617a0dc": "2.13.0",
"659a72e41e3276e882709901c27de33d": "2.14.0",
"9cf77f4405212c45daf608e1cd646852": "2.14.0",
"c03fb294bfdaca2b44c552ad35e52d45": "2.14.0",
"24d9d411c2f90c8fbe8907f99e89d4b0": "2.15.0",
"7b96ef6dda75bdd1d70be8c2f7cb814e": "2.15.0",
"f10776149bf76be288def3c2ca73bdc1": "2.15.0",
"3318fe66091c0ffbb64faec39976cb7d": "2.16.0",
"6093345773c65683f60c20c8e62cbe4a": "2.16.0",
"adf563436d12ba0d50ea5beb7f3be1bb": "2.16.0",
"d56742caf7b3b3f4bd2df93a9bbb5503": "2.16.0",
"0eb277b50d6ce4069261c69150ce52c9": "2.17.0",
"1441d6b13b8623fa7fbf61433abebd31": "2.17.6",
"a0cb0c928b23bc17a26e062b351dc44d": "2.17.6",
"ded6ef11c73fdc638d6ff6d3ad22a67b": "2.17.6",
"6a9b5a03a7e784a4558b10c769f188d9": "2.18.0",
"77bd0a83c49bfc555a44a0740f15003a": "2.18.0",
"8e50e448b241be23b9e990094f4dca39": "2.18.0",
"b0e899ec5a90e4661501f0b69e9dd70f": "2.18.0",
"b6d0a1f034d158b0d37b51d559379697": "2.18.0",
"f91b8b03bf7f30a5e983fd19b23d978d": "2.18.2",
"287683014dfbd311f6400c655c97a26d": "2.18.6",
"501ef5cbd64ca70b6b42672346af6a8a": "2.19.0",
"adb4292f3ec25074ca70abcd2d5c7251": "2.19.0",
"afcf461a16dfa5e88f88a2aa68764c99": "2.19.0",
"e727fae79fb45aac639252a9453b785e": "2.19.1",
"ce5d37cf26ea4faac543cd216f3b96d1": "3.0.0",
"617d044d9faa87a98c29f8aad5d2f220": "3.0.3",
"16ad76edd19b537bf6ea64fdd31977a7": "3.0.5",
"36b0375d284ee2af0d0fffc6e6e48fde": "3.0.5",
"90b56a561f70cd55e972cb49b79b3d8b": "3.0.5",
"aa64af18e7d086041ac127cc4bc50c5e": "3.0.5",
"5191d02bb1d36a9f8609aa7495894e76": "3.1.0",
"7dbbeeb8ef7b91338640dca3927636de": "3.1.3",
"9d6362266b78e4198f784da1a28fd82b": "3.2.0",
"f71c76320d35b65f1164dbaa6d95fe09": "3.2.5",
"77b867742ae1ace67fbbb9a9a0d0334e": "3.3.0",
"ee1eb666c76a5cb7746faf39d0b97547": "3.3.0",
"fe53c4fdba846005b70514aec3840296": "3.4.0",
"d20a1be77c3d3c41b2a5accaee1ce549": "3.4.3",
"71dcc635f2e5dca494525aa13ca9006b": "3.5.0",
"80a49c7111088100a233b2ae788e1f48": "3.5.0",
"cda356e9bae476c70de33809fd92e009": "3.5.0",
"30c051cb9192f6d6812be3f0b87a6356": "3.6.0",
"2858c2c0920495f00b9bce9edf6a8cd9": "3.6.2",
"f956f595844a2f845a55707faaaa51e4": "3.6.2",
"bae16a6858d8c0fe2c437b275eb807cd": "3.7.0",
"d91c0e6f35f0eb2e44124e8f42aa44a7": "3.7.0",
"fa07b8a2d866963d1117ecdcea9287c8": "3.8.0",
"830f4f59e7969c70b595182826435c19": "3.8.1",
"97ff04a728735e6b6b098bdf983faaba": "3.9.2",
"1ce86630892e2dca9a8543fdb8ed8e22": "3.10.7",
"78da37fed6bf1489361a312568249f3f": "3.11.5",
"41be3daaabd524b8aa7423bc24584957": "3.12.0",
"ace654289f5abc240509fc941453ebc5": "3.12.1"
}
}
-173
View File
@@ -1,173 +0,0 @@
#!/usr/bin/env python3
import json, subprocess, sys, os, struct, re
def run(cmd, cwd=None):
p = subprocess.run(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return p.returncode, p.stdout, p.stderr
def r2flutter_json(target):
rc, out, err = run([os.path.join(os.path.dirname(__file__), '..', 'bin', 'r2flutter'), '-q', '-j', '-H', target])
if rc != 0 or not out.strip():
raise RuntimeError('r2flutter failed: %s' % err)
return json.loads(out.strip().splitlines()[-1])
def round_up(x,a):
return (x + (a-1)) & ~(a-1)
HEX_RE = re.compile(r"0x([0-9a-fA-F]+)")
def search_hex(target, start, end, hexpat):
rc, out, err = run(['r2', '-nnq', '-c', f'e search.in=range; e search.from=0x{start:x}; e search.to=0x{end:x}; /x {hexpat}', target])
addrs = []
for line in out.splitlines():
m = HEX_RE.search(line)
if m:
addrs.append(int(m.group(1), 16))
return addrs
def read_qword(target, addr):
rc, out, err = run(['r2', '-nnq', '-c', f'pxq 1 @ 0x{addr:x}', target])
for line in out.splitlines():
m = HEX_RE.search(line)
if m:
return int(m.group(1), 16)
return 0
def le64(buf, off):
if off < 0 or off+8 > len(buf):
return 0
return struct.unpack_from('<Q', bytes(buf), off)[0]
def read_cstr(buf, off, maxlen=128):
if off < 0 or off >= len(buf):
return ''
end = off
n = 0
out = []
while end < len(buf) and n < maxlen:
b = buf[end]
if b == 0:
break
if 32 <= b < 127 or b == 9:
out.append(chr(b))
else:
return ''
end += 1
n += 1
return ''.join(out)
def derive_offsets(target):
j = r2flutter_json(target)
iso_data = j['iso_data']
iso_instr = j['iso_instr']
total = j['cluster']['total']
cws = j.get('cws', 4)
align = 16
base = iso_data + round_up(total, align)
end = iso_instr if iso_instr > base else base + (1<<22)
# Candidate offsets within Code and Function objects (64-bit typical)
ep_cands = [0x10,0x18,0x20,0x28,0x30]
owner_cands = [0x10,0x18,0x20,0x28,0x30]
name_cands = [0x10,0x18,0x20,0x28,0x30]
good_ep, good_owner, good_name = set(), set(), set()
# Fast path: search for common prefixes in strings to get candidate name addresses
names = []
for pat in (b'package:', b'dart:'):
hexpat = pat.hex()
addrs = search_hex(target, base, end, hexpat)
names.extend(addrs)
# For each candidate String address, locate owner(Function) via pointers.
# Consider both 64-bit and 32-bit compressed pointers.
max_hits = 800
for sa in names[:200]: # cap initial string candidates
le_name = sa.to_bytes(8, 'little').hex()
owner_ptrs = search_hex(target, base, end, le_name)
# also try 32-bit compressed encodings for (sa-base)
rel = sa - base
for sh in (0,1,2,3):
enc = (rel >> sh) & 0xffffffff
for tag in (0,1,3,7):
val = (enc | tag) & 0xffffffff
le4 = val.to_bytes(4, 'little').hex()
owner_ptrs += search_hex(target, base, end, le4)
# Each owner_ptr is at (owner + name_off)
for owner_ptr in owner_ptrs[:12]: # cap per-name refs
for name_off in name_cands:
owner = owner_ptr - name_off
if owner < base or owner >= end:
continue
# Find Code.owner refs: pointers to 'owner' within range (64-bit and 32-bit compressed)
le_owner = owner.to_bytes(8, 'little').hex()
code_owner_ptrs = search_hex(target, base, end, le_owner)
rel_owner = owner - base
for sh2 in (0,1,2,3):
enc2 = (rel_owner >> sh2) & 0xffffffff
for tag2 in (0,1,3,7):
val2 = (enc2 | tag2) & 0xffffffff
code_owner_ptrs += search_hex(target, base, end, val2.to_bytes(4, 'little').hex())
for cop in code_owner_ptrs[:16]:
# cop == (code_base + owner_off)
for owner_off in owner_cands:
code_base = cop - owner_off
if code_base < base or code_base >= end:
continue
for ep_off in ep_cands:
ep = read_qword(target, code_base + ep_off)
if iso_instr <= ep < iso_instr + (1<<26) and (ep & 3) == 0:
good_owner.add(owner_off)
good_name.add(name_off)
good_ep.add(ep_off)
max_hits -= 1
break
if max_hits <= 0:
break
if max_hits <= 0:
break
if max_hits <= 0:
break
if max_hits <= 0:
break
if max_hits <= 0:
break
return {
'hash': j['hash'],
'compressed_word_size': cws,
'heap_object_tag': 1,
'max_alignment': align,
'it_cap': 20000,
'code_entry_point_offsets': sorted(good_ep),
'code_owner_offsets': sorted(good_owner),
'function_name_offsets': sorted(good_name),
}
def merge_offsets(path, entry):
if os.path.exists(path):
with open(path, 'r') as f:
obj = json.load(f)
else:
obj = {'arch': 'arm64', 'hashes': {}}
h = entry['hash']
obj.setdefault('hashes', {})
obj['hashes'][h] = entry
with open(path, 'w') as f:
json.dump(obj, f, indent=2)
def main():
if len(sys.argv) < 2:
print('Usage: derive_offsets.py <path-to-libapp.so-or-.app>', file=sys.stderr)
sys.exit(1)
target = sys.argv[1]
# resolve .app path to App binary
if target.endswith('.app'):
appbin = os.path.join(target, 'Frameworks', 'App.framework', 'App')
if os.path.exists(appbin):
target = appbin
entry = derive_offsets(target)
out = os.path.join(os.path.dirname(__file__), '..', 'offsets.json')
merge_offsets(out, entry)
print(json.dumps(entry, indent=2))
if __name__ == '__main__':
main()
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Generate r2flutter/offsets.json for the detected snapshot hash and Dart version.
# Usage: scripts/gen_offsets.sh <libdir>
if [ $# -lt 1 ]; then
echo "Usage: $0 <libdir-with-libapp.so-and-libflutter.so>" >&2
exit 1
fi
LIBDIR="$1"
LIBAPP="$LIBDIR/libapp.so"
LIBFLUTTER="$LIBDIR/libflutter.so"
if [ ! -f "$LIBAPP" ] || [ ! -f "$LIBFLUTTER" ]; then
echo "Missing libapp.so or libflutter.so in $LIBDIR" >&2
exit 1
fi
SNAPSHOT_DATA_VADDR=$(readelf -Ws "$LIBAPP" | grep '_kDartVmSnapshotData$' | awk '{print "0x"$2}' | head -n 1)
if [ -z "$SNAPSHOT_DATA_VADDR" ]; then
echo "Failed to find _kDartVmSnapshotData symbol in $LIBAPP" >&2
exit 1
fi
HASH_OFFSET=$((SNAPSHOT_DATA_VADDR+20))
HASH=$(dd if="$LIBAPP" bs=1 skip=$((HASH_OFFSET)) count=32 2>/dev/null | tr -dc '0-9a-f' | head -c 32)
if [ -z "$HASH" ]; then
echo "Failed to extract snapshot hash from $LIBAPP" >&2
exit 1
fi
VERLINE="$(strings -a "$LIBFLUTTER" | sed -n 's/^\([0-9]\+\.[0-9]\+\.[0-9]\+\) (stable).*/\1/p' | head -n1)"
if [ -z "$VERLINE" ]; then
echo "Warning: Cannot determine Dart version from $LIBFLUTTER; continuing with hash only" >&2
fi
echo "Detected snapshot hash: $HASH, dart version: ${VERLINE:-unknown}"
# Prepare minimal offsets JSON with reasonable defaults; future versions of this
# generator can curl dart-lang/sdk sources and compute more fields.
OUTJSON="offsets.json"
mkdir -p "$(dirname "$OUTJSON")"
cat > "$OUTJSON" <<JSON
{
"arch": "arm64",
"hashes": {
"$HASH": {
"compressed_word_size": 4,
"heap_object_tag": 1,
"notes": "Autogenerated skeleton for $VERLINE; refine via SDK source parsing"
}
}
}
JSON
echo "Wrote $OUTJSON"
+1149
View File
File diff suppressed because it is too large. Load diff
+1 -4
View File
@@ -528,10 +528,7 @@ static void dart_app_merge_class_methods(DartApp *app) {
}
DartApp *dart_app_new(const char *path) {
DartApp *app = (DartApp *)calloc (1, sizeof (DartApp));
if (!app) {
return NULL;
}
DartApp *app = R_NEW0 (DartApp);
app->file_path = path? strdup (path): NULL;
app->functions = RVecDartFunction_new ();
return app;
+32 -1533
View File
File diff suppressed because it is too large. Load diff
+7 -50
View File
@@ -13,55 +13,13 @@ typedef struct {
static void init_layout_hints(LayoutHints *lh) {
memset (lh, 0, sizeof (*lh));
lh->ep_offs[lh->ep_offs_n++] = 0x10;
lh->ep_offs[lh->ep_offs_n++] = 0x18;
lh->ep_offs[lh->ep_offs_n++] = 0x20;
lh->owner_offs[lh->owner_offs_n++] = 0x10;
lh->owner_offs[lh->owner_offs_n++] = 0x18;
lh->owner_offs[lh->owner_offs_n++] = 0x20;
lh->name_offs[lh->name_offs_n++] = 0x10;
lh->name_offs[lh->name_offs_n++] = 0x18;
lh->name_offs[lh->name_offs_n++] = 0x20;
}
static void read_json_u64_array(const RJson *parent, const char *key, ut64 *out, int *out_n, int max) {
const RJson *arr = r_json_get (parent, key);
if (arr && arr->type == R_JSON_ARRAY) {
*out_n = 0;
size_t n = arr->children.count;
for (size_t i = 0; i < n && *out_n < max; i++) {
const RJson *el = r_json_item (arr, i);
if (el && el->type == R_JSON_INTEGER) {
out[(*out_n)++] = (ut64)el->num.u_value;
}
}
}
}
static void enrich_layout_hints_from_json(LayoutHints *lh, const char *hash) {
if (!lh || !hash) {
return;
}
char *s = r_file_slurp ("r2flutter/offsets.json", NULL);
if (!s) {
s = r_file_slurp ("offsets.json", NULL);
}
if (!s) {
return;
}
RJson *j = r_json_parse (s);
if (!j) {
free (s);
return;
}
const RJson *item = r_json_get (r_json_get (j, "hashes"), hash);
if (item) {
read_json_u64_array (item, "code_entry_point_offsets", lh->ep_offs, &lh->ep_offs_n, 8);
read_json_u64_array (item, "code_owner_offsets", lh->owner_offs, &lh->owner_offs_n, 8);
read_json_u64_array (item, "function_name_offsets", lh->name_offs, &lh->name_offs_n, 8);
}
r_json_free (j);
free (s);
lh->ep_offs[lh->ep_offs_n++] = 8;
lh->ep_offs[lh->ep_offs_n++] = 24;
lh->ep_offs[lh->ep_offs_n++] = 16;
lh->ep_offs[lh->ep_offs_n++] = 32;
lh->owner_offs[lh->owner_offs_n++] = 56;
lh->name_offs[lh->name_offs_n++] = 24;
lh->name_offs[lh->name_offs_n++] = 8;
}
static bool read_heap_ptr(DartCtx *ctx, ut64 addr, ut64 data_image_base, ut64 *out_abs) {
@@ -177,7 +135,6 @@ HtUP *scan_code_names(DartCtx *ctx, ut64 data_image_base, ut64 data_image_end) {
}
LayoutHints lh;
init_layout_hints (&lh);
enrich_layout_hints_from_json (&lh, ctx->snapshot_hash);
HtUP *name_by_ep = ht_up_new0 ();
if (!name_by_ep) {
return NULL;
+143 -87
View File
@@ -1,7 +1,74 @@
/* r2flutter - MIT - Copyright 2026 - pancake */
#include <ctype.h>
#include "dart_pool_parse_priv.h"
static bool dart_is_snapshot_hash(const char *s) {
if (R_STR_ISEMPTY (s) || strlen (s) != DART_SNAPSHOT_HASH_SIZE) {
return false;
}
for (int i = 0; i < DART_SNAPSHOT_HASH_SIZE; i++) {
if (!isxdigit ((ut8)s[i])) {
return false;
}
}
return true;
}
static void dart_copy_snapshot_hash_lower(char *dst, size_t dstsz, const char *src) {
if (!dst || !dstsz) {
return;
}
for (int i = 0; i < DART_SNAPSHOT_HASH_SIZE && (size_t)i + 1 < dstsz; i++) {
dst[i] = tolower ((ut8)src[i]);
}
dst[R_MIN ((size_t)DART_SNAPSHOT_HASH_SIZE, dstsz - 1)] = '\0';
}
bool dart_ctx_set_profile_override(DartCtx *ctx, const char *spec) {
if (!ctx) {
return false;
}
ctx->snapshot_hash_override[0] = '\0';
ctx->dart_version_override[0] = '\0';
if (R_STR_ISEMPTY (spec)) {
return true;
}
if (dart_is_snapshot_hash (spec)) {
dart_copy_snapshot_hash_lower (ctx->snapshot_hash_override, sizeof (ctx->snapshot_hash_override), spec);
return true;
}
const DartVerLayout *profile = dart_profile_from_version (spec);
if (!profile) {
return false;
}
r_str_ncpy (ctx->dart_version_override, spec, sizeof (ctx->dart_version_override));
return true;
}
const char *dart_ctx_effective_hash(DartCtx *ctx) {
if (!ctx) {
return NULL;
}
if (R_STR_ISNOTEMPTY (ctx->snapshot_hash)) {
return ctx->snapshot_hash;
}
if (R_STR_ISNOTEMPTY (ctx->snapshot_hash_override)) {
return ctx->snapshot_hash_override;
}
return R_STR_ISNOTEMPTY (ctx->snapshot_hash_actual)? ctx->snapshot_hash_actual: NULL;
}
const char *dart_ctx_effective_version(DartCtx *ctx) {
if (!ctx) {
return NULL;
}
if (R_STR_ISNOTEMPTY (ctx->dart_version_override)) {
return ctx->dart_version_override;
}
return dart_version_from_hash (dart_ctx_effective_hash (ctx));
}
static const char *dart_tag_style_names[] = {
"CID_INT32", // DART_TAG_STYLE_CID_INT32 = 0
"CID_SHIFT1", // DART_TAG_STYLE_CID_SHIFT1 = 1
@@ -28,29 +95,12 @@ static inline const char *dart_tag_style_to_string_verbose(DartTagStyle style) {
}
}
#include <r2flutter/dart_offsets.h>
static const DartVerLayout *load_layout_from_json(const char *hash, DartVerLayout *out) {
if (!hash || !out) {
return NULL;
}
char *s = r_file_slurp ("r2flutter/offsets.json", NULL);
if (!s) {
s = r_file_slurp ("offsets.json", NULL);
}
if (!s) {
return NULL;
}
RJson *j = r_json_parse (s);
if (!j) {
free (s);
return NULL;
}
const RJson *hashes = r_json_get (j, "hashes");
const RJson *item = r_json_get (hashes, hash);
if (!item) {
r_json_free (j);
free (s);
return NULL;
}
const char *version = dart_version_from_hash (hash);
const DartVerLayout *base_profile = version? dart_profile_from_version (version): NULL;
if (base_profile) {
@@ -58,53 +108,59 @@ static const DartVerLayout *load_layout_from_json(const char *hash, DartVerLayou
} else {
memset (out, 0, sizeof (*out));
out->tag_style = DART_TAG_STYLE_OBJECT_HEADER;
out->cid_class = 5;
out->cid_function = 7;
out->cid_code = 18;
out->cid_string = 93;
out->cid_one_byte_string = 94;
out->cid_two_byte_string = 95;
out->cid_array = 90;
out->cid_mint = 61;
out->cid_object_pool = 23;
out->num_predefined_cids = 175;
}
const char *h = r_json_get_str (item, "hash");
r_str_ncpy (out->hash, R_STR_ISNOTEMPTY (h)? h: hash, sizeof (out->hash));
int cws = (int)r_json_get_num (item, "compressed_word_size");
if (cws > 0) {
out->compressed_word_size = cws;
r_str_ncpy (out->hash, hash, sizeof (out->hash));
for (int i = 0; i < DART_HASH_ENTRIES_COUNT; i++) {
if (!strcmp (dart_hash_entries[i].hash, hash)) {
out->compressed_word_size = dart_hash_entries[i].compressed_word_size;
break;
}
}
int hot = (int)r_json_get_num (item, "heap_object_tag");
if (hot > 0) {
out->heap_object_tag = hot;
}
int mal = (int)r_json_get_num (item, "max_alignment");
if (mal > 0) {
out->max_alignment = mal;
}
ut64 cap = (ut64)r_json_get_num (item, "it_cap");
if (cap > 0) {
out->it_cap = cap;
}
r_json_free (j);
free (s);
return out;
}
static DartVerLayout *dart_layout_new_from_profile(DartCtx *ctx, const DartVerLayout *profile) {
if (!profile) {
return NULL;
}
DartVerLayout *dvl = R_NEW0 (DartVerLayout);
memcpy (dvl, profile, sizeof (DartVerLayout));
const char *hash = dart_ctx_effective_hash (ctx);
if (R_STR_ISNOTEMPTY (hash)) {
r_str_ncpy (dvl->hash, hash, sizeof (dvl->hash));
}
return dvl;
}
static DartVerLayout *dart_pick_layout_owned_for_ctx(DartCtx *ctx) {
if (!ctx) {
return NULL;
}
if (R_STR_ISNOTEMPTY (ctx->dart_version_override)) {
return dart_layout_new_from_profile (ctx, dart_profile_from_version (ctx->dart_version_override));
}
return dart_pick_layout_by_hash (dart_ctx_effective_hash (ctx));
}
static void extract_snapshot_hash_flags(DartCtx *ctx, ut64 vm_data) {
if (!ctx || !vm_data) {
return;
}
ctx->snapshot_hash[0] = '\0';
ctx->snapshot_hash_actual[0] = '\0';
DartSnapshotHeader hdr;
if (!dart_snapshot_header_read (ctx, vm_data, &hdr)) {
return;
}
memcpy (ctx->snapshot_hash, hdr.hash, 32);
ctx->snapshot_hash[32] = '\0';
memcpy (ctx->snapshot_hash_actual, hdr.hash, DART_SNAPSHOT_HASH_SIZE);
ctx->snapshot_hash_actual[DART_SNAPSHOT_HASH_SIZE] = '\0';
if (R_STR_ISNOTEMPTY (ctx->snapshot_hash_override)) {
r_str_ncpy (ctx->snapshot_hash, ctx->snapshot_hash_override, sizeof (ctx->snapshot_hash));
} else {
r_str_ncpy (ctx->snapshot_hash, ctx->snapshot_hash_actual, sizeof (ctx->snapshot_hash));
}
if (ctx->verbose > 0) {
fprintf (stderr, "[r2flutter] snapshot_hash=%.*s flags=%.128s\n", 32, hdr.hash, hdr.flags);
fprintf (stderr, "[r2flutter] snapshot_hash=%s flags=%.128s\n", ctx->snapshot_hash, hdr.flags);
}
}
@@ -128,7 +184,7 @@ static void derive_layout_from_flags(DartCtx *ctx) {
if (ctx->layout && ctx->compressed_word_size == 4) {
int major = 0;
int minor = 0;
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
bool use_64_alignment = ctx->layout->tag_style == DART_TAG_STYLE_OBJECT_HEADER;
if (!use_64_alignment && version && sscanf (version, "%d.%d", &major, &minor) == 2) {
use_64_alignment = major > 2 || (major == 2 && minor >= 19);
@@ -143,10 +199,10 @@ static void derive_layout_from_flags(DartCtx *ctx) {
DartVerLayout *dart_ctx_init_layout(DartCtx *ctx, DartVerLayout *tmp) {
extract_snapshot_hash_flags (ctx, ctx->vm_data);
ctx->layout = load_layout_from_json (ctx->snapshot_hash, tmp);
ctx->layout = R_STR_ISEMPTY (ctx->dart_version_override)? load_layout_from_json (dart_ctx_effective_hash (ctx), tmp): NULL;
DartVerLayout *owned = NULL;
if (!ctx->layout) {
owned = dart_pick_layout_by_hash (ctx->snapshot_hash);
owned = dart_pick_layout_owned_for_ctx (ctx);
ctx->layout = owned;
}
derive_layout_from_flags (ctx);
@@ -525,7 +581,7 @@ static int prepare_header_data(DartCtx *ctx) {
return -1;
}
extract_snapshot_hash_flags (ctx, ctx->vm_data);
ctx->layout = dart_pick_layout_by_hash (ctx->snapshot_hash);
ctx->layout = dart_pick_layout_owned_for_ctx (ctx);
derive_layout_from_flags (ctx);
return 0;
}
@@ -538,7 +594,7 @@ char *dart_pool_dump_header(DartCtx *ctx, int fmt) {
return fmt == 'r'? strdup ("# Error: Dart snapshots not found\n"): strdup ("Error: Dart snapshots not found\n");
}
const bool quiet = ctx && ctx->quiet;
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
if (fmt == 'j') {
ut64 header_addr = ctx->iso_data? ctx->iso_data: ctx->vm_data;
DartSnapshotHeader sh = { 0 };
@@ -583,16 +639,16 @@ char *dart_pool_dump_header(DartCtx *ctx, int fmt) {
pj_kn (pj, "it_capacity", l->it_cap);
pj_k (pj, "cid_table");
pj_o (pj);
pj_ki (pj, "cid_class", l->cid_class);
pj_ki (pj, "cid_function", l->cid_function);
pj_ki (pj, "cid_code", l->cid_code);
pj_ki (pj, "cid_string", l->cid_string);
pj_ki (pj, "cid_one_byte_string", l->cid_one_byte_string);
pj_ki (pj, "cid_two_byte_string", l->cid_two_byte_string);
pj_ki (pj, "cid_array", l->cid_array);
pj_ki (pj, "cid_mint", l->cid_mint);
pj_ki (pj, "cid_object_pool", l->cid_object_pool);
pj_ki (pj, "num_predefined", l->num_predefined_cids);
pj_ki (pj, "cid_class", dart_cid_get (l, DART_CID_CLASS));
pj_ki (pj, "cid_function", dart_cid_get (l, DART_CID_FUNCTION));
pj_ki (pj, "cid_code", dart_cid_get (l, DART_CID_CODE));
pj_ki (pj, "cid_string", dart_cid_get (l, DART_CID_STRING));
pj_ki (pj, "cid_one_byte_string", dart_cid_get (l, DART_CID_ONE_BYTE_STRING));
pj_ki (pj, "cid_two_byte_string", dart_cid_get (l, DART_CID_TWO_BYTE_STRING));
pj_ki (pj, "cid_array", dart_cid_get (l, DART_CID_ARRAY));
pj_ki (pj, "cid_mint", dart_cid_get (l, DART_CID_MINT));
pj_ki (pj, "cid_object_pool", dart_cid_get (l, DART_CID_OBJECT_POOL));
pj_ki (pj, "num_predefined", dart_cid_get (l, DART_CID_NUM_PREDEFINED_CIDS));
pj_end (pj);
}
pj_end (pj);
@@ -686,16 +742,16 @@ char *dart_pool_dump_header(DartCtx *ctx, int fmt) {
if (ctx->layout) {
const DartVerLayout *l = ctx->layout;
r_strbuf_appendf (sb, "\n## Class IDs (CID Table)\n");
r_strbuf_appendf (sb, " cid_class: %d\n", l->cid_class);
r_strbuf_appendf (sb, " cid_function: %d\n", l->cid_function);
r_strbuf_appendf (sb, " cid_code: %d\n", l->cid_code);
r_strbuf_appendf (sb, " cid_string: %d\n", l->cid_string);
r_strbuf_appendf (sb, " cid_one_byte_string: %d\n", l->cid_one_byte_string);
r_strbuf_appendf (sb, " cid_two_byte_string: %d\n", l->cid_two_byte_string);
r_strbuf_appendf (sb, " cid_array: %d\n", l->cid_array);
r_strbuf_appendf (sb, " cid_mint: %d\n", l->cid_mint);
r_strbuf_appendf (sb, " cid_object_pool: %d\n", l->cid_object_pool);
r_strbuf_appendf (sb, " num_predefined: %d\n", l->num_predefined_cids);
r_strbuf_appendf (sb, " cid_class: %d\n", dart_cid_get (l, DART_CID_CLASS));
r_strbuf_appendf (sb, " cid_function: %d\n", dart_cid_get (l, DART_CID_FUNCTION));
r_strbuf_appendf (sb, " cid_code: %d\n", dart_cid_get (l, DART_CID_CODE));
r_strbuf_appendf (sb, " cid_string: %d\n", dart_cid_get (l, DART_CID_STRING));
r_strbuf_appendf (sb, " cid_one_byte_string: %d\n", dart_cid_get (l, DART_CID_ONE_BYTE_STRING));
r_strbuf_appendf (sb, " cid_two_byte_string: %d\n", dart_cid_get (l, DART_CID_TWO_BYTE_STRING));
r_strbuf_appendf (sb, " cid_array: %d\n", dart_cid_get (l, DART_CID_ARRAY));
r_strbuf_appendf (sb, " cid_mint: %d\n", dart_cid_get (l, DART_CID_MINT));
r_strbuf_appendf (sb, " cid_object_pool: %d\n", dart_cid_get (l, DART_CID_OBJECT_POOL));
r_strbuf_appendf (sb, " num_predefined: %d\n", dart_cid_get (l, DART_CID_NUM_PREDEFINED_CIDS));
}
return r_strbuf_drain (sb);
@@ -755,7 +811,7 @@ static void dump_header_snapshot_json(DartCtx *ctx, PJ *pj, const char *label, u
}
static char *dump_header_ext_json(DartCtx *ctx, int detail) {
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
DartSnapshotHeader iso = { 0 };
if (ctx->iso_data) {
dart_snapshot_header_read (ctx, ctx->iso_data, &iso);
@@ -792,16 +848,16 @@ static char *dump_header_ext_json(DartCtx *ctx, int detail) {
pj_kn (pj, "it_capacity", l->it_cap);
pj_k (pj, "cid_table");
pj_o (pj);
pj_ki (pj, "cid_class", l->cid_class);
pj_ki (pj, "cid_function", l->cid_function);
pj_ki (pj, "cid_code", l->cid_code);
pj_ki (pj, "cid_string", l->cid_string);
pj_ki (pj, "cid_one_byte_string", l->cid_one_byte_string);
pj_ki (pj, "cid_two_byte_string", l->cid_two_byte_string);
pj_ki (pj, "cid_array", l->cid_array);
pj_ki (pj, "cid_mint", l->cid_mint);
pj_ki (pj, "cid_object_pool", l->cid_object_pool);
pj_ki (pj, "num_predefined", l->num_predefined_cids);
pj_ki (pj, "cid_class", dart_cid_get (l, DART_CID_CLASS));
pj_ki (pj, "cid_function", dart_cid_get (l, DART_CID_FUNCTION));
pj_ki (pj, "cid_code", dart_cid_get (l, DART_CID_CODE));
pj_ki (pj, "cid_string", dart_cid_get (l, DART_CID_STRING));
pj_ki (pj, "cid_one_byte_string", dart_cid_get (l, DART_CID_ONE_BYTE_STRING));
pj_ki (pj, "cid_two_byte_string", dart_cid_get (l, DART_CID_TWO_BYTE_STRING));
pj_ki (pj, "cid_array", dart_cid_get (l, DART_CID_ARRAY));
pj_ki (pj, "cid_mint", dart_cid_get (l, DART_CID_MINT));
pj_ki (pj, "cid_object_pool", dart_cid_get (l, DART_CID_OBJECT_POOL));
pj_ki (pj, "num_predefined", dart_cid_get (l, DART_CID_NUM_PREDEFINED_CIDS));
pj_end (pj);
}
pj_ka (pj, "snapshots");
+10 -5
View File
@@ -181,11 +181,16 @@ static void sbom_add_snapshot_runtime(DartCtx *ctx, RList *components) {
if (ctx->vm_data && R_STR_ISEMPTY (ctx->snapshot_hash)) {
DartSnapshotHeader hdr;
if (dart_snapshot_header_read (ctx, ctx->vm_data, &hdr)) {
memcpy (ctx->snapshot_hash, hdr.hash, 32);
ctx->snapshot_hash[32] = '\0';
memcpy (ctx->snapshot_hash_actual, hdr.hash, 32);
ctx->snapshot_hash_actual[32] = '\0';
if (R_STR_ISNOTEMPTY (ctx->snapshot_hash_override)) {
r_str_ncpy (ctx->snapshot_hash, ctx->snapshot_hash_override, sizeof (ctx->snapshot_hash));
} else {
r_str_ncpy (ctx->snapshot_hash, ctx->snapshot_hash_actual, sizeof (ctx->snapshot_hash));
}
}
}
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
char evidence[96];
snprintf (evidence, sizeof (evidence), "snapshot_hash=%s", ctx->snapshot_hash[0]? ctx->snapshot_hash: "unknown");
sbom_add_component (components, "runtime", "dart-sdk", version, "snapshot_header", version? 100: 70, evidence);
@@ -465,7 +470,7 @@ static void sbom_dump_component_json(PJ *pj, const DartSbomComponent *c) {
}
static char *sbom_dump_json(DartCtx *ctx, RList *components, const char *input_path) {
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
PJ *pj = pj_new ();
pj_o (pj);
pj_ks (pj, "format", "r2flutter-recovered-sbom");
@@ -525,7 +530,7 @@ static char *sbom_dump_text(DartCtx *ctx, RList *components) {
const bool quiet = ctx && ctx->quiet;
RStrBuf *sb = r_strbuf_new ("");
if (!quiet) {
const char *version = dart_version_from_hash (ctx->snapshot_hash);
const char *version = dart_ctx_effective_version (ctx);
r_strbuf_append (sb, "# Dart/Flutter Recovered Components\n");
r_strbuf_append (sb, "# complete: false\n");
r_strbuf_append (sb, "# versions: explicit metadata only; AOT snapshots usually do not serialize pub package versions\n");
+111 -88
View File
@@ -2,8 +2,8 @@
// Dart SDK version detection and layout profiles
//
// Supported Dart SDK versions: 2.10.0 - 3.10.7
// Based on unflutter's version profiles and CID tables.
// Supported Dart SDK versions: 2.10.0 - 3.12.2
// Based on Dart SDK source tags plus external snapshot-hash references.
#include <r_core.h>
#include "../../include/r2flutter/dart_version.h"
@@ -14,111 +14,141 @@ void dart_version_set_verbose(int level) {
G_VERBOSE = level;
}
static bool parse_dart_version(const char *version, int *major, int *minor, int *patch) {
char tail = 0;
return version && sscanf (version, "%d.%d.%d%c", major, minor, patch, &tail) == 3;
}
int dart_version_compare(const char *a, const char *b) {
int av[3], bv[3];
if (!parse_dart_version (a, &av[0], &av[1], &av[2]) || !parse_dart_version (b, &bv[0], &bv[1], &bv[2])) {
return -2;
}
for (int i = 0; i < 3; i++) {
if (av[i] < bv[i]) {
return -1;
}
if (av[i] > bv[i]) {
return 1;
}
}
return 0;
}
// Known snapshot hashes mapped to Dart SDK versions
// Sources: unflutter version.go, reFlutter enginehash.csv, blutter precompiled SDKs
static const struct {
const char *hash;
const char *version;
} known_hashes[] = {
// Dart 2.10.x (Flutter 1.22.x)
// Dart 2.10.x
{ "8ee4ef7a67df9845fba331734198a953", "2.10.0" },
// Dart 2.13.x (Flutter 2.2.x - 2.3.x)
{ "e4a09dbf2bb120fe4674e0576617a0dc", "2.13.0" },
{ "d979fa911b038a8682e98cc8c8569261", "2.10.0" },
// Dart 2.12.x
{ "e036be9d5df68283e1a043e348fa7ff4", "2.12.0" },
// Dart 2.13.x
{ "0c7f1aa25fc597a7b3b9a19ed390afa1", "2.13.0" },
{ "34f6eec64e9371856eaaa278ccf56538", "2.13.0" },
{ "7a5b240780941844bae88eca5dbaa7b8", "2.13.0" },
// Dart 2.14.x (Flutter 2.4.x - 2.5.x)
{ "9cf77f4405212c45daf608e1cd646852", "2.14.0" },
{ "e4a09dbf2bb120fe4674e0576617a0dc", "2.13.0" },
// Dart 2.14.x
{ "659a72e41e3276e882709901c27de33d", "2.14.0" },
// Dart 2.15.x (Flutter 2.6.x - 2.7.x)
{ "f10776149bf76be288def3c2ca73bdc1", "2.15.0" },
{ "9cf77f4405212c45daf608e1cd646852", "2.14.0" },
{ "c03fb294bfdaca2b44c552ad35e52d45", "2.14.0" },
// Dart 2.15.x
{ "24d9d411c2f90c8fbe8907f99e89d4b0", "2.15.0" },
// Dart 2.16.x (Flutter 2.8.x - 2.16.x)
{ "d56742caf7b3b3f4bd2df93a9bbb5503", "2.16.0" },
{ "7b96ef6dda75bdd1d70be8c2f7cb814e", "2.15.0" },
{ "f10776149bf76be288def3c2ca73bdc1", "2.15.0" },
// Dart 2.16.x
{ "3318fe66091c0ffbb64faec39976cb7d", "2.16.0" },
{ "6093345773c65683f60c20c8e62cbe4a", "2.16.0" },
{ "adf563436d12ba0d50ea5beb7f3be1bb", "2.16.0" },
// Dart 2.17.x (Flutter 2.17.x)
{ "d56742caf7b3b3f4bd2df93a9bbb5503", "2.16.0" },
// Dart 2.17.x
{ "0eb277b50d6ce4069261c69150ce52c9", "2.17.0" },
{ "1441d6b13b8623fa7fbf61433abebd31", "2.17.6" },
{ "a0cb0c928b23bc17a26e062b351dc44d", "2.17.6" },
{ "ded6ef11c73fdc638d6ff6d3ad22a67b", "2.17.6" },
// Dart 2.18.x (Flutter 3.3.x)
// Dart 2.18.x
{ "287683014dfbd311f6400c655c97a26d", "2.18.6" },
{ "6a9b5a03a7e784a4558b10c769f188d9", "2.18.0" },
{ "77bd0a83c49bfc555a44a0740f15003a", "2.18.0" },
{ "8e50e448b241be23b9e990094f4dca39", "2.18.0" },
{ "b0e899ec5a90e4661501f0b69e9dd70f", "2.18.0" },
{ "b6d0a1f034d158b0d37b51d559379697", "2.18.0" },
{ "8e50e448b241be23b9e990094f4dca39", "2.18.0" },
{ "6a9b5a03a7e784a4558b10c769f188d9", "2.18.0" },
// Dart 2.19.x (Flutter 3.7.x)
{ "adb4292f3ec25074ca70abcd2d5c7251", "2.19.0" },
{ "f91b8b03bf7f30a5e983fd19b23d978d", "2.18.2" },
// Dart 2.19.x
{ "501ef5cbd64ca70b6b42672346af6a8a", "2.19.0" },
// Dart 3.0.x (Flutter 3.10.x - 3.12.x)
{ "adb4292f3ec25074ca70abcd2d5c7251", "2.19.0" },
{ "afcf461a16dfa5e88f88a2aa68764c99", "2.19.0" },
{ "e727fae79fb45aac639252a9453b785e", "2.19.1" },
// Dart 3.0.x
{ "16ad76edd19b537bf6ea64fdd31977a7", "3.0.5" },
{ "36b0375d284ee2af0d0fffc6e6e48fde", "3.0.5" },
{ "617d044d9faa87a98c29f8aad5d2f220", "3.0.3" },
{ "90b56a561f70cd55e972cb49b79b3d8b", "3.0.5" },
{ "aa64af18e7d086041ac127cc4bc50c5e", "3.0.5" },
{ "36b0375d284ee2af0d0fffc6e6e48fde", "3.0.5" },
{ "16ad76edd19b537bf6ea64fdd31977a7", "3.0.5" },
// Dart 3.1.x (Flutter 3.13.x)
{ "7dbbeeb8ef7b91338640dca3927636de", "3.1.0" },
// Dart 3.2.x (Flutter 3.16.x)
{ "ce5d37cf26ea4faac543cd216f3b96d1", "3.0.0" },
// Dart 3.1.x
{ "5191d02bb1d36a9f8609aa7495894e76", "3.1.0" },
{ "7dbbeeb8ef7b91338640dca3927636de", "3.1.3" },
// Dart 3.2.x
{ "9d6362266b78e4198f784da1a28fd82b", "3.2.0" },
{ "f71c76320d35b65f1164dbaa6d95fe09", "3.2.5" },
// Dart 3.3.x (Flutter 3.19.x)
// Dart 3.3.x
{ "77b867742ae1ace67fbbb9a9a0d0334e", "3.3.0" },
{ "ee1eb666c76a5cb7746faf39d0b97547", "3.3.0" },
// Dart 3.4.x (Flutter 3.22.x)
// Dart 3.4.x
{ "d20a1be77c3d3c41b2a5accaee1ce549", "3.4.3" },
// Dart 3.5.x (Flutter 3.24.x)
{ "fe53c4fdba846005b70514aec3840296", "3.4.0" },
// Dart 3.5.x
{ "71dcc635f2e5dca494525aa13ca9006b", "3.5.0" },
{ "80a49c7111088100a233b2ae788e1f48", "3.5.0" },
{ "cda356e9bae476c70de33809fd92e009", "3.5.0" },
// Dart 3.6.x
{ "2858c2c0920495f00b9bce9edf6a8cd9", "3.6.2" },
// Dart 3.6.x (Flutter 3.27.x)
{ "30c051cb9192f6d6812be3f0b87a6356", "3.6.0" },
{ "f956f595844a2f845a55707faaaa51e4", "3.6.2" },
// Dart 3.7.x (Flutter 3.29.x)
// Dart 3.7.x
{ "bae16a6858d8c0fe2c437b275eb807cd", "3.7.0" },
{ "d91c0e6f35f0eb2e44124e8f42aa44a7", "3.7.0" },
// Dart 3.8.x (Flutter 3.32.x)
// Dart 3.8.x
{ "830f4f59e7969c70b595182826435c19", "3.8.1" },
// Dart 3.9.x (Flutter 3.35.x)
{ "fa07b8a2d866963d1117ecdcea9287c8", "3.8.0" },
// Dart 3.9.x
{ "97ff04a728735e6b6b098bdf983faaba", "3.9.2" },
// Dart 3.10.x (Flutter 3.38.x)
// Dart 3.10.x
{ "1ce86630892e2dca9a8543fdb8ed8e22", "3.10.7" },
// Dart 3.11.x
{ "78da37fed6bf1489361a312568249f3f", "3.11.5" },
// Dart 3.12.x
{ "41be3daaabd524b8aa7423bc24584957", "3.12.0" },
{ "ace654289f5abc240509fc941453ebc5", "3.12.1" },
{ NULL, NULL }
};
// Version profiles with CID tables - based on unflutter's version.go
// Range-start version profiles. CID tables are generated in dart_cid.c.
static const DartVerLayout version_profiles[] = {
// Dart 2.10.0 - raw int32 tag, 4 header fields, pre-FunctionType split
{ "", "2.10.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_INT32, 4, 4, 6, 16, 80, 81, 82, 78, 53, 20, 156 },
// Dart 2.13.0 - raw int32 tag, 5 header fields, split canonical
{ "", "2.13.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_INT32, 5, 4, 6, 15, 77, 78, 79, 75, 51, 18, 148 },
// Dart 2.14.0 - shift1 tag, 5 header fields
{ "", "2.14.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 4, 6, 16, 81, 82, 83, 79, 54, 20, 152 },
// Dart 2.15.0 - shift1 tag, 5 header fields, NativePointer inserted
{ "", "2.15.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 17, 82, 83, 84, 79, 55, 21, 153 },
// Dart 2.16.0 - shift1 tag, 6 header fields, adds ConstMap/ConstSet
{ "", "2.16.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 6, 5, 7, 17, 84, 85, 86, 81, 55, 21, 154 },
// Dart 2.17.6 - shift1 tag, 6 header fields
{ "", "2.17.6", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 6, 5, 7, 17, 89, 90, 91, 86, 59, 21, 158 },
// Dart 2.18.0 - shift1 tag, 5 header fields, adds SuspendState
{ "", "2.18.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 17, 90, 91, 92, 87, 59, 21, 159 },
// Dart 2.19.0 - shift1 tag, 5 header fields, adds RecordType/Record
{ "", "2.19.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 17, 92, 93, 94, 89, 60, 21, 176 },
// Dart 3.0.5 - shift1 tag, 5 header fields, adds WeakArray
{ "", "3.0.5", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 18, 93, 94, 95, 90, 61, 22, 177 },
// Dart 3.1.0 - shift1 tag, 5 header fields
{ "", "3.1.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 18, 92, 93, 94, 89, 60, 22, 176 },
// Dart 3.2.5 - shift1 tag, 5 header fields, PoolType swapped
{ "", "3.2.5", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 18, 92, 93, 94, 89, 60, 22, 176 },
// Dart 3.3.0 - shift1 tag, 5 header fields
{ "", "3.3.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5, 5, 7, 18, 92, 93, 94, 89, 60, 22, 176 },
// Dart 3.4.3 - ObjectHeader tag, 5 header fields
{ "", "3.4.3", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 92, 93, 94, 89, 60, 22, 174 },
// Dart 3.5.0 - ObjectHeader tag, 5 header fields
{ "", "3.5.0", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 92, 93, 94, 89, 60, 22, 174 },
// Dart 3.6.2 - ObjectHeader tag, 5 header fields
{ "", "3.6.2", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 93, 94, 95, 90, 61, 23, 175 },
// Dart 3.7.0 - ObjectHeader tag, 5 header fields
{ "", "3.7.0", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 93, 94, 95, 90, 61, 23, 175 },
// Dart 3.8.1 - ObjectHeader tag, 5 header fields
{ "", "3.8.1", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 93, 94, 95, 90, 61, 23, 175 },
// Dart 3.9.2 - ObjectHeader tag, 5 header fields
{ "", "3.9.2", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 93, 94, 95, 90, 61, 23, 175 },
// Dart 3.10.7 - ObjectHeader tag, 5 header fields
{ "", "3.10.7", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5, 5, 7, 18, 93, 94, 95, 90, 61, 23, 175 },
{ { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
{ "", "2.10.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_INT32, 4 }, // Dart 2.10.0
{ "", "2.12.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_INT32, 4 }, // Dart 2.12.0
{ "", "2.13.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_INT32, 5 }, // Dart 2.13.0
{ "", "2.14.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 2.14.0
{ "", "2.15.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 2.15.0
{ "", "2.16.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 6 }, // Dart 2.16.0
{ "", "2.17.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 6 }, // Dart 2.17.0
{ "", "2.18.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 2.18.0
{ "", "2.18.2", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5 }, // Dart 2.18.2
{ "", "2.18.3", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 2.18.3
{ "", "2.19.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 2.19.0
{ "", "3.0.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 3.0.0
{ "", "3.1.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 3.1.0
{ "", "3.2.0", 8, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 3.2.0
{ "", "3.3.0", 4, 1, 16, 20000, DART_TAG_STYLE_CID_SHIFT1, 5 }, // Dart 3.3.0
{ "", "3.4.0", 8, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5 }, // Dart 3.4.0
{ "", "3.5.0", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5 }, // Dart 3.5.0
{ "", "3.6.0", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5 }, // Dart 3.6.0
{ "", "3.9.0", 4, 1, 16, 20000, DART_TAG_STYLE_OBJECT_HEADER, 5 }, // Dart 3.9.0
{ { 0 }, NULL, 0, 0, 0, 0, 0, 0 }
};
const char *dart_version_from_hash(const char *hash) {
@@ -137,19 +167,22 @@ const DartVerLayout *dart_profile_from_version(const char *version) {
if (!version) {
return NULL;
}
const DartVerLayout *best = NULL;
for (int i = 0; version_profiles[i].dart_version; i++) {
if (!strcmp (version_profiles[i].dart_version, version)) {
return &version_profiles[i];
const int cmp = dart_version_compare (version, version_profiles[i].dart_version);
if (cmp == -2) {
return NULL;
}
if (cmp < 0) {
break;
}
best = &version_profiles[i];
}
return NULL;
return best? best: version_profiles;
}
DartVerLayout *dart_pick_layout_by_hash(const char *hash) {
DartVerLayout *dvl = calloc (1, sizeof (DartVerLayout));
if (!dvl) {
return NULL;
}
DartVerLayout *dvl = R_NEW0 (DartVerLayout);
const char *version = dart_version_from_hash (hash);
const DartVerLayout *profile = version? dart_profile_from_version (version): NULL;
if (profile) {
@@ -169,16 +202,6 @@ DartVerLayout *dart_pick_layout_by_hash(const char *hash) {
dvl->it_cap = 20000;
dvl->tag_style = DART_TAG_STYLE_OBJECT_HEADER;
dvl->header_fields = 5;
dvl->cid_class = 5;
dvl->cid_function = 7;
dvl->cid_code = 18;
dvl->cid_string = 93;
dvl->cid_one_byte_string = 94;
dvl->cid_two_byte_string = 95;
dvl->cid_array = 90;
dvl->cid_mint = 61;
dvl->cid_object_pool = 23;
dvl->num_predefined_cids = 175;
dvl->dart_version = "unknown";
if (G_VERBOSE > 0) {
fprintf (stderr, "[r2flutter] Unknown snapshot hash, using v3.9.2 defaults (hash=%s)\n", hash? hash: "(null)");
+32 -9
View File
@@ -11,6 +11,7 @@
#define R2FLUTTER_CFG_MAPFILE "r2flutter.mapfile"
#define R2FLUTTER_CFG_NAMEPOOL "r2flutter.namepool"
#define R2FLUTTER_CFG_PROFILE "r2flutter.profile"
typedef struct {
char action;
@@ -31,51 +32,63 @@ static bool r2flutter_core_init(RCorePluginSession *cps) {
r_config_node_desc (node, "Flutter obfuscation map JSON path");
node = r_config_set_b (cfg, R2FLUTTER_CFG_NAMEPOOL, false);
r_config_node_desc (node, "Enable heuristic name-pool fallback resolution");
node = r_config_set (cfg, R2FLUTTER_CFG_PROFILE, "");
r_config_node_desc (node, "Override Dart snapshot profile by 32-byte hash or Dart version");
r_config_lock (cfg, true);
return true;
}
static bool r2flutter_core_fini(RCorePluginSession *cps) {
#if R2_PLUGIN_INCORE
// removing config vars causes an UAF. this is a temporal workaround
#else
RConfig *cfg = cps->core->config;
r_config_lock (cfg, false);
r_config_rm (cfg, R2FLUTTER_CFG_MAPFILE);
r_config_rm (cfg, R2FLUTTER_CFG_NAMEPOOL);
r_config_rm (cfg, R2FLUTTER_CFG_PROFILE);
r_config_lock (cfg, true);
#endif
return true;
}
static void r2flutter_apply_config(RCore *core, DartCtx *dctx) {
dctx->obf_map_path = r_config_get (core->config, R2FLUTTER_CFG_MAPFILE);
dctx->use_name_pool = r_config_get_b (core->config, R2FLUTTER_CFG_NAMEPOOL);
const char *profile = r_config_get (core->config, R2FLUTTER_CFG_PROFILE);
if (R_STR_ISNOTEMPTY (profile) && !dart_ctx_set_profile_override (dctx, profile)) {
R_LOG_WARN ("Ignoring unsupported Dart snapshot profile override: %s", profile);
}
}
static void r2flutter_help(RCore *core) {
r_cons_printf (core->cons,
"Usage: r2flutter [-jqrnv] [-l N] [-m file] <action>\n"
"Usage: r2flutter [options] <action>\n"
"| r2flutter show same -h help message\n"
"| r2flutter -j <act> output JSON for dump actions\n"
"| r2flutter -q <act> compact output; quiet analysis logs\n"
"| r2flutter -r <act> output r2 commands for dump actions\n"
"| r2flutter -n use heuristic name-pool fallback; names may be wrong\n"
"| r2flutter -v increase parser verbosity\n"
"| r2flutter -l N limit function/instruction-table/xref output\n"
"| r2flutter -m file load Flutter obfuscation map JSON\n"
"| r2flutter -A analyze dart snapshot and apply flags/comments\n"
"| r2flutter -AA analyze with field extraction enabled\n"
"| r2flutter -AAA run Dart-aware code analysis and recover code refs\n"
"| r2flutter -c dump classes\n"
"| r2flutter -C apply Dart classes, fields, methods and types\n"
"| r2flutter -D prof override Dart snapshot profile by hash or version\n"
"| r2flutter -f dump recovered functions\n"
"| r2flutter -H dump Dart AOT snapshot header info\n"
"| r2flutter -HH dump Dart AOT snapshot header and cluster layout\n"
"| r2flutter -HHH decode selected cluster payloads for diagnostics\n"
"| r2flutter -h show this help\n"
"| r2flutter -i dump instruction table entries\n"
"| r2flutter -j <act> output JSON for dump actions\n"
"| r2flutter -l N limit function/instruction-table/xref output\n"
"| r2flutter -m file load Flutter obfuscation map JSON\n"
"| r2flutter -n use heuristic name-pool fallback; names may be wrong\n"
"| r2flutter -O addr decode Dart tagged/object pointer or ObjectPool PP slot\n"
"| r2flutter -p print reconstructed ObjectPool PP value\n"
"| r2flutter -q <act> compact output; quiet analysis logs\n"
"| r2flutter -r <act> output r2 commands for dump actions\n"
"| r2flutter -R dump full radare2 script (like standalone -R)\n"
"| r2flutter -S dump best-effort recovered SBOM/components\n"
"| r2flutter -T dump string-based type names\n"
"| r2flutter -v increase parser verbosity\n"
"| r2flutter -V show version\n"
"| r2flutter -x dump metadata/data-image xrefs; with -z, include string refs/ax in -r\n"
"| r2flutter -z dump reliable ObjectPool-referenced strings (-q prints values only)\n"
@@ -231,6 +244,16 @@ static bool r2flutter_parse_cmd(const char *args, DartCtx *dctx, R2FlutterCmd *c
case 'p':
cmd->action = flag;
break;
case 'D':
{
const char *arg = r2flutter_opt_arg (tail, words, nwords, &i);
if (!arg || !dart_ctx_set_profile_override (dctx, arg)) {
cmd->help = true;
break;
}
j += strlen (tail);
break;
}
case 'j':
cmd->fmt = 'j';
break;
@@ -301,7 +324,7 @@ static bool r2flutter_parse_cmd(const char *args, DartCtx *dctx, R2FlutterCmd *c
cmd->help = true;
break;
}
if (cmd->help || (R_STR_ISNOTEMPTY (tail) && (flag == 'l' || flag == 'm' || flag == 'O'))) {
if (cmd->help || (R_STR_ISNOTEMPTY (tail) && (flag == 'l' || flag == 'm' || flag == 'O' || flag == 'D'))) {
break;
}
}
+9 -2
View File
@@ -14,9 +14,9 @@ static const char usage_text[] =
"Modifiers:\n"
" -h Show help\n"
" -j Output in JSON format\n"
" -n Heuristic fallback for unknown functions; may assign wrong names\n"
" -q Compact output; suppress non-essential detail\n"
" -r Output r2 commands for the selected action\n"
" -n Heuristic fallback for unknown functions; may assign wrong names\n"
" -v Verbose (stderr debug info)\n"
" -vv More verbose (dump headers)\n"
" -V Show version\n"
@@ -39,6 +39,7 @@ static const char usage_text[] =
" -z Print reliable ObjectPool-referenced strings (-q prints values only)\n"
" -zz Print all fuzzy/carved extracted strings (-xzz includes refs/ax in -r)\n"
"Options:\n"
" -D <hash|version> Override Dart snapshot profile for analysis\n"
" -l <N> Limit output to N items\n"
" -m <file> Load Flutter obfuscation map JSON\n";
@@ -117,7 +118,7 @@ int main(int argc, char **argv) {
.no_stubs = true
};
RGetopt opt;
r_getopt_init (&opt, argc, (const char **)argv, "AcfhHijnm:O:pqrRSzTvVxl:");
r_getopt_init (&opt, argc, (const char **)argv, "AcD:fhHijnm:O:pqrRSzTvVxl:");
int c;
while ((c = r_getopt_next (&opt)) != -1) {
switch (c) {
@@ -149,6 +150,12 @@ int main(int argc, char **argv) {
case 'p':
action = c;
break;
case 'D':
if (!dart_ctx_set_profile_override (&dctx, opt.arg)) {
R_LOG_ERROR ("Unsupported Dart snapshot profile override: %s", opt.arg);
return 1;
}
break;
case 'j':
fmt = c;
break;
+1 -1
View File
@@ -5,7 +5,7 @@
"timeout": 30,
"expect": {
"contains": [
"snapshot_hash=78da37fed6bf1489361a312568249f3f dart_version=unknown",
"snapshot_hash=78da37fed6bf1489361a312568249f3f dart_version=3.11.5",
"detail: object_pool_entries",
"34 cid=23 alloc=object_pool fill=none count=1",
"object_pool_decode: fill_not_parsed"
+1 -1
View File
@@ -4,6 +4,6 @@ CMDS=<<EOF
!!../bin/r2flutter -j -H bins/android/first 2>/dev/null
EOF
EXPECT=<<EOF
{"kind":3,"hash":"f91b8b03bf7f30a5e983fd19b23d978d","vm_data":512,"vm_instr":327680,"iso_data":36544,"iso_instr":419584,"cluster":{"base":1154,"objs":11342,"clusters":47,"it_len":1311,"it_off":64,"total":91657},"cws":8,"dart_version":"unknown","tag_style":"OBJECT_HEADER","alignment":16,"header_fields":5,"it_capacity":20000,"cid_table":{"cid_class":5,"cid_function":7,"cid_code":18,"cid_string":93,"cid_one_byte_string":94,"cid_two_byte_string":95,"cid_array":90,"cid_mint":61,"cid_object_pool":23,"num_predefined":175}}
{"kind":3,"hash":"f91b8b03bf7f30a5e983fd19b23d978d","vm_data":512,"vm_instr":327680,"iso_data":36544,"iso_instr":419584,"cluster":{"base":1154,"objs":11342,"clusters":47,"it_len":1311,"it_off":64,"total":91657},"cws":8,"dart_version":"2.18.2","tag_style":"OBJECT_HEADER","alignment":16,"header_fields":5,"it_capacity":20000,"cid_table":{"cid_class":5,"cid_function":7,"cid_code":18,"cid_string":93,"cid_one_byte_string":94,"cid_two_byte_string":95,"cid_array":90,"cid_mint":61,"cid_object_pool":23,"num_predefined":175}}
EOF
RUN
+9
View File
@@ -0,0 +1,9 @@
NAME=header-override-profile
FILE=-
CMDS=<<EOF
!!../bin/r2flutter -j -D 830f4f59e7969c70b595182826435c19 -H bins/android/first 2>/dev/null
EOF
EXPECT=<<EOF
{"kind":3,"hash":"830f4f59e7969c70b595182826435c19","vm_data":512,"vm_instr":327680,"iso_data":36544,"iso_instr":419584,"cluster":{"base":1154,"objs":11342,"clusters":47,"it_len":1311,"it_off":64,"total":91657},"cws":8,"dart_version":"3.8.1","tag_style":"OBJECT_HEADER","alignment":16,"header_fields":5,"it_capacity":20000,"cid_table":{"cid_class":5,"cid_function":7,"cid_code":18,"cid_string":93,"cid_one_byte_string":94,"cid_two_byte_string":95,"cid_array":90,"cid_mint":61,"cid_object_pool":23,"num_predefined":175}}
EOF
RUN
+20 -17
View File
@@ -14,9 +14,9 @@ Usage: ../bin/r2flutter [options] <libapp_path_or_dir>
Modifiers:
-h Show help
-j Output in JSON format
-n Heuristic fallback for unknown functions; may assign wrong names
-q Compact output; suppress non-essential detail
-r Output r2 commands for the selected action
-n Heuristic fallback for unknown functions; may assign wrong names
-v Verbose (stderr debug info)
-vv More verbose (dump headers)
-V Show version
@@ -39,34 +39,36 @@ Actions:
-z Print reliable ObjectPool-referenced strings (-q prints values only)
-zz Print all fuzzy/carved extracted strings (-xzz includes refs/ax in -r)
Options:
-D <hash|version> Override Dart snapshot profile for analysis
-l <N> Limit output to N items
-m <file> Load Flutter obfuscation map JSON
===
Usage: r2flutter [-jqrnv] [-l N] [-m file] <action>
Usage: r2flutter [options] <action>
| r2flutter show same -h help message
| r2flutter -j <act> output JSON for dump actions
| r2flutter -q <act> compact output; quiet analysis logs
| r2flutter -r <act> output r2 commands for dump actions
| r2flutter -n use heuristic name-pool fallback; names may be wrong
| r2flutter -v increase parser verbosity
| r2flutter -l N limit function/instruction-table/xref output
| r2flutter -m file load Flutter obfuscation map JSON
| r2flutter -A analyze dart snapshot and apply flags/comments
| r2flutter -AA analyze with field extraction enabled
| r2flutter -AAA run Dart-aware code analysis and recover code refs
| r2flutter -c dump classes
| r2flutter -C apply Dart classes, fields, methods and types
| r2flutter -D prof override Dart snapshot profile by hash or version
| r2flutter -f dump recovered functions
| r2flutter -H dump Dart AOT snapshot header info
| r2flutter -HH dump Dart AOT snapshot header and cluster layout
| r2flutter -HHH decode selected cluster payloads for diagnostics
| r2flutter -h show this help
| r2flutter -i dump instruction table entries
| r2flutter -j <act> output JSON for dump actions
| r2flutter -l N limit function/instruction-table/xref output
| r2flutter -m file load Flutter obfuscation map JSON
| r2flutter -n use heuristic name-pool fallback; names may be wrong
| r2flutter -O addr decode Dart tagged/object pointer or ObjectPool PP slot
| r2flutter -p print reconstructed ObjectPool PP value
| r2flutter -q <act> compact output; quiet analysis logs
| r2flutter -r <act> output r2 commands for dump actions
| r2flutter -R dump full radare2 script (like standalone -R)
| r2flutter -S dump best-effort recovered SBOM/components
| r2flutter -T dump string-based type names
| r2flutter -v increase parser verbosity
| r2flutter -V show version
| r2flutter -x dump metadata/data-image xrefs; with -z, include string refs/ax in -r
| r2flutter -z dump reliable ObjectPool-referenced strings (-q prints values only)
@@ -74,31 +76,32 @@ Usage: r2flutter [-jqrnv] [-l N] [-m file] <action>
===
Usage: ../bin/r2flutter [options] <libapp_path_or_dir>
===
Usage: r2flutter [-jqrnv] [-l N] [-m file] <action>
Usage: r2flutter [options] <action>
| r2flutter show same -h help message
| r2flutter -j <act> output JSON for dump actions
| r2flutter -q <act> compact output; quiet analysis logs
| r2flutter -r <act> output r2 commands for dump actions
| r2flutter -n use heuristic name-pool fallback; names may be wrong
| r2flutter -v increase parser verbosity
| r2flutter -l N limit function/instruction-table/xref output
| r2flutter -m file load Flutter obfuscation map JSON
| r2flutter -A analyze dart snapshot and apply flags/comments
| r2flutter -AA analyze with field extraction enabled
| r2flutter -AAA run Dart-aware code analysis and recover code refs
| r2flutter -c dump classes
| r2flutter -C apply Dart classes, fields, methods and types
| r2flutter -D prof override Dart snapshot profile by hash or version
| r2flutter -f dump recovered functions
| r2flutter -H dump Dart AOT snapshot header info
| r2flutter -HH dump Dart AOT snapshot header and cluster layout
| r2flutter -HHH decode selected cluster payloads for diagnostics
| r2flutter -h show this help
| r2flutter -i dump instruction table entries
| r2flutter -j <act> output JSON for dump actions
| r2flutter -l N limit function/instruction-table/xref output
| r2flutter -m file load Flutter obfuscation map JSON
| r2flutter -n use heuristic name-pool fallback; names may be wrong
| r2flutter -O addr decode Dart tagged/object pointer or ObjectPool PP slot
| r2flutter -p print reconstructed ObjectPool PP value
| r2flutter -q <act> compact output; quiet analysis logs
| r2flutter -r <act> output r2 commands for dump actions
| r2flutter -R dump full radare2 script (like standalone -R)
| r2flutter -S dump best-effort recovered SBOM/components
| r2flutter -T dump string-based type names
| r2flutter -v increase parser verbosity
| r2flutter -V show version
| r2flutter -x dump metadata/data-image xrefs; with -z, include string refs/ax in -r
| r2flutter -z dump reliable ObjectPool-referenced strings (-q prints values only)