mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fc2dddc1d9
Recognize baseline-dependent #JTD metadata at the shared layout owner before table sizing and decoding. Report unsupported partial metadata across all inspection workflows, preserve admitted PE/CLI and metadata header facts, and keep member identities and inventories unknown without the baseline. A generated PE carrier reproduced complete coverage and a wrong standalone MethodDef token before the fix. Producer and actual CLI/MCP checks now cover all three inspections, normal metadata, retained comparison after source deletion, exact caller selection, source digests, unchanged bytes, and known header facts. Released .NET writer/reader sources establish framing applicability; natural PE occurrence and real CLR/Edit-and-Continue execution were not verified.
79 lines
3.2 KiB
TypeScript
79 lines
3.2 KiB
TypeScript
import { buildManagedPeFixture } from "../../src/dotnet/ManagedPe.fixture.js";
|
|
import { readManagedPeLayout } from "../../src/dotnet/ManagedPeReader.js";
|
|
|
|
const align4 = (size: number): number => Math.ceil(size / 4) * 4;
|
|
|
|
/**
|
|
* Authored minimal EnC metadata carried by an ordinary PE fixture shell.
|
|
* Matches runtime v9.0.0 MetadataBuilder/MetadataSizes: #- and empty #JTD,
|
|
* wide references despite small local tables, Module and EncMap rows.
|
|
* MethodDef physical row 1 maps to baseline token 0x06000002. This does not
|
|
* establish CLR loadability or execute an Edit-and-Continue operation.
|
|
*/
|
|
export const managedMetadataDelta = () => {
|
|
const bytes = buildManagedPeFixture({ targetFramework: null });
|
|
const pe = readManagedPeLayout(bytes);
|
|
if (pe.cli === null) throw new Error("Fixture omitted CLI metadata");
|
|
const rootOffset = pe.rvaToOffset(
|
|
pe.cli.metadata.rva,
|
|
pe.cli.metadata.size,
|
|
"fixture metadata",
|
|
);
|
|
const strings = Buffer.from("\0Delta.dll\0Updated\0");
|
|
const tables = Buffer.alloc(align4(24 + 3 * 4 + 18 + 20 + 2 * 4 + 1));
|
|
tables[4] = 2;
|
|
tables[6] = 7;
|
|
tables[7] = 1;
|
|
tables.writeBigUInt64LE(1n | (1n << 6n) | (1n << 31n), 8);
|
|
tables.writeUInt32LE(1, 24); // Module
|
|
tables.writeUInt32LE(1, 28); // MethodDef
|
|
tables.writeUInt32LE(2, 32); // EncMap
|
|
tables.writeUInt16LE(1, 36); // Module.Generation
|
|
tables.writeUInt32LE(1, 38); // Module.Name
|
|
tables.writeUInt32LE(1, 42); // MVID
|
|
tables.writeUInt32LE(2, 46); // EncId
|
|
tables.writeUInt32LE(3, 50); // EncBaseId
|
|
tables.writeUInt16LE(0x0086, 54 + 6); // MethodDef.Flags
|
|
tables.writeUInt32LE(strings.indexOf("Updated"), 54 + 8);
|
|
tables.writeUInt32LE(1, 54 + 12); // Signature
|
|
tables.writeUInt32LE(1, 54 + 16); // ParamList, four bytes even with no Param rows
|
|
tables.writeUInt32LE(0x0000_0001, 74); // EncMap: Module
|
|
tables.writeUInt32LE(0x0600_0002, 78); // EncMap: MethodDef in baseline coordinates
|
|
const streams = [
|
|
{ name: "#-", data: tables },
|
|
{ name: "#Strings", data: strings },
|
|
{ name: "#US", data: Buffer.from([0]) },
|
|
{ name: "#GUID", data: Buffer.alloc(48, 0x41) },
|
|
{ name: "#Blob", data: Buffer.from([0, 3, 0, 0, 1]) },
|
|
{ name: "#JTD", data: Buffer.alloc(0) },
|
|
];
|
|
const headerSize =
|
|
32 +
|
|
streams.reduce((sum, { name }) => sum + 8 + align4(name.length + 1), 0);
|
|
const metadata = Buffer.alloc(
|
|
headerSize +
|
|
streams.reduce((sum, { data }) => sum + align4(data.length), 0),
|
|
);
|
|
metadata.writeUInt32LE(0x424a_5342);
|
|
metadata.writeUInt16LE(1, 4);
|
|
metadata.writeUInt16LE(1, 6);
|
|
metadata.writeUInt32LE(12, 12);
|
|
metadata.write("v4.0.30319", 16);
|
|
metadata.writeUInt16LE(streams.length, 30);
|
|
let header = 32;
|
|
let content = headerSize;
|
|
let markerOffset = 0;
|
|
for (const { name, data } of streams) {
|
|
metadata.writeUInt32LE(content, header);
|
|
metadata.writeUInt32LE(align4(data.length), header + 4);
|
|
metadata.write(name, header + 8);
|
|
metadata.set(data, content);
|
|
if (name === "#JTD") markerOffset = rootOffset + header;
|
|
header += 8 + align4(name.length + 1);
|
|
content += align4(data.length);
|
|
}
|
|
bytes.set(metadata, rootOffset);
|
|
bytes.writeUInt32LE(metadata.length, pe.cli.headerOffset + 12);
|
|
return { bytes, markerOffset };
|
|
};
|