fix(il2cpp): preserve recognized truncated metadata prefixes

This commit is contained in:
morluto committed 2026-10-21 01:47:09 +08:00
1 parent eb7acc70bf
commit b3aadaf474
10 files changed
+273 -25

No files matched your search

+4 -3
View File
@@ -3,7 +3,7 @@ import { createHash } from "node:crypto";
import { setImmediate } from "node:timers/promises";
import type { DesktopFile, DesktopFact } from "../domain/desktopApplication.js";
import { jsonValueByteLength } from "../domain/jsonValueByteLength.js";
import { IL2CPP_METADATA_MAGIC } from "../domain/il2cpp/il2cppMetadata.js";
import { observeIl2cppMetadataHeaderPrefix } from "../domain/il2cpp/il2cppMetadataHeaderPrefix.js";
import { parsePeRecord, peRvaToFileOffset } from "../domain/binaryTarget.js";
import { readManagedMetadataLayout } from "../dotnet/ManagedMetadataLayout.js";
import { readAssemblyReferenceName } from "../dotnet/ManagedMetadataInventoryRows.js";
@@ -98,13 +98,14 @@ export const inspectDesktopFile = async (
row.facts.push(observation);
};
const prefix = await read(0, Math.min(size, 64));
if (prefix.length >= 8 && prefix.readUInt32LE(0) === IL2CPP_METADATA_MAGIC)
const metadataPrefix = observeIl2cppMetadataHeaderPrefix(prefix);
if (metadataPrefix.kind === "il2cpp")
fact({
kind: "il2cpp-metadata-header",
offset: 0,
value: {
magic: "0xfab11baf",
raw_version: prefix.readUInt32LE(4),
raw_version: metadataPrefix.rawVersion,
},
});
if (prefix.length >= 20 && prefix.toString("latin1", 0, 4) === "GDPC")
+4 -1
View File
@@ -56,7 +56,10 @@ const desktopFactSchema = z.discriminatedUnion("kind", [
),
fact(
"il2cpp-metadata-header",
z.strictObject({ magic: z.literal("0xfab11baf"), raw_version: byteOffset }),
z.strictObject({
magic: z.literal("0xfab11baf"),
raw_version: byteOffset.nullable(),
}),
),
fact(
"godot-pck-header",
+1 -1
View File
@@ -87,7 +87,7 @@ export const projectDesktopApplication = (
candidate(
"unity-il2cpp",
[...metadata, ...il2cpp],
"IL2CPP metadata headers and conventionally named native libraries coexist; their build correspondence is unverified.",
"IL2CPP metadata magic and conventionally named native libraries coexist; metadata validity and build correspondence are unverified.",
"inferred",
);
for (const file of il2cpp)
@@ -0,0 +1,59 @@
import { IL2CPP_METADATA_MAGIC } from "./il2cppMetadata.js";
/** Parsed identity facts available before the complete IL2CPP header exists. */
export type Il2cppMetadataHeaderPrefix =
| {
readonly kind: "unavailable-magic";
readonly magic: null;
readonly rawVersion: null;
readonly version: null;
}
| {
readonly kind: "other-magic";
readonly magic: number;
readonly rawVersion: null;
readonly version: null;
}
| {
readonly kind: "il2cpp";
readonly magic: typeof IL2CPP_METADATA_MAGIC;
/** Unsigned bytes as stored; null means fewer than eight prefix bytes. */
readonly rawVersion: number | null;
/** The decoder's signed Int32 interpretation; null means unavailable. */
readonly version: number | null;
};
/** Parse the shared magic/version prefix once, retaining incomplete identity explicitly. */
export const observeIl2cppMetadataHeaderPrefix = (
bytes: Uint8Array,
): Il2cppMetadataHeaderPrefix => {
if (bytes.byteLength < 4)
return {
kind: "unavailable-magic",
magic: null,
rawVersion: null,
version: null,
};
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
const magic = view.getUint32(0, true);
if (magic !== IL2CPP_METADATA_MAGIC)
return {
kind: "other-magic",
magic,
rawVersion: null,
version: null,
};
if (bytes.byteLength < 8)
return {
kind: "il2cpp",
magic: IL2CPP_METADATA_MAGIC,
rawVersion: null,
version: null,
};
return {
kind: "il2cpp",
magic: IL2CPP_METADATA_MAGIC,
rawVersion: view.getUint32(4, true),
version: view.getInt32(4, true),
};
};
+9 -4
View File
@@ -4,13 +4,13 @@ import {
Il2cppMetadataFormatFailure,
} from "./Il2cppMetadataFormat.js";
import {
IL2CPP_METADATA_MAGIC,
IL2CPP_METADATA_VERSIONS,
il2cppMetadataSectionNames,
type Il2cppMetadata,
type Il2cppMetadataSection,
type IL2cppMetadataSectionName,
} from "../domain/il2cpp/il2cppMetadata.js";
import { observeIl2cppMetadataHeaderPrefix } from "../domain/il2cpp/il2cppMetadataHeaderPrefix.js";
import {
readIl2cppMembers,
readIl2cppMemberTables,
@@ -129,13 +129,18 @@ const isIndexWidth = (value: number): value is IndexWidth =>
value === 1 || value === 2 || value === 4;
const readHeader = (bytes: Buffer) => {
const magic = bytes.length < 4 ? null : bytes.readUInt32LE(0);
if (bytes.length < 8 || magic !== IL2CPP_METADATA_MAGIC)
const prefix = observeIl2cppMetadataHeaderPrefix(bytes);
if (prefix.kind !== "il2cpp")
throw new Il2cppMetadataFormatFailure(
"unrecognized-magic",
"the file does not start with the IL2CPP global-metadata magic 0xFAB11BAF; encrypted or non-metadata inputs are not decoded",
);
const version = bytes.readInt32LE(4);
if (prefix.version === null)
throw new Il2cppMetadataFormatFailure(
"truncated-header",
`the file has ${bytes.length} bytes, fewer than the 8-byte magic/version prefix; the metadata version is unknown`,
);
const { magic, version } = prefix;
if (!isSupportedVersion(version))
throw new Il2cppMetadataFormatFailure(
"unsupported-version",