mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
fix(elf): preserve virtual relocation identity (#9990)
* fix(elf): keep compressed storage out of decoded metadata facts * fix(elf): preserve virtual relocation identity Keep linked initializer backing and relocation values in their owning virtual or ET_REL section coordinates. Replace the IL2CPP physical-copy materializer with compact virtual value facts while preserving file-backed capacity. Reuse initializer repairs and original regressions from ShuaixinHuang PRs repair retains independent alias values instead of blanket alias refusal. Co-authored-by: 帅鑫 Huang <1836656514@qq.com> * fix(elf): admit compressed string tables the profile does not read SHF_COMPRESSED string tables are rejected only when they name sections or symbols. An unreferenced string table is not decoded, so it no longer makes an otherwise analyzable ELF unsupported. * fix(il2cpp): admit virtual pointer workspace before retention * fix(elf): reject null relocation target sections * fix(il2cpp): avoid decoding unrelated Mach-O words * fix(il2cpp): preserve uncertainty in candidate scans * fix(il2cpp): bound uncertain array candidates * fix(il2cpp): preserve unknown registration candidates * fix(il2cpp): classify type kinds before bound data * fix(il2cpp): bind candidate counts to matching names --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: 帅鑫 Huang <1836656514@qq.com>
This commit is contained in:
18 files changed
+1807
-419
No files matched your search
@@ -5,6 +5,7 @@ import {
|
||||
import { binaryMetadataArchitecture } from "../domain/binaryMetadataArchitecture.js";
|
||||
import {
|
||||
BinaryFormatFailure,
|
||||
BinaryMappingFailure,
|
||||
BinaryResourceFailure,
|
||||
createFileMappingIndex,
|
||||
mappedFileOffset,
|
||||
@@ -21,8 +22,15 @@ import {
|
||||
parseMachoLayout,
|
||||
UnsupportedMachoMetadataFormatError,
|
||||
} from "../native/AppleMachoSelection.js";
|
||||
import { applyElfRelativeRelocationsSteps } from "./ElfRelocations.js";
|
||||
import { Il2cppBinaryFormatFailure } from "./Il2cppBinaryFormat.js";
|
||||
import {
|
||||
readElfPointerValuesSteps,
|
||||
ElfPointerRelocationFailure,
|
||||
type ElfVirtualPointerWrites,
|
||||
} from "../native/metadata/ElfPointerRelocations.js";
|
||||
import {
|
||||
Il2cppBinaryFormatFailure,
|
||||
IL2CPP_BINARY_BYTES,
|
||||
} from "./Il2cppBinaryFormat.js";
|
||||
const MACHO_CPU = new Map([
|
||||
[0x01000007, "amd64"],
|
||||
[0x0100000c, "arm64"],
|
||||
@@ -83,8 +91,8 @@ export interface NativeImage {
|
||||
/** One image's immutable load mappings, shared by stored and loader-aware reads. */
|
||||
readonly fileMappings: FileMappingIndex;
|
||||
readonly imageBase: bigint;
|
||||
readonly unresolvedPointerSlots: ReadonlyMap<bigint, number>;
|
||||
readonly zeroFillPointers: ReadonlyMap<bigint, bigint>;
|
||||
/** ELF loader writes retain virtual identity; source bytes stay unchanged. */
|
||||
readonly elfPointerOverlay?: ElfVirtualPointerWrites;
|
||||
/** Mach-O loader fixups shared by every native pointer consumer. */
|
||||
readonly machoPointerFixups?: PointerFixups;
|
||||
}
|
||||
@@ -93,7 +101,7 @@ export function* openImageSteps(
|
||||
bytes: Buffer,
|
||||
architecture: string | undefined,
|
||||
): Generator<void, NativeImage> {
|
||||
let image = selectImage(bytes, architecture);
|
||||
const image = selectImage(bytes, architecture);
|
||||
let container: BinaryContainer;
|
||||
try {
|
||||
container = readBinaryContainer(image);
|
||||
@@ -117,27 +125,28 @@ export function* openImageSteps(
|
||||
"unsupported-container",
|
||||
`only 64-bit little-endian images are supported, not ${container.bits}-bit ${container.byte_order}-endian`,
|
||||
);
|
||||
let relocated:
|
||||
| {
|
||||
bytes: Buffer;
|
||||
unresolved: ReadonlyMap<bigint, number>;
|
||||
zeroFillPointers: ReadonlyMap<bigint, bigint>;
|
||||
}
|
||||
| undefined;
|
||||
let elfPointerOverlay: ElfVirtualPointerWrites | undefined;
|
||||
try {
|
||||
if (container.format === "elf")
|
||||
relocated = yield* applyElfRelativeRelocationsSteps(
|
||||
elfPointerOverlay = yield* readElfPointerValuesSteps(
|
||||
image,
|
||||
container.elf,
|
||||
container.mappings,
|
||||
container.zero_fills,
|
||||
{
|
||||
bits: 64,
|
||||
little: true,
|
||||
machine: container.elf.machine,
|
||||
dynamicSegments: container.elf.dynamicSegments,
|
||||
mappings: container.mappings,
|
||||
zeroFills: container.zero_fills,
|
||||
},
|
||||
IL2CPP_BINARY_BYTES,
|
||||
);
|
||||
} catch (cause) {
|
||||
if (cause instanceof ElfPointerRelocationFailure)
|
||||
throw new Il2cppBinaryFormatFailure(cause.reason, cause.message);
|
||||
if (cause instanceof BinaryFormatFailure)
|
||||
throw new Il2cppBinaryFormatFailure("malformed-container", cause.message);
|
||||
throw cause;
|
||||
}
|
||||
if (relocated !== undefined) image = relocated.bytes;
|
||||
if (container.format === "macho" && container.macho_chained_fixups === true)
|
||||
throw new Il2cppBinaryFormatFailure(
|
||||
"unsupported-pointer-encoding",
|
||||
@@ -195,8 +204,7 @@ export function* openImageSteps(
|
||||
container.zero_fills,
|
||||
),
|
||||
imageBase,
|
||||
unresolvedPointerSlots: relocated?.unresolved ?? new Map<bigint, number>(),
|
||||
zeroFillPointers: relocated?.zeroFillPointers ?? new Map<bigint, bigint>(),
|
||||
...(elfPointerOverlay === undefined ? {} : { elfPointerOverlay }),
|
||||
...(machoPointerFixups === undefined ? {} : { machoPointerFixups }),
|
||||
};
|
||||
}
|
||||
@@ -217,14 +225,13 @@ export const readUInt32 = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): number | "unknown" | null => {
|
||||
if (
|
||||
hasUnresolvedElfBytes(image, address, 4) ||
|
||||
image.machoPointerFixups?.hasUnresolvedLegacyBytes(address, 4) === true
|
||||
)
|
||||
if (image.machoPointerFixups?.hasUnresolvedLegacyBytes(address, 4) === true)
|
||||
return "unknown";
|
||||
const virtual = image.zeroFillPointers.get(address);
|
||||
if (virtual !== undefined) return Number(virtual & 0xffffffffn);
|
||||
try {
|
||||
if (image.elfPointerOverlay?.hasWrites(address, 4) === true) {
|
||||
const value = image.elfPointerOverlay.unsignedAt(address, 4);
|
||||
return value === undefined ? "unknown" : Number(value);
|
||||
}
|
||||
return image.bytes.readUInt32LE(image.fileMappings.offset(address, 4));
|
||||
} catch (cause) {
|
||||
if (cause instanceof BinaryFormatFailure) return null;
|
||||
@@ -314,34 +321,20 @@ export const isExecutable = (image: NativeImage, address: bigint): boolean => {
|
||||
}
|
||||
};
|
||||
|
||||
const hasUnresolvedElfBytes = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
size = 8,
|
||||
): boolean => {
|
||||
if (image.unresolvedPointerSlots.size === 0) return false;
|
||||
for (let delta = -7; delta < size; delta++) {
|
||||
const width = image.unresolvedPointerSlots.get(address + BigInt(delta));
|
||||
if (width !== undefined && delta + width > 0) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const readSlot = (
|
||||
image: NativeImage,
|
||||
address: bigint,
|
||||
): bigint | "unknown" | null => {
|
||||
if (hasUnresolvedElfBytes(image, address)) return "unknown";
|
||||
try {
|
||||
const virtual = image.zeroFillPointers.get(address);
|
||||
let raw: bigint | null;
|
||||
if (virtual !== undefined) raw = virtual;
|
||||
else {
|
||||
// A successful indexed read already excludes zero-fill aliases. Only a
|
||||
// non-file-backed slot needs the zero-fill ownership walk.
|
||||
raw = readStoredWord(image, address);
|
||||
if (raw === null && isZeroFilled(image, address, 8)) raw = 0n;
|
||||
if (image.elfPointerOverlay !== undefined) {
|
||||
const value = image.elfPointerOverlay.unsignedAt(address, 8);
|
||||
if (value !== undefined) return value;
|
||||
if (image.elfPointerOverlay.hasWrites(address, 8)) return "unknown";
|
||||
}
|
||||
// A successful indexed read already excludes zero-fill aliases. Only a
|
||||
// non-file-backed slot needs the zero-fill ownership walk.
|
||||
let raw = readStoredWord(image, address);
|
||||
if (raw === null && isZeroFilled(image, address, 8)) raw = 0n;
|
||||
if (raw === null) return null;
|
||||
if (image.machoPointerFixups !== undefined) {
|
||||
const resolution = image.machoPointerFixups.decode(address, raw);
|
||||
@@ -356,6 +349,7 @@ export const readSlot = (
|
||||
}
|
||||
return raw;
|
||||
} catch (cause) {
|
||||
if (cause instanceof BinaryMappingFailure) return null;
|
||||
if (cause instanceof BinaryFormatFailure)
|
||||
throw new Il2cppBinaryFormatFailure("malformed-container", cause.message);
|
||||
throw cause;
|
||||
|
||||
Reference in new issue
Block a user