From a4e6446d16defdbb4e8e8d6bf736b94c607d5f22 Mon Sep 17 00:00:00 2001 From: pancake Date: Fri, 17 Apr 2026 19:17:59 +0200 Subject: [PATCH] Reject v24.0 metadata instead of silently decoding wrong offsets --- doc/future.md | 4 ++++ doc/r2unity.md | 8 ++++++-- src/lib/lib.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/doc/future.md b/doc/future.md index 6e058e7..be7ee34 100644 --- a/doc/future.md +++ b/doc/future.md @@ -119,12 +119,16 @@ if (version < 24 || version > 31) return NULL; if (version < 27) header_size = sizeof (v24); else if (version < 29) header_size = sizeof (v27); else header_size = sizeof (v29); /* 29, 30, 31 */ +/* After normalizing header fields, reject v24.0 via image-stride probe. */ +if (version == 24 && is_v24_0 (meta)) return NULL; ``` | Wire version | Status | Reality | |--------------|-----------------------------------|--------------------------------------------------------------------------------------------| | 16, 19, 20 | Rejected | Pre-Unity-5.5 builds, effectively extinct. | | 21, 22, 23 | Rejected | Unity 5.3 – 5.5 IPAs exist but are rare. | +| 24.0 | Rejected after sub-version probe | On-disk `version` is 24 for both v24.0 and v24.1+. The parser probes image-row stride (32 B vs 40 B) and rejects v24.0 with an explicit error; TypeDefinition/MethodDefinition/ImageDefinition rows would otherwise decode at wrong offsets. | +| 24.1 – 24.5 | Accepted via `_v24` header struct | Row decoders target the v24.1+ strides. | | 27 | Accepted via `_v27` header struct | Header correct. Row decoders still assume the v24.1+ layout; v27.2 RGCTX widening not handled (only affects RGCTX which is unused). | | 29 | Accepted via `_v29` header struct | Header correct. Method rows decoded as 32 B. Reverse-P/Invoke BLOB path is the only v29-specific code. | | 30 | Accepted | Never shipped on disk; dead slot, safe. | diff --git a/doc/r2unity.md b/doc/r2unity.md index f8f2336..311f640 100644 --- a/doc/r2unity.md +++ b/doc/r2unity.md @@ -917,9 +917,13 @@ Unity-release → wire-version → sub-version mapping. `Il2CppMethodDefinition`, aligning with ECMA-335's return-value param-row model. -r2unity's current acceptance band is **v24..v31**, with dedicated +r2unity's current acceptance band is **v24.1..v31**, with dedicated handling only for the v24.1+ table strides and the v31 -`returnParameterToken` insertion. +`returnParameterToken` insertion. Since the on-disk `version` field is +`24` for both v24.0 and v24.1+, the parser probes the image-row stride +(32 B on v24.0, 40 B on v24.1+) and rejects v24.0 explicitly to avoid +silent mis-decoding of TypeDefinition/MethodDefinition/ImageDefinition +rows. ## 5. How the parser is wired in r2unity diff --git a/src/lib/lib.c b/src/lib/lib.c index 4035258..6a38011 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -14,6 +14,43 @@ R_API bool r2unity_is_debug (void) { } +/* Detect v24.0 vs v24.1+ (both land on disk as version==24). + * + * At v24.1 the ImageDefinition row grew by 8 bytes (added + * customAttributeStart/Count), so imagesSize is a multiple of 40 on v24.1+ + * and 32 on v24.0. When imagesSize is divisible by both (a multiple of 160), + * probe the 4 bytes at offset 40: under v24.1+ that is row 1's nameIndex + * (a valid string-pool offset); under v24.0 it is mid-row. + * + * Fixing row layouts for v24.0 (larger TypeDefinition, MethodDefinition, + * ImageDefinition) is tracked separately; reject for now so decoders don't + * silently return wrong offsets. */ +static bool is_v24_0 (R2UnityMetadata *meta) { + ut64 ioff = meta->header.v24.imagesOffset; + ut64 isize = meta->header.v24.imagesSize; + if (!isize) { + return false; + } + bool div40 = (isize % 40) == 0; + bool div32 = (isize % 32) == 0; + if (div40 && !div32) { + return false; + } + if (div32 && !div40) { + return true; + } + if (isize >= 44) { + ut8 probe[4]; + if (r_buf_read_at (meta->buf, ioff + 40, probe, 4) == 4) { + uint32_t name_idx = r_read_le32 (probe); + if (name_idx < (uint32_t) meta->stringSize) { + return false; + } + } + } + return true; +} + R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf) { if (!buf) { return NULL; @@ -97,6 +134,13 @@ R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf) { meta->typeDefinitionsOffset = meta->header.v29.typeDefinitionsOffset; meta->typeDefinitionsSize = meta->header.v29.typeDefinitionsSize; } + if (meta->version == 24 && is_v24_0 (meta)) { + R_LOG_ERROR ("v24.0 metadata (Unity 5.6..2018.2) not supported: " + "TypeDefinition/MethodDefinition/ImageDefinition row layouts " + "differ from v24.1+ and would silently decode wrong offsets"); + r2unity_free_metadata (meta); + return NULL; + } meta->strings = r_buf_new_slice (buf, meta->stringOffset, meta->stringSize); meta->string_literals = r_buf_new_slice (buf, meta->stringLiteralOffset, meta->stringLiteralSize); if (g_debug) {