diff --git a/src/il2cpp/Il2cppBinaryRegistration.ts b/src/il2cpp/Il2cppBinaryRegistration.ts index 1ae50113c3..0452477ec5 100644 --- a/src/il2cpp/Il2cppBinaryRegistration.ts +++ b/src/il2cpp/Il2cppBinaryRegistration.ts @@ -331,6 +331,7 @@ export function* findMetadataRegistration( } > { const matches: { field: bigint; count: number; types: bigint }[] = []; + const matchedFields = new Set(); const low = (offset: number) => image.bytes.readUInt32LE(offset); const word = (offset: number) => image.bytes.readBigUInt64LE(offset); for (const mapping of image.container.mappings) { @@ -350,13 +351,17 @@ export function* findMetadataRegistration( !isMapped(image, types, count * 8) ) continue; + const field = mapping.address + BigInt(at + 48); + // Exact load aliases can visit one virtual registration field twice. + if (matchedFields.has(field)) continue; + matchedFields.add(field); if (matches.length !== 0) throw new Il2cppBinaryFormatFailure( "metadata-registration-not-found", "multiple MetadataRegistration candidates match", ); matches.push({ - field: mapping.address + BigInt(at + 48), + field, count, types, }); diff --git a/tests/boundary/il2cpp/il2cppBinaryFile.test.ts b/tests/boundary/il2cpp/il2cppBinaryFile.test.ts index f0488b2cf4..a8c0738241 100644 --- a/tests/boundary/il2cpp/il2cppBinaryFile.test.ts +++ b/tests/boundary/il2cpp/il2cppBinaryFile.test.ts @@ -124,6 +124,16 @@ it("still rejects distinct CodeRegistration module table fields", () => { ).toEqual({ reason: "code-registration-not-found", kind: "malformed" }); }); +it("still rejects distinct MetadataRegistration fields", () => { + expect( + failure( + createElfFixture( + createIl2cppBinaryFixture({ duplicateMetadataRegistration: true }), + ), + ), + ).toEqual({ reason: "metadata-registration-not-found", kind: "malformed" }); +}); + it("rejects reused MethodDef tokens within an image but preserves cross-image reuse and folded addresses", () => { const duplicateTokens = Uint32Array.from(facts.methodTokens); duplicateTokens[1] = duplicateTokens[0]!; diff --git a/tests/fixtures/il2cpp/binary.ts b/tests/fixtures/il2cpp/binary.ts index 2eafd51117..3b8283f6c7 100644 --- a/tests/fixtures/il2cpp/binary.ts +++ b/tests/fixtures/il2cpp/binary.ts @@ -31,6 +31,8 @@ export interface Il2cppBinaryFixtureOptions { readonly codeReference?: boolean; /** Omit the MetadataRegistration type table. */ readonly metadataRegistration?: boolean; + /** Write a second distinct MetadataRegistration candidate. */ + readonly duplicateMetadataRegistration?: boolean; /** Byte written before each image name instead of NUL (MSVC pads with 0xFF). */ readonly namePadding?: number; /** Text written directly before mscorlib.dll, making it the tail of a longer name. */ @@ -162,6 +164,15 @@ export const createIl2cppBinaryFixture = ( word(11, address(TYPE_POINTERS)); word(12, 4n); word(13, address(TYPE_POINTERS)); + if (options.duplicateMetadataRegistration === true) { + const duplicate = METADATA_REGISTRATION + 0x80; + bytes.writeBigUInt64LE(BigInt(types.length), duplicate + 6 * 8); + bytes.writeBigUInt64LE(address(TYPE_POINTERS), duplicate + 7 * 8); + bytes.writeBigUInt64LE(4n, duplicate + 10 * 8); + bytes.writeBigUInt64LE(address(TYPE_POINTERS), duplicate + 11 * 8); + bytes.writeBigUInt64LE(4n, duplicate + 12 * 8); + bytes.writeBigUInt64LE(address(TYPE_POINTERS), duplicate + 13 * 8); + } } return bytes; };