mirror of
https://github.com/morluto/rea
synced 2026-10-27 06:33:32 -04:00
fix(il2cpp): preserve loader ownership and ABI field boundaries
Resolve pointer and scalar facts through their shared loader-aware owners before registration search or type rendering. Preserve unresolved names and attributes, read count fields at their declared width, and admit declared zero-fill registration tails without accepting unmapped bytes. Cover relocation overlap and adjacency, loader-bound fields, ABI padding, nullable names, and CLI/MCP behavior; document format and verification limits. Fixes #6881 Fixes #6873 Fixes #6871
This commit is contained in:
@@ -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 shared by every native pointer consumer. */
|
||||
readonly machoPointerFixups?: PointerFixups;
|
||||
}
|
||||
|
||||
@@ -191,13 +191,8 @@ export function* openImageSteps(
|
||||
};
|
||||
}
|
||||
|
||||
export const readPointer = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): bigint | null => {
|
||||
if (hasUnresolvedPointer(image, address)) return null;
|
||||
const virtual = image.zeroFillPointers.get(address);
|
||||
if (virtual !== undefined) return virtual;
|
||||
/** Stored bytes only; loader interpretation belongs to readSlot. */
|
||||
const readStoredWord = (image: NativeImage, address: bigint): bigint | null => {
|
||||
try {
|
||||
const offset = mappedFileOffset(
|
||||
image.container.mappings,
|
||||
@@ -216,8 +211,12 @@ export const readPointer = (
|
||||
export const readUInt32 = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): number | null => {
|
||||
if (hasUnresolvedPointer(image, address, 4)) return null;
|
||||
): number | "unknown" | null => {
|
||||
if (
|
||||
hasUnresolvedElfBytes(image, address, 4) ||
|
||||
image.machoPointerFixups?.hasUnresolvedLegacyBytes(address, 4) === true
|
||||
)
|
||||
return "unknown";
|
||||
const virtual = image.zeroFillPointers.get(address);
|
||||
if (virtual !== undefined) return Number(virtual & 0xffffffffn);
|
||||
try {
|
||||
@@ -329,7 +328,7 @@ export const isExecutable = (image: NativeImage, address: bigint): boolean => {
|
||||
}
|
||||
};
|
||||
|
||||
const hasUnresolvedPointer = (
|
||||
const hasUnresolvedElfBytes = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
size = 8,
|
||||
@@ -346,13 +345,13 @@ export const readSlot = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): bigint | "unknown" | null => {
|
||||
if (hasUnresolvedPointer(image, address)) return "unknown";
|
||||
if (hasUnresolvedElfBytes(image, address)) return "unknown";
|
||||
try {
|
||||
const virtual = image.zeroFillPointers.get(address);
|
||||
let raw: bigint | null;
|
||||
if (virtual !== undefined) raw = virtual;
|
||||
else if (isZeroFilled(image, address, 8)) raw = 0n;
|
||||
else raw = readPointer(image, address);
|
||||
else raw = readStoredWord(image, address);
|
||||
if (raw === null) return null;
|
||||
if (image.machoPointerFixups !== undefined) {
|
||||
const resolution = image.machoPointerFixups.decode(address, raw);
|
||||
@@ -372,3 +371,12 @@ export const readSlot = (
|
||||
throw cause;
|
||||
}
|
||||
};
|
||||
|
||||
/** Require an observed resolved pointer; unknown and unmapped slots stay null. */
|
||||
export const readPointer = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): bigint | null => {
|
||||
const value = readSlot(image, address);
|
||||
return typeof value === "bigint" ? value : null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user