* feat(il2cpp): inventory IL2CPP global-metadata images, types and methods Add inspect_il2cpp_metadata (CLI inspect-il2cpp-metadata), a read-only in-process decoder for unencrypted Unity global-metadata.dat version 39. It reports header sections, serialized index widths, images, type definitions (nesting from the nestedTypes section) and method names. Unrecognized magic and other versions are unsupported; damaged headers, overlapping sections, inconsistent record sizes, out-of-range indices and invalid strings fail with a reason code and no partial success. MCP detail summary retains the complete Evidence and pages rows through inspect_analysis_view kind il2cpp-metadata. Adds an opt-in verify:il2cpp:metadata -- --metadata PATH check. * feat(il2cpp): deliver metadata summaries by default over MCP A 112,232-method file produced a 10.5 MB complete response, above the 10 MiB stdio budget. Default MCP delivery is now the retained summary; detail complete stays available, and the one-shot CLI requests it. * fix(il2cpp): reject shifted strings, nesting cycles and method owner drift Review fuzzing showed that moving the strings section offset by one byte silently renamed every image, type and method. Name indices must now start a string, which also bounds total decoding by the section size. Nesting cycles and methods whose declaring type disagrees with the owning type range are rejected instead of returned. Adds service, shutdown and index-width coverage, and moves environment-specific measurements out of the public guide and tool description. * feat(il2cpp): decode global-metadata versions 29 and 31 Unity 2022.3 writes version 29 or 31 metadata: a 256-byte header of (offset, size) pairs, fixed 4-byte indices, type records with elementTypeIndex, and method records that gained returnParameterToken in version 31. Record counts come from section sizes and must be whole. Sections report a null count for these versions and index widths report fixed-width-version. Image, type and method rows keep the same shape, and the string, nesting and method-ownership checks apply to every version. * fix(il2cpp): bound report size before serializing and tighten coverage Rows share decoded names, so a 130 KB file could expand into gigabytes of JSON before the 64 MiB budget check, ending in an internal RangeError. The provider now refuses from a lower bound on the serialized rows first. The decoder also rejects non-empty sections inside the header, methods outside their declaring type's range and overlapping image type ranges, and keeps a leading byte order mark in names. Layouts now carry one indexing mode instead of two coupled flags, and the tool description explains nested_type_start. * fix(il2cpp): refuse oversized metadata before decoding rows Address review findings on the IL2CPP metadata inventory: - check a lower bound from header row counts before any row object is allocated, so a large rejected file no longer builds every row first; - validate sealed parent Evidence and count its rows once per report instead of on every inspect_analysis_view page; - decode version 39 fixtures with 2- and 4-byte type-definition, generic-container and parameter indices. * docs(il2cpp): attach the decoder comment to readIl2cppMetadata * fix(il2cpp): deliver complete rows by default like the other inspection tools inspect_il2cpp_metadata defaulted to detail summary, the only inspection tool to do so. Omitted detail now returns every row inline, as inspect_artifact, decode_interface_builder and the capture tools do; summary stays one argument away and the guide, CLI reference and skill reference say to select it first for large games, whose complete MCP delivery is refused at the stdio budget with retained Evidence. * test(il2cpp): cover narrow-width -1 sentinels and fix the skill's default An empty image stores its type start as the all-ones value of a one- or two-byte index; the decoder reads it as -1, but no fixture exercised it, so removing either conversion passed the suite. The fixture can now append an empty image, and both widths decode it. The skill still described a summary default; it now says to select summary first, as the guide does. * docs(il2cpp): request summary explicitly in the summary example * chore(il2cpp): hash the verifier metadata through owned file resources * fix(il2cpp): count escaped name length without building the escaped string * fix(il2cpp): keep the verifier's check failure and small-table last page * feat(domain): count JSON string length without building the escaped string * fix(il2cpp): keep descriptor cleanup owners and share the JSON length count * test(domain): give the backslash case real backslashes * fix(il2cpp): select the CLI path and finish the command like the other tools Follow main's absoluteCallerPath (#4067) and pass the command signal to finishAnalysisCommand. * fix(il2cpp): select the verifier input path like the CLI Use absoluteCallerPath (#4067) so a path with a symlink followed by .. names the same file the CLI and MCP inspect. * feat(il2cpp): add compact composable metadata queries Retain source-indexed Evidence for filtered batch and field queries. Bound representation growth before serialization, yield decoding for cancellation, and share CLI Evidence publication with desktop inspection. Verify public Unity metadata against independent byte and managed-DLL oracles and exercise actual stdio SDK workflows. * fix(il2cpp): retain the validated metadata header magic * test(il2cpp): remove obsolete execution wording exception * fix(artifacts): preserve export selection and completed source facts --------- Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
9.0 KiB
Desktop installation directories
Use inspect_desktop_application when an installation directory is the target
and its runtime is unknown. It reads directory entries, selected headers and
bounded metadata, then reports runtime candidates, supporting files, component
path markers and concrete follow-up operations. No native provider or active
binary session is needed. It does not run the application, extract archives,
follow child symlinks, contact services or change target files.
MCP
{ "path": "/artifacts/MyApplication" }
Default detail: "summary" retains complete source Evidence in the session and
returns candidates with representative supporting paths, counts, coverage,
limitations and grouped next probes. normalized_result.parent_evidence_id
identifies the complete record. A server without Evidence retention refuses
summary delivery before reading the target; select detail: "complete" to
receive every retained fact inline.
Read exact files in one request:
{
"source": {
"kind": "retained-evidence",
"evidence_id": "ev_<parent-sha256>"
},
"view": {
"kind": "desktop-application",
"collection": "files",
"paths": ["Game_Data/Managed/Assembly-CSharp.dll", "GameAssembly.dll"],
"fields": ["path", "read_status", "ranges", "facts", "issues"],
"offset": 0,
"limit": 16
}
}
Collections are files, omissions, candidates, components and next_probes.
Files and omissions accept exact paths and batched file_ids / omission_ids.
Files also accept has_issues: true to select probe diagnostics directly, or
false to select rows without reported issues. This filter uses the retained
issue facts; it does not re-read targets or infer that uninspected files are healthy.
When both are supplied, all filters apply; an empty selection returns no rows.
Omission records retain the observed path, kind and stable omission_id; their
payloads are not read, and other special-entry metadata remains unavailable.
candidates accepts exact families.
Omitted selectors match all retained rows; an empty selector matches none.
Every collection supports fields, offset and limit; its stable row ID is
always included. Selection changes delivery, not source inspection. Pages keep
source coverage and parent Evidence links. Page exhaustion does not establish
absence in a partial source. Complete Evidence remains accessible through
get_evidence and Evidence bundle export.
The summary's probe_issues counts files with reported issues and their retained
issue entries. It previews at most two such files, including stable file_id,
read status and the first issue. Path/reason previews use at most 256 UTF-16 units
each without splitting surrogate pairs; text_truncated marks shortened text,
and preview_truncated marks additional files. These are display prefixes;
full caller paths and all reasons remain in Evidence. Counts describe retained
observations, while source coverage still identifies partial inspection.
Use inspect_analysis_view with collection: "files", has_issues: true and
fields: ["path", "read_status", "issues"] for exact reasons, with the usual
paging and parent links. It intersects with exact paths and batched file IDs.
An ASAR inventory probe first selects its exact path with open_binary; then
call inspect_artifact on that active target. Directory inspection itself does
not select or replace the session target. The JavaScript application workflow
accepts its own selected path directly.
CLI
The one-shot CLI returns complete Evidence by default. For compact output, explicitly retain it in a bundle:
rea inspect-desktop-application /artifacts/MyApplication \
--detail summary --evidence_output /reports/application.evidence.json --json
This returns summary Evidence and an evidence_bundle publication receipt.
Existing output files are never overwritten. Summary delivery requires
--evidence_output, checked before analysis. inspect-evidence-bundle selects
saved records; an exact saved record can also feed inspect-analysis-view.
--detail complete returns source Evidence inline and can optionally write the
same bundle. Export writes only the caller-selected output file.
Facts and uncertainty
| Family | Evidence used |
|---|---|
| .NET | A PE optional header declares a nonempty CLI directory. |
| Unity Mono | A managed assembly below *_Data/Managed or Contents/Resources/Data/Managed has an exact UnityEngine assembly reference. |
| Unity IL2CPP | An IL2CPP metadata header coexists with a conventionally named native GameAssembly.dll, GameAssembly.so, GameAssembly.dylib or libil2cpp.so image. Build correspondence remains unknown. |
| Godot | A GDPC header at file start or a validated executable trailer offset. |
| GameMaker | A bounded FORM container starts with a GEN8 chunk. |
| Unreal | Content/Paks path conventions or an IoStore TOC signature; arbitrary .pak filenames are insufficient. |
| Electron | A resources/app.asar or resources/default_app.asar path convention; archive validity is unverified. |
An observed metadata header with supported raw version 29, 31 or 39 offers an
inspect_il2cpp_metadata follow-up at its admitted file path, including when no
native library was found. This probe does not establish full metadata validity
or correspondence to a native binary. See IL2CPP metadata.
Candidates are derived or inferred from these facts and do not prove loading or execution. BepInEx, MelonLoader, Easy Anti-Cheat and BattlEye labels identify path conventions only; runtime presence stays unknown. No bypass is provided.
file_id includes the admitted root namespace, recorded path and available filesystem identity. The caller-selected root path and admitted canonical path/root identity are both retained; local_path identifies each observed file for follow-up operations. The selected root may be a symlink; child symlinks are not followed. Exact
metadata integers remain decimal strings. Read ranges have offsets, byte counts
and SHA-256 digests; typed facts expose CLI RVAs, metadata/pack versions and
assembly tokens. Directory and symlink identities unavailable from traversal
remain null.
The directory's snapshot_sha256 commits to retained paths, omission kinds,
available metadata and range digests, composed through the admitted root,
entry and omission identities. Caller ceilings, coverage counters, diagnostic
wording and interpretation facts remain in Evidence, outside source identity.
The same observations under different generous limits share a snapshot digest;
Evidence IDs still preserve request parameters and reported coverage. Different
retained entries or read ranges change the source snapshot.
Omission records share the entry and representation budgets and can be fetched
independently through their view.
It is not a digest of all file contents. These are sequential stable entry
observations, not an atomic directory snapshot. Unread bytes remain unknown.
Resource bounds and reuse
Defaults are 20,000 examined entries and 8 MiB of total probe reads. Callers may select up to 100,000 entries and 64 MiB. A separate 32 MiB conservative representation budget bounds retained paths and facts before growth. Limits and failed probes produce partial coverage. Traversal and reads are serial. Each reader admits one inspection at a time; overlapping requests receive a retryable capacity refusal without cancelling the admitted caller.
Unity reference decoding stops after a witness in each Data/Managed directory;
other assemblies' references remain unexamined, while their headers are still
checked. AssemblyRef facts decode names and tokens only; they do not decode or
hash unrelated key/culture/hash payloads or establish runtime binding. Pack contents, encrypted data, metadata/address correspondence and
section-embedded PCKs without a trailer are separate capabilities.
Filesystem results are not cached across calls. Retained views reuse validated immutable metadata without rescanning files or retaining another inventory.