mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 09:52:27 +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
@@ -32,6 +32,7 @@ const withLoadRanges = (
|
||||
readonly offset: number;
|
||||
readonly size: number;
|
||||
readonly zeroFill?: number;
|
||||
readonly address?: bigint;
|
||||
}[],
|
||||
): Buffer => {
|
||||
const headers: Buffer[] = [];
|
||||
@@ -47,7 +48,7 @@ const withLoadRanges = (
|
||||
header.writeUInt32LE(1);
|
||||
header.writeUInt32LE(7, 4);
|
||||
header.writeBigUInt64LE(BigInt(range.offset), 8);
|
||||
const address = FIXTURE_BINARY_BASE + BigInt(range.offset);
|
||||
const address = range.address ?? FIXTURE_BINARY_BASE + BigInt(range.offset);
|
||||
header.writeBigUInt64LE(address, 16);
|
||||
header.writeBigUInt64LE(address, 24);
|
||||
header.writeBigUInt64LE(BigInt(range.size), 32);
|
||||
@@ -61,6 +62,74 @@ const withLoadRanges = (
|
||||
return result;
|
||||
};
|
||||
|
||||
it.each([183, 62])(
|
||||
"keeps file-backed relocation writes on their virtual owner despite physical aliases (machine %s)",
|
||||
(machine) => {
|
||||
const original = createElfFixture(createIl2cppBinaryFixture(), { machine });
|
||||
// RELA restores the zero stored at 0x308, but must not change the same
|
||||
// file bytes independently mapped at base + 0x2000. A single file copy
|
||||
// cannot represent those two different loader values.
|
||||
expect(original.readBigUInt64LE(0x308)).toBe(0n);
|
||||
for (const [offset, size] of [
|
||||
[0x308, 8],
|
||||
[0x307, 2],
|
||||
[0x30f, 2],
|
||||
] as const) {
|
||||
const bytes = withLoadRanges(original, [
|
||||
{ offset: 0, size: original.length },
|
||||
{
|
||||
offset,
|
||||
size,
|
||||
address: FIXTURE_BINARY_BASE + 0x2000n,
|
||||
},
|
||||
]);
|
||||
const snapshot = Buffer.from(bytes);
|
||||
const image = open(bytes);
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x308n)).toBe(
|
||||
FIXTURE_BINARY_BASE + 0x200n,
|
||||
);
|
||||
if (offset === 0x308 && size === 8)
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x2000n)).toBe(0n);
|
||||
expect(Buffer.compare(bytes, snapshot)).toBe(0);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.each([183, 62])(
|
||||
"keeps unresolved symbol writes from changing another virtual mapping (machine %s)",
|
||||
(machine) => {
|
||||
const source = createIl2cppBinaryFixture();
|
||||
source.writeBigUInt64LE(0x1234n, 0x700);
|
||||
const original = createElfFixture(source, {
|
||||
machine,
|
||||
unresolvedRelocations: [
|
||||
{ offset: 0x700, kind: machine === 183 ? 257 : 1 },
|
||||
],
|
||||
});
|
||||
const bytes = withLoadRanges(original, [
|
||||
{ offset: 0, size: original.length },
|
||||
{ offset: 0x700, size: 8, address: FIXTURE_BINARY_BASE + 0x2000n },
|
||||
]);
|
||||
const image = open(bytes);
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x700n)).toBe("unknown");
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x2000n)).toBe(0x1234n);
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps consistent aliases and distinct virtual mappings of untouched file bytes", () => {
|
||||
const original = createElfFixture(createIl2cppBinaryFixture());
|
||||
for (const alias of [
|
||||
{ offset: 0x300, size: 0x28 },
|
||||
{ offset: 0x200, size: 0x20, address: FIXTURE_BINARY_BASE + 0x2000n },
|
||||
]) {
|
||||
const bytes = withLoadRanges(original, [
|
||||
{ offset: 0, size: original.length },
|
||||
alias,
|
||||
]);
|
||||
expect(link(bytes)).toEqual(link(original));
|
||||
}
|
||||
});
|
||||
|
||||
it("reuses admitted mappings for repeated file-backed loader reads", () => {
|
||||
const original = createIl2cppBinaryFixture();
|
||||
const image = open(createElfFixture(original, { zeroFilledTable: true }));
|
||||
@@ -223,3 +292,78 @@ it("keeps mapped-span admission consistent with pointer reads across zero-fill a
|
||||
expect(isMapped(image, FIXTURE_BINARY_BASE + 0xc00n, 4)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("reads both halves of a relocated word without changing a physical alias's UInt32 fields", () => {
|
||||
const original = createElfFixture(createIl2cppBinaryFixture());
|
||||
const bytes = withLoadRanges(original, [
|
||||
{ offset: 0, size: original.length },
|
||||
{ offset: 0x304, size: 16, address: FIXTURE_BINARY_BASE + 0x2000n },
|
||||
]);
|
||||
const image = open(bytes);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x308n)).toBe(0x200);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x30cn)).toBe(1);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x2004n)).toBe(0);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x2008n)).toBe(0);
|
||||
expect(image.bytes.equals(bytes)).toBe(true);
|
||||
});
|
||||
|
||||
it.each([183, 62])(
|
||||
"retains independent relocated values for two virtual aliases (machine %s)",
|
||||
(machine) => {
|
||||
const original = createElfFixture(createIl2cppBinaryFixture(), { machine });
|
||||
// Redirect a separate existing RELA record to the alias, retaining the write
|
||||
// to the original 0x308 slot and the same immutable source word.
|
||||
const dynamic = Number(original.readBigUInt64LE(128));
|
||||
const count = Number(original.readBigUInt64LE(dynamic + 24)) / 24;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const at = 0x1000 + i * 24;
|
||||
if (original.readBigUInt64LE(at) === FIXTURE_BINARY_BASE + 0x308n)
|
||||
continue;
|
||||
original.writeBigUInt64LE(FIXTURE_BINARY_BASE + 0x2000n, at);
|
||||
original.writeBigUInt64LE(FIXTURE_BINARY_BASE + 0x333n, at + 16);
|
||||
break;
|
||||
}
|
||||
const bytes = withLoadRanges(original, [
|
||||
{ offset: 0, size: original.length },
|
||||
{ offset: 0x308, size: 8, address: FIXTURE_BINARY_BASE + 0x2000n },
|
||||
]);
|
||||
const image = open(bytes);
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x308n)).toBe(
|
||||
FIXTURE_BINARY_BASE + 0x200n,
|
||||
);
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x2000n)).toBe(
|
||||
FIXTURE_BINARY_BASE + 0x333n,
|
||||
);
|
||||
expect(image.bytes.equals(bytes)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([183, 62])(
|
||||
"keeps an untouched UInt32 half known after a same-start narrow unknown write (machine %s)",
|
||||
(machine) => {
|
||||
const bytes = createElfFixture(createIl2cppBinaryFixture(), {
|
||||
machine,
|
||||
unresolvedRelocations: [
|
||||
{ offset: 0x308, kind: machine === 183 ? 258 : 10 },
|
||||
],
|
||||
});
|
||||
const image = open(bytes);
|
||||
expect(readSlot(image, FIXTURE_BINARY_BASE + 0x308n)).toBe("unknown");
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x308n)).toBe("unknown");
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x30cn)).toBe(1);
|
||||
},
|
||||
);
|
||||
|
||||
it("composes a UInt32 crossing a known relocation edge with unchanged source bytes", () => {
|
||||
const source = createIl2cppBinaryFixture();
|
||||
source.writeUInt32LE(0xaabbccdd, 0x310);
|
||||
const bytes = createElfFixture(source);
|
||||
const image = open(bytes);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x306n)).toBe(
|
||||
bytes.readUInt16LE(0x306) + 0x02000000,
|
||||
);
|
||||
// The relocated word at 0x308 is 0x0000000100000200. Its final two
|
||||
// bytes are followed by the original dd cc bytes at 0x310.
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x30en)).toBe(0xccdd0000);
|
||||
expect(readUInt32(image, FIXTURE_BINARY_BASE + 0x30cn)).toBe(1);
|
||||
});
|
||||
Reference in new issue
Block a user