fix(il2cpp): honor loader pointers and registration field layout

This commit is contained in:
morluto committed 2026-10-24 02:29:08 +08:00
1 parent db923eba44
commit 26031bcd26
3 files changed
+64 -14

No files matched your search

+12 -6
View File
@@ -76,7 +76,7 @@ export interface NativeImage {
readonly imageBase: bigint;
readonly unresolvedPointerSlots: ReadonlyMap<bigint, number>;
readonly zeroFillPointers: ReadonlyMap<bigint, bigint>;
/** Mach-O loader fixups, used when interpreting method pointer slots. */
/** Mach-O loader fixups, owned by every pointer interpretation. */
readonly machoPointerFixups?: PointerFixups;
}
@@ -191,10 +191,7 @@ export function* openImageSteps(
};
}
export const readPointer = (
image: NativeImage,
address: bigint,
): bigint | null => {
const readRawPointer = (image: NativeImage, address: bigint): bigint | null => {
if (hasUnresolvedPointer(image, address)) return null;
const virtual = image.zeroFillPointers.get(address);
if (virtual !== undefined) return virtual;
@@ -347,7 +344,7 @@ export const readSlot = (
let raw: bigint | null;
if (virtual !== undefined) raw = virtual;
else if (isZeroFilled(image, address, 8)) raw = 0n;
else raw = readPointer(image, address);
else raw = readRawPointer(image, address);
if (raw === null) return null;
if (image.machoPointerFixups !== undefined) {
const resolution = image.machoPointerFixups.decode(address, raw);
@@ -367,3 +364,12 @@ export const readSlot = (
throw cause;
}
};
/** Resolve a pointer through the same loader interpretation as method slots. */
export const readPointer = (
image: NativeImage,
address: bigint,
): bigint | null => {
const slot = readSlot(image, address);
return typeof slot === "bigint" ? slot : null;
};
+15 -8
View File
@@ -207,7 +207,7 @@ export function* findCodeRegistration(
modules: readonly Il2cppCodeGenModule[],
): Generator<void, { readonly field: bigint | null; readonly array: bigint }> {
const expected = new Set(modules.map((module) => module.address));
const total = BigInt(modules.length);
const total = modules.length;
const matches: { field: bigint; array: bigint }[] = [];
const matchedFields = new Set<bigint>();
for (const mapping of image.container.mappings) {
@@ -215,8 +215,9 @@ export function* findCodeRegistration(
for (let at = start; at + 16 <= mapping.size; at += 8) {
if ((at & 0xffff) < 8) yield;
const offset = mapping.offset + at;
if (image.bytes.readBigUInt64LE(offset) !== total) continue;
const array = image.bytes.readBigUInt64LE(offset + 8);
if (image.bytes.readUInt32LE(offset) !== total) continue;
const array = readPointer(image, mapping.address + BigInt(at + 8));
if (array === null) continue;
if (!isMapped(image, array, modules.length * 8)) continue;
const seen = new Set<bigint>();
for (let slot = 0; slot < modules.length; slot++) {
@@ -333,21 +334,27 @@ export function* findMetadataRegistration(
const matches: { field: bigint; count: number; types: bigint }[] = [];
const matchedFields = new Set<bigint>();
const low = (offset: number) => image.bytes.readUInt32LE(offset);
const word = (offset: number) => image.bytes.readBigUInt64LE(offset);
for (const mapping of image.container.mappings) {
const start = Number((8n - (mapping.address % 8n)) % 8n);
for (let at = start; at + 128 <= mapping.size; at += 8) {
for (let at = start; at + 112 <= mapping.size; at += 8) {
if ((at & 0xffff) < 8) yield;
const base = mapping.offset + at;
if (low(base + 80) !== typeDefinitions) continue;
if (low(base + 96) !== typeDefinitions) continue;
const count = low(base + 48);
const types = word(base + 56);
const address = mapping.address + BigInt(at);
if (!hasPointerArrayCoverage(image, address, 16)) continue;
const types = readPointer(image, address + 56n);
const fieldOffsets = readPointer(image, address + 88n);
const typeSizes = readPointer(image, address + 104n);
if (
count === 0 ||
count > 0x7fffffff ||
!isMapped(image, word(base + 88), 8) ||
!isMapped(image, word(base + 104), 8) ||
types === null ||
fieldOffsets === null ||
typeSizes === null ||
!isMapped(image, fieldOffsets, 8) ||
!isMapped(image, typeSizes, 8) ||
!isMapped(image, types, count * 8)
)
continue;