589 lines
18 KiB
TypeScript
589 lines
18 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { dosMz, pe } from "./binaryTarget.fixture.js";
|
|
import { parseExecutableHeader } from "./binaryTarget.js";
|
|
import {
|
|
observeMzWindowsHeader,
|
|
readDosMzDeclarations,
|
|
dosMzDeclaredImageByteLength,
|
|
parseDeclaredMzHeaderEvidence,
|
|
withMzWindowsHeaderSignature,
|
|
parseDosMzHeader,
|
|
parseMzHeaderEvidence,
|
|
} from "./dosMz.js";
|
|
|
|
describe("DOS MZ load-module validation", () => {
|
|
it("separates initialized module and appended overlay bytes", () => {
|
|
const image = dosMz(480);
|
|
const bytes = Buffer.concat([image, Buffer.from("overlay")]);
|
|
expect(parseDosMzHeader(bytes)).toEqual({
|
|
ok: true,
|
|
value: {
|
|
headerBytes: 32,
|
|
imageBytes: 512,
|
|
moduleBytes: 480,
|
|
overlayBytes: 7,
|
|
relocationCount: 0,
|
|
relocationTableOffset: 28,
|
|
relocations: [],
|
|
entrySegment: 0,
|
|
entryOffset: 0,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("accepts relocation records overlapping the Windows new-header field", () => {
|
|
const bytes = Buffer.alloc(224);
|
|
dosMz().copy(bytes, 0, 0, 28);
|
|
bytes.writeUInt16LE(bytes.length, 2);
|
|
bytes.writeUInt16LE(6, 8);
|
|
bytes.writeUInt16LE(2, 6);
|
|
bytes.writeUInt16LE(62, 24);
|
|
bytes.writeUInt16LE(1, 62);
|
|
bytes.writeUInt16LE(8, 66);
|
|
expect(bytes.readUInt32LE(60)).toBe(65536);
|
|
expect(observeMzWindowsHeader(bytes)).toEqual({ state: "absent" });
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz" },
|
|
});
|
|
expect(parseDosMzHeader(bytes)).toMatchObject({
|
|
ok: true,
|
|
value: { headerBytes: 96, relocationCount: 2, moduleBytes: 128 },
|
|
});
|
|
});
|
|
|
|
it("uses the actual file length rather than the bounded prefix length", () => {
|
|
const bytes = dosMz(8192);
|
|
expect(parseDosMzHeader(bytes.subarray(0, 64), bytes.length).ok).toBe(true);
|
|
expect(parseDosMzHeader(bytes.subarray(0, 64))).toMatchObject({
|
|
ok: false,
|
|
error: "truncated DOS MZ load module",
|
|
});
|
|
});
|
|
|
|
it("keeps a partial DOS prefix unknown until the Windows pointer is examined", () => {
|
|
const bytes = dosMz(64);
|
|
|
|
expect(observeMzWindowsHeader(bytes.subarray(0, 32), bytes.length)).toEqual(
|
|
{
|
|
state: "header-needed",
|
|
},
|
|
);
|
|
expect(
|
|
parseExecutableHeader(bytes.subarray(0, 32), "x64", bytes.length),
|
|
).toMatchObject({ ok: false });
|
|
expect(observeMzWindowsHeader(bytes.subarray(0, 32))).toEqual({
|
|
state: "absent",
|
|
});
|
|
});
|
|
|
|
it("parses a tiny known-length DOS module without requiring an impossible pointer", () => {
|
|
const bytes = Buffer.alloc(33);
|
|
bytes.write("MZ", 0, "ascii");
|
|
bytes.writeUInt16LE(bytes.length, 2);
|
|
bytes.writeUInt16LE(1, 4);
|
|
bytes.writeUInt16LE(2, 8);
|
|
bytes.writeUInt16LE(28, 24);
|
|
bytes[32] = 0xc3;
|
|
|
|
expect(observeMzWindowsHeader(bytes.subarray(0, 28), bytes.length)).toEqual(
|
|
{
|
|
state: "absent",
|
|
},
|
|
);
|
|
expect(
|
|
parseExecutableHeader(bytes.subarray(0, 28), "x64", bytes.length),
|
|
).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz", architecture: "x86" },
|
|
});
|
|
});
|
|
|
|
it("preserves PE classification when low relocation records do not overlap e_lfanew", () => {
|
|
const bytes = pe(0x8664);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(1, 6);
|
|
bytes.writeUInt16LE(28, 24);
|
|
expect(observeMzWindowsHeader(bytes)).toEqual({
|
|
state: "declared",
|
|
offset: 64,
|
|
signature: "PE",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "pe", architecture: "x86_64" },
|
|
});
|
|
expect(parseDosMzHeader(bytes).ok).toBe(false);
|
|
});
|
|
|
|
it.each([
|
|
[
|
|
"page count",
|
|
(bytes: Buffer) => bytes.writeUInt16LE(0, 4),
|
|
"invalid DOS MZ page count or final-page size",
|
|
],
|
|
[
|
|
"final-page size",
|
|
(bytes: Buffer) => bytes.writeUInt16LE(512, 2),
|
|
"invalid DOS MZ page count or final-page size",
|
|
],
|
|
[
|
|
"header size",
|
|
(bytes: Buffer) => bytes.writeUInt16LE(1, 8),
|
|
"invalid DOS MZ header size or empty load module",
|
|
],
|
|
[
|
|
"entry point",
|
|
(bytes: Buffer) => bytes.writeUInt16LE(128, 20),
|
|
"DOS MZ entry point lies outside its initialized load module",
|
|
],
|
|
[
|
|
"relocation-table bounds",
|
|
(bytes: Buffer) => {
|
|
bytes.writeUInt16LE(2, 6);
|
|
},
|
|
"DOS MZ relocation table lies outside its header",
|
|
],
|
|
[
|
|
"relocation target",
|
|
(bytes: Buffer) => {
|
|
bytes.writeUInt16LE(1, 6);
|
|
bytes.writeUInt16LE(127, 28);
|
|
},
|
|
"DOS MZ relocation 0 points outside its load module",
|
|
],
|
|
] as const)("rejects invalid %s", (_name, damage, error) => {
|
|
const bytes = dosMz();
|
|
damage(bytes);
|
|
expect(parseDosMzHeader(bytes)).toEqual({ ok: false, error });
|
|
});
|
|
|
|
it("rejects a truncated relocation table even when the file size is known", () => {
|
|
const bytes = dosMz();
|
|
bytes.writeUInt16LE(1, 6);
|
|
expect(parseDosMzHeader(bytes.subarray(0, 30), bytes.length)).toMatchObject(
|
|
{
|
|
ok: false,
|
|
error: "truncated DOS MZ relocation table",
|
|
},
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("MZ Windows header observations", () => {
|
|
it("keeps a confirmed overlapping PE distinct from malformed header offsets", () => {
|
|
const bytes = pe(0x014c, 4);
|
|
expect(observeMzWindowsHeader(bytes)).toEqual({
|
|
state: "declared",
|
|
offset: 4,
|
|
signature: "PE",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toEqual({
|
|
ok: false,
|
|
error:
|
|
"Unsupported overlapping PE header at file offset 4; this reader requires the Windows header outside the 64-byte DOS header",
|
|
});
|
|
});
|
|
|
|
it.each(["NE", "LE", "LX"])(
|
|
"distinguishes unsupported %s from DOS",
|
|
(signature) => {
|
|
const bytes = pe(0x8664);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(64, 24);
|
|
bytes.write(signature, 64, "ascii");
|
|
expect(parseExecutableHeader(bytes, "x64")).toEqual({
|
|
ok: false,
|
|
error: `unsupported ${signature} executable in MZ image`,
|
|
});
|
|
},
|
|
);
|
|
|
|
it("keeps a short-header nonzero module value as DOS without a signature", () => {
|
|
const bytes = dosMz(64);
|
|
bytes.writeUInt32LE(bytes.length, 60);
|
|
|
|
expect(observeMzWindowsHeader(bytes)).toEqual({ state: "absent" });
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz", architecture: "x86" },
|
|
});
|
|
});
|
|
|
|
it.each(["PEZZ", "NE", "LE", "LX", "PE"])(
|
|
"keeps a non-Windows %s signature candidate as DOS",
|
|
(signature) => {
|
|
const bytes = dosMz(64);
|
|
const offset = 32;
|
|
bytes.writeUInt32LE(offset, 60);
|
|
const candidate = Buffer.from(
|
|
[...Buffer.from(signature)].map((byte) =>
|
|
signature === "PEZZ" ? byte : byte | 0x80,
|
|
),
|
|
);
|
|
bytes.set(candidate, offset);
|
|
|
|
expect(observeMzWindowsHeader(bytes)).toEqual({ state: "absent" });
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz", architecture: "x86" },
|
|
});
|
|
},
|
|
);
|
|
|
|
it("accepts a short-header candidate only when it points at a Windows signature", () => {
|
|
const stub = dosMz(64);
|
|
const offset = stub.length;
|
|
stub.writeUInt32LE(offset, 60);
|
|
const record = pe(0x8664).subarray(64);
|
|
const bytes = Buffer.concat([stub, record]);
|
|
|
|
expect(observeMzWindowsHeader(bytes)).toMatchObject({
|
|
state: "declared",
|
|
offset,
|
|
signature: "PE",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "pe", architecture: "x86_64" },
|
|
});
|
|
});
|
|
|
|
it.each(["NE", "LE", "LX"])(
|
|
"recognizes short-header %s signatures as Windows declarations",
|
|
(signature) => {
|
|
const stub = dosMz(64);
|
|
const offset = stub.length;
|
|
stub.writeUInt32LE(offset, 60);
|
|
const bytes = Buffer.concat([stub, Buffer.alloc(24)]);
|
|
bytes.write(signature, offset, "ascii");
|
|
|
|
expect(observeMzWindowsHeader(bytes)).toMatchObject({
|
|
state: "declared",
|
|
offset,
|
|
signature,
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toEqual({
|
|
ok: false,
|
|
error: `unsupported ${signature} executable in MZ image`,
|
|
});
|
|
},
|
|
);
|
|
|
|
it("requests the signature when a short-header candidate is outside its prefix", () => {
|
|
const offset = 8192;
|
|
const bytes = dosMz(64);
|
|
bytes.writeUInt32LE(offset, 60);
|
|
const prefix = Buffer.alloc(4096);
|
|
bytes.copy(prefix);
|
|
|
|
expect(observeMzWindowsHeader(prefix, offset + 512)).toEqual({
|
|
state: "signature-needed",
|
|
offset,
|
|
});
|
|
expect(
|
|
observeMzWindowsHeader(prefix, offset + 512, {
|
|
offset,
|
|
bytes: Buffer.from("PE\0\0", "binary"),
|
|
}),
|
|
).toEqual({ state: "declared", offset, signature: "PE" });
|
|
});
|
|
});
|
|
|
|
describe("MZ header padding observations", () => {
|
|
it("treats a complete header after the relocation table as DOS padding", () => {
|
|
const bytes = Buffer.alloc(128);
|
|
bytes.write("MZ", 0, "ascii");
|
|
bytes.writeUInt16LE(128, 2);
|
|
bytes.writeUInt16LE(1, 4);
|
|
bytes.writeUInt16LE(2, 6);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(28, 24);
|
|
bytes.writeUInt32LE(0, 28);
|
|
bytes.writeUInt32LE(0, 32);
|
|
bytes.write("ABCD", 60, "ascii");
|
|
|
|
const evidence = parseMzHeaderEvidence(bytes);
|
|
expect(evidence.dos).toMatchObject({
|
|
ok: true,
|
|
value: {
|
|
headerBytes: 64,
|
|
imageBytes: 128,
|
|
moduleBytes: 64,
|
|
relocationCount: 2,
|
|
relocationTableOffset: 28,
|
|
},
|
|
});
|
|
expect(evidence.windowsHeader).toEqual({ state: "absent" });
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz", architecture: "x86" },
|
|
});
|
|
|
|
bytes.writeUInt32LE(0xfffffff0, 60);
|
|
expect(parseMzHeaderEvidence(bytes).windowsHeader).toEqual({
|
|
state: "absent",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({
|
|
ok: true,
|
|
value: { format: "dos-mz", architecture: "x86" },
|
|
});
|
|
});
|
|
|
|
it("requests an unread signature before treating padding as DOS data", () => {
|
|
const offset = 8192;
|
|
const bytes = Buffer.alloc(offset + 512);
|
|
bytes.write("MZ", 0, "ascii");
|
|
bytes.writeUInt16LE(128, 2);
|
|
bytes.writeUInt16LE(1, 4);
|
|
bytes.writeUInt16LE(2, 6);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(28, 24);
|
|
bytes.writeUInt32LE(offset, 60);
|
|
const prefix = bytes.subarray(0, 4096);
|
|
|
|
expect(observeMzWindowsHeader(prefix, bytes.length)).toEqual({
|
|
state: "signature-needed",
|
|
offset,
|
|
});
|
|
expect(
|
|
observeMzWindowsHeader(prefix, bytes.length, {
|
|
offset,
|
|
bytes: Buffer.from("PE\0\0", "binary"),
|
|
}),
|
|
).toEqual({ state: "declared", offset, signature: "PE" });
|
|
expect(
|
|
observeMzWindowsHeader(prefix, bytes.length, {
|
|
offset,
|
|
bytes: Buffer.from("ZZZZ", "ascii"),
|
|
}),
|
|
).toEqual({ state: "absent" });
|
|
});
|
|
|
|
it("keeps an unconfirmed pointer outside a relocation table unresolved", () => {
|
|
const bytes = Buffer.alloc(256);
|
|
dosMz().copy(bytes, 0, 0, 28);
|
|
bytes.writeUInt16LE(256, 2);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(64, 24);
|
|
bytes.writeUInt32LE(192, 60);
|
|
|
|
expect(parseMzHeaderEvidence(bytes).windowsHeader).toEqual({
|
|
state: "candidate",
|
|
offset: 192,
|
|
signature: "other",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({ ok: false });
|
|
|
|
bytes.writeUInt32LE(0xfffffff0, 60);
|
|
expect(parseMzHeaderEvidence(bytes).windowsHeader).toEqual({
|
|
state: "candidate",
|
|
offset: 0xfffffff0,
|
|
signature: "unobserved",
|
|
});
|
|
expect(parseExecutableHeader(bytes, "x64")).toMatchObject({ ok: false });
|
|
});
|
|
});
|
|
|
|
it("retains ordered DOS relocation aliases and their source/module target coordinates", () => {
|
|
const bytes = Buffer.alloc(128);
|
|
bytes.write("MZ");
|
|
bytes.writeUInt16LE(128, 2);
|
|
bytes.writeUInt16LE(1, 4);
|
|
bytes.writeUInt16LE(4, 6);
|
|
bytes.writeUInt16LE(4, 8);
|
|
bytes.writeUInt16LE(28, 24);
|
|
bytes.writeUInt16LE(0, 28);
|
|
bytes.writeUInt16LE(1, 30);
|
|
bytes.writeUInt16LE(16, 32);
|
|
bytes.writeUInt16LE(0, 34);
|
|
bytes.writeUInt16LE(16, 36);
|
|
bytes.writeUInt16LE(0, 38);
|
|
bytes.writeUInt16LE(17, 40);
|
|
bytes.writeUInt16LE(0, 42);
|
|
const parsed = parseDosMzHeader(bytes);
|
|
if (!parsed.ok) throw new Error(parsed.error);
|
|
expect(parsed.value.relocations).toEqual([
|
|
{ segment: 1, offset: 0, moduleOffset: 16, fileOffset: 80 },
|
|
{ segment: 0, offset: 16, moduleOffset: 16, fileOffset: 80 },
|
|
{ segment: 0, offset: 16, moduleOffset: 16, fileOffset: 80 },
|
|
{ segment: 0, offset: 17, moduleOffset: 17, fileOffset: 81 },
|
|
]);
|
|
// Parsed facts are snapshots, independent of later source-buffer edits.
|
|
bytes.writeUInt16LE(63, 32);
|
|
expect(parsed.value.relocations[1]).toEqual({
|
|
segment: 0,
|
|
offset: 16,
|
|
moduleOffset: 16,
|
|
fileOffset: 80,
|
|
});
|
|
expect(parseDosMzHeader(bytes)).toEqual({
|
|
ok: false,
|
|
error: "DOS MZ relocation 1 points outside its load module",
|
|
});
|
|
});
|
|
|
|
const extendedRelocationImage = (): Buffer => {
|
|
const bytes = dosMz(8192);
|
|
bytes.writeUInt16LE(257, 8); // 4112-byte header.
|
|
bytes.writeUInt16LE(2, 6);
|
|
bytes.writeUInt16LE(4096, 24);
|
|
return bytes;
|
|
};
|
|
|
|
it("retains fixed declarations while requesting only a source-bounded relocation prefix", () => {
|
|
const bytes = extendedRelocationImage();
|
|
const prefix = bytes.subarray(0, 64);
|
|
const evidence = parseMzHeaderEvidence(prefix, bytes.length);
|
|
expect(evidence.declarations).toEqual(readDosMzDeclarations(prefix));
|
|
expect(evidence.declarations).toMatchObject({
|
|
ok: true,
|
|
value: {
|
|
headerBytes: 4112,
|
|
relocationCount: 2,
|
|
relocationTableOffset: 4096,
|
|
relocationTableEnd: 4104,
|
|
entryOffset: 0,
|
|
entrySegment: 0,
|
|
},
|
|
});
|
|
expect(evidence.relocationTableRead).toEqual({ offset: 0, byteLength: 4104 });
|
|
expect(evidence.dos).toEqual({
|
|
ok: false,
|
|
error: "truncated DOS MZ relocation table",
|
|
});
|
|
const observed = parseMzHeaderEvidence(bytes.subarray(0, 4104), bytes.length);
|
|
expect(observed.relocationTableRead).toBeUndefined();
|
|
expect(observed.dos).toMatchObject({
|
|
ok: true,
|
|
value: { relocationCount: 2, headerBytes: 4112 },
|
|
});
|
|
});
|
|
|
|
it("does not request absent or out-of-bounds relocation records", () => {
|
|
const zero = extendedRelocationImage();
|
|
zero.writeUInt16LE(512, 8);
|
|
zero.writeUInt16LE(0, 6);
|
|
zero.writeUInt16LE(6000, 24);
|
|
expect(
|
|
parseMzHeaderEvidence(zero.subarray(0, 64), zero.length)
|
|
.relocationTableRead,
|
|
).toBeUndefined();
|
|
expect(parseDosMzHeader(zero).ok).toBe(true);
|
|
const outsideHeader = extendedRelocationImage();
|
|
outsideHeader.writeUInt16LE(5000, 24);
|
|
const headerEvidence = parseMzHeaderEvidence(
|
|
outsideHeader.subarray(0, 64),
|
|
outsideHeader.length,
|
|
);
|
|
expect(headerEvidence.relocationTableRead).toBeUndefined();
|
|
expect(headerEvidence.dos).toEqual({
|
|
ok: false,
|
|
error: "DOS MZ relocation table lies outside its header",
|
|
});
|
|
const outsideFile = extendedRelocationImage();
|
|
outsideFile.writeUInt16LE(1024, 8);
|
|
outsideFile.writeUInt16LE(9000, 24);
|
|
expect(
|
|
parseMzHeaderEvidence(outsideFile.subarray(0, 64), outsideFile.length)
|
|
.relocationTableRead,
|
|
).toBeUndefined();
|
|
});
|
|
|
|
it("keeps independent malformed declarations and the established DOS error precedence", () => {
|
|
const bytes = extendedRelocationImage();
|
|
bytes.writeUInt16LE(0, 4);
|
|
bytes.writeUInt16LE(65535, 20);
|
|
const evidence = parseMzHeaderEvidence(bytes.subarray(0, 64), bytes.length);
|
|
expect(evidence.declarations).toMatchObject({
|
|
ok: true,
|
|
value: { pages: 0, entryOffset: 65535 },
|
|
});
|
|
expect(evidence.relocationTableRead?.byteLength).toBe(4104);
|
|
expect(evidence.dos).toEqual({
|
|
ok: false,
|
|
error: "invalid DOS MZ page count or final-page size",
|
|
});
|
|
expect(parseDosMzHeader(bytes, bytes.length - 1)).toEqual({
|
|
ok: false,
|
|
error: "invalid DOS MZ file length",
|
|
});
|
|
bytes.writeUInt16LE(17, 4);
|
|
expect(parseDosMzHeader(bytes.subarray(0, 64), bytes.length)).toEqual({
|
|
ok: false,
|
|
error: "truncated DOS MZ relocation table",
|
|
});
|
|
expect(parseDosMzHeader(bytes)).toEqual({
|
|
ok: false,
|
|
error: "DOS MZ entry point lies outside its initialized load module",
|
|
});
|
|
});
|
|
|
|
it("keeps declared Windows signatures independent of incomplete DOS relocations", () => {
|
|
const bytes = extendedRelocationImage();
|
|
bytes.writeUInt32LE(128, 60);
|
|
const evidence = parseMzHeaderEvidence(bytes.subarray(0, 64), bytes.length, {
|
|
offset: 128,
|
|
bytes: Buffer.from("PE\0\0"),
|
|
});
|
|
expect(evidence.windowsHeader).toEqual({
|
|
state: "declared",
|
|
signature: "PE",
|
|
offset: 128,
|
|
});
|
|
expect(evidence.dos).toEqual({
|
|
ok: false,
|
|
error: "truncated DOS MZ relocation table",
|
|
});
|
|
expect(evidence.relocationTableRead?.byteLength).toBe(4104);
|
|
});
|
|
|
|
it("completes captured evidence from the original admitted fixed declarations", () => {
|
|
const bytes = extendedRelocationImage();
|
|
const declarations = readDosMzDeclarations(bytes.subarray(0, 64));
|
|
if (!declarations.ok) throw new Error(declarations.error);
|
|
expect(dosMzDeclaredImageByteLength(declarations.value)).toEqual({
|
|
ok: true,
|
|
value: bytes.length,
|
|
});
|
|
const evidence = parseDeclaredMzHeaderEvidence(
|
|
bytes.subarray(0, 4104),
|
|
bytes.length,
|
|
declarations,
|
|
);
|
|
expect(evidence.declarations).toBe(declarations);
|
|
expect(evidence).toEqual(
|
|
parseMzHeaderEvidence(bytes.subarray(0, 4104), bytes.length),
|
|
);
|
|
expect(evidence.dos.ok).toBe(true);
|
|
});
|
|
|
|
it("adds distant Windows signatures while retaining prior DOS observations", () => {
|
|
const bytes = extendedRelocationImage();
|
|
bytes.writeUInt32LE(6000, 60);
|
|
const prefix = bytes.subarray(0, 4104);
|
|
const evidence = parseMzHeaderEvidence(prefix, bytes.length);
|
|
expect(evidence.windowsHeader).toEqual({
|
|
state: "signature-needed",
|
|
offset: 6000,
|
|
});
|
|
const signature = { offset: 6000, bytes: Buffer.from("PE\0\0") };
|
|
const completed = withMzWindowsHeaderSignature(
|
|
prefix,
|
|
bytes.length,
|
|
evidence,
|
|
signature,
|
|
);
|
|
expect(completed.dos).toBe(evidence.dos);
|
|
expect(completed.declarations).toBe(evidence.declarations);
|
|
expect(completed.windowsHeader).toEqual({
|
|
state: "declared",
|
|
signature: "PE",
|
|
offset: 6000,
|
|
});
|
|
expect(completed).toEqual(
|
|
parseMzHeaderEvidence(prefix, bytes.length, signature),
|
|
);
|
|
});
|