[GH-ISSUE #5403] [Bug] IL2CPP metadata with a missing version reports unrecognized magic #3273

Closed
opened 2026-10-31 00:38:38 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5403

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

CLI

Observed behavior

node scripts/rea.mjs inspect-il2cpp-metadata <file> --json reports unsupported_target with unrecognized-magic for a four-through-seven-byte file beginning with the complete IL2CPP magic af 1b b1 fa. The diagnostic says that the magic is absent, although only the version field is absent or incomplete. Each case still exits 1.

Reproduction

The independent verifier ran this public CLI reproduction twice from the built source checkout. It creates synthetic regular files and isolates CLI state; no Unity installation or native-analysis provider is required.

WORK=$(mktemp -d)
export HOME="$WORK/home"
export XDG_CONFIG_HOME="$WORK/config"
export XDG_DATA_HOME="$WORK/data"
export XDG_CACHE_HOME="$WORK/cache"
export XDG_STATE_HOME="$WORK/state"
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME"
python3 - "$WORK" <<'PYTHON'
import json
import pathlib
import struct
import subprocess
import sys

root = pathlib.Path(sys.argv[1])
magic = bytes.fromhex("af1bb1fa")
inputs = {f"magic-{size}.dat": magic + bytes(size - 4) for size in range(4, 8)}
inputs.update({
    "cut-header.dat": magic + struct.pack("<i", 39) + bytes(56),
    "v39-eight.dat": magic + struct.pack("<i", 39),
    "wrong-magic.dat": bytes(4),
    "v27-eight.dat": magic + struct.pack("<i", 27),
})
for name, content in inputs.items():
    path = root / name
    path.write_bytes(content)
    result = subprocess.run(
        ["node", "scripts/rea.mjs", "inspect-il2cpp-metadata", str(path), "--json"],
        capture_output=True, text=True,
    )
    value = json.loads(result.stdout)
    details = value.get("details", {})
    diagnostic = details.get("reason")
    if diagnostic is None:
        diagnostic = details["issues"][0]["message"].split("is corrupt: ", 1)[-1]
    print(name, result.returncode, value["code"], diagnostic)
PYTHON

Expected behavior

Source-grounded expectation: docs/il2cpp-metadata.md:140-152 reserves unrecognized-magic for a magic other than 0xFAB11BAF and describes truncated-header for a file shorter than its header, returning an input error with an invalid_format issue. A complete recognized magic followed by a missing or partial version should therefore produce a truncation input error without assuming a version or a version-specific header size.

Impact and scope

Misleading error category and wording for already-invalid inputs. All eight synthetic cases failed inspection with exit 1, with the same results in both CLI runs. No successful decoding of corrupt data, valid-input failure, data loss, or security-boundary crossing was observed. Callers can identify this specific truncation by checking the four magic bytes and a total length below eight bytes. MCP was not replayed.

REA version

6.7.0; source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node v26.12.0; macOS (darwin), arm64. No Hopper/Ghidra or Unity runtime involved.

Target and artifact context

Synthetic regular files: recognized little-endian IL2CPP magic with total lengths 4, 5, 6 and 7 bytes; supported version 39 controls of 8 and 64 bytes; four zero bytes; and recognized magic plus complete unsupported version 27.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The reproduction above prints these reduced results (diagnostic suffixes are shown after the selected-artifact context for input errors):

magic-4.dat 1 unsupported_target unrecognized-magic: the file does not start with the IL2CPP global-metadata magic 0xFAB11BAF; encrypted or non-metadata inputs are not decoded
magic-5.dat 1 unsupported_target [same reason]
magic-6.dat 1 unsupported_target [same reason]
magic-7.dat 1 unsupported_target [same reason]
v39-eight.dat 1 invalid_request truncated-header: the file has 8 bytes, fewer than the 380-byte version 39 header
cut-header.dat 1 invalid_request truncated-header: the file has 64 bytes, fewer than the 380-byte version 39 header
wrong-magic.dat 1 unsupported_target [same unrecognized-magic reason]
v27-eight.dat 1 unsupported_target unsupported-version [diagnostic abbreviated]

Both version 39 controls have details.issues[0].reason: invalid_format. The missing-version inputs cannot establish an intended metadata version.

Typed outcome or recovery expected

Continue rejecting the four-through-seven-byte inputs, but return an input error (invalid_request) with an invalid_format issue containing truncated-header, preserving the unknown version. Preserve the wrong-magic and complete unsupported-version distinctions. These are proposed restoration checks; no fix was tested.

Analysis or suspected cause

Source-derived: src/il2cpp/Il2cppMetadataFile.ts:157-175 reads the magic when four bytes exist, then classifies every input shorter than eight bytes as unrecognized-magic. src/il2cpp/Il2cppMetadataProvider.ts:83-95 maps that unsupported classification to unsupported_target; corrupt classifications become input errors with invalid_format.

Additional context

Prepared with AI assistance and independently reproduced through the public CLI. Upstream main was fetched and checked: no commits after the tested baseline changed the cited decoder, provider, or documentation files. Related IL2CPP feature PRs expand metadata coverage but do not report this short-header diagnostic behavior.

NOT_ENOUGH_INFO: no last-known-good version or regression boundary was established. Valid metadata decoding and MCP behavior were not replayed in this verification.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5403 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area CLI ### Observed behavior `node scripts/rea.mjs inspect-il2cpp-metadata <file> --json` reports `unsupported_target` with `unrecognized-magic` for a four-through-seven-byte file beginning with the complete IL2CPP magic `af 1b b1 fa`. The diagnostic says that the magic is absent, although only the version field is absent or incomplete. Each case still exits 1. ### Reproduction The independent verifier ran this public CLI reproduction twice from the built source checkout. It creates synthetic regular files and isolates CLI state; no Unity installation or native-analysis provider is required. ```sh WORK=$(mktemp -d) export HOME="$WORK/home" export XDG_CONFIG_HOME="$WORK/config" export XDG_DATA_HOME="$WORK/data" export XDG_CACHE_HOME="$WORK/cache" export XDG_STATE_HOME="$WORK/state" mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" python3 - "$WORK" <<'PYTHON' import json import pathlib import struct import subprocess import sys root = pathlib.Path(sys.argv[1]) magic = bytes.fromhex("af1bb1fa") inputs = {f"magic-{size}.dat": magic + bytes(size - 4) for size in range(4, 8)} inputs.update({ "cut-header.dat": magic + struct.pack("<i", 39) + bytes(56), "v39-eight.dat": magic + struct.pack("<i", 39), "wrong-magic.dat": bytes(4), "v27-eight.dat": magic + struct.pack("<i", 27), }) for name, content in inputs.items(): path = root / name path.write_bytes(content) result = subprocess.run( ["node", "scripts/rea.mjs", "inspect-il2cpp-metadata", str(path), "--json"], capture_output=True, text=True, ) value = json.loads(result.stdout) details = value.get("details", {}) diagnostic = details.get("reason") if diagnostic is None: diagnostic = details["issues"][0]["message"].split("is corrupt: ", 1)[-1] print(name, result.returncode, value["code"], diagnostic) PYTHON ``` ### Expected behavior Source-grounded expectation: `docs/il2cpp-metadata.md:140-152` reserves `unrecognized-magic` for a magic other than `0xFAB11BAF` and describes `truncated-header` for a file shorter than its header, returning an input error with an `invalid_format` issue. A complete recognized magic followed by a missing or partial version should therefore produce a truncation input error without assuming a version or a version-specific header size. ### Impact and scope Misleading error category and wording for already-invalid inputs. All eight synthetic cases failed inspection with exit 1, with the same results in both CLI runs. No successful decoding of corrupt data, valid-input failure, data loss, or security-boundary crossing was observed. Callers can identify this specific truncation by checking the four magic bytes and a total length below eight bytes. MCP was not replayed. ### REA version 6.7.0; source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node v26.12.0; macOS (darwin), arm64. No Hopper/Ghidra or Unity runtime involved. ### Target and artifact context Synthetic regular files: recognized little-endian IL2CPP magic with total lengths 4, 5, 6 and 7 bytes; supported version 39 controls of 8 and 64 bytes; four zero bytes; and recognized magic plus complete unsupported version 27. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The reproduction above prints these reduced results (diagnostic suffixes are shown after the selected-artifact context for input errors): ```text magic-4.dat 1 unsupported_target unrecognized-magic: the file does not start with the IL2CPP global-metadata magic 0xFAB11BAF; encrypted or non-metadata inputs are not decoded magic-5.dat 1 unsupported_target [same reason] magic-6.dat 1 unsupported_target [same reason] magic-7.dat 1 unsupported_target [same reason] v39-eight.dat 1 invalid_request truncated-header: the file has 8 bytes, fewer than the 380-byte version 39 header cut-header.dat 1 invalid_request truncated-header: the file has 64 bytes, fewer than the 380-byte version 39 header wrong-magic.dat 1 unsupported_target [same unrecognized-magic reason] v27-eight.dat 1 unsupported_target unsupported-version [diagnostic abbreviated] ``` Both version 39 controls have `details.issues[0].reason: invalid_format`. The missing-version inputs cannot establish an intended metadata version. ### Typed outcome or recovery expected Continue rejecting the four-through-seven-byte inputs, but return an input error (`invalid_request`) with an `invalid_format` issue containing `truncated-header`, preserving the unknown version. Preserve the wrong-magic and complete unsupported-version distinctions. These are proposed restoration checks; no fix was tested. ### Analysis or suspected cause Source-derived: `src/il2cpp/Il2cppMetadataFile.ts:157-175` reads the magic when four bytes exist, then classifies every input shorter than eight bytes as `unrecognized-magic`. `src/il2cpp/Il2cppMetadataProvider.ts:83-95` maps that unsupported classification to `unsupported_target`; corrupt classifications become input errors with `invalid_format`. ### Additional context Prepared with AI assistance and independently reproduced through the public CLI. Upstream main was fetched and checked: no commits after the tested baseline changed the cited decoder, provider, or documentation files. Related IL2CPP feature PRs expand metadata coverage but do not report this short-header diagnostic behavior. NOT_ENOUGH_INFO: no last-known-good version or regression boundary was established. Valid metadata decoding and MCP behavior were not replayed in this verification.
Author
Owner

@CassieFox23 commented on GitHub (Oct 21, 2026):

Thanks, coygeek, for the eight-file matrix. From reading main at 01788bac8, not a run: this looks fixed. Commit b3aadaf474 on 2026-10-21 added src/domain/il2cpp/il2cppMetadataHeaderPrefix.ts. Four to seven bytes with the right magic now come back as kind "il2cpp" with version null (lines 49-55). The file src/il2cpp/Il2cppMetadataFile.ts:137-141 turns that into truncated-header instead of unrecognized-magic. PR #5726 closed the same day without merging. Closing is the maintainers' call.

🤖 Written with Claude Code (Fable 5.1, verified by Opus 5.5), posted with my OK 🦊

<!-- gh-comment-id:6321743256 --> @CassieFox23 commented on GitHub (Oct 21, 2026): Thanks, coygeek, for the eight-file matrix. From reading main at 01788bac8, not a run: this looks fixed. Commit b3aadaf474 on 2026-10-21 added `src/domain/il2cpp/il2cppMetadataHeaderPrefix.ts`. Four to seven bytes with the right magic now come back as kind `"il2cpp"` with version null (lines 49-55). The file `src/il2cpp/Il2cppMetadataFile.ts:137-141` turns that into `truncated-header` instead of `unrecognized-magic`. PR #5726 closed the same day without merging. Closing is the maintainers' call. 🤖 Written with Claude Code (Fable 5.1, verified by Opus 5.5), posted with my OK 🦊
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3273
No description provided.