| 1 | import assert from "node:assert/strict"; |
| 2 | import fs from "node:fs"; |
| 3 | import os from "node:os"; |
| 4 | import path from "node:path"; |
| 5 | import test from "node:test"; |
| 6 | |
| 7 | import { |
| 8 | readPESubsystem, |
| 9 | verifyWindowsGUISubsystem, |
| 10 | WINDOWS_GUI_SUBSYSTEM, |
| 11 | } from "./verify-windows-gui-subsystem.mjs"; |
| 12 | |
| 13 | function peImage(subsystem, magic = 0x20b) { |
| 14 | const image = Buffer.alloc(0x200); |
| 15 | image.write("MZ", 0, "ascii"); |
| 16 | image.writeUInt32LE(0x80, 0x3c); |
| 17 | image.write("PE\0\0", 0x80, "binary"); |
| 18 | image.writeUInt16LE(0xf0, 0x80 + 20); |
| 19 | image.writeUInt16LE(magic, 0x80 + 24); |
| 20 | image.writeUInt16LE(subsystem, 0x80 + 24 + 68); |
| 21 | return image; |
| 22 | } |
| 23 | |
| 24 | test("reads the subsystem from PE32 and PE32+ optional headers", () => { |
| 25 | assert.equal(readPESubsystem(peImage(WINDOWS_GUI_SUBSYSTEM, 0x10b)), 2); |
| 26 | assert.equal(readPESubsystem(peImage(WINDOWS_GUI_SUBSYSTEM, 0x20b)), 2); |
| 27 | }); |
| 28 | |
| 29 | test("rejects a console-subsystem executable", () => { |
| 30 | const directory = fs.mkdtempSync(path.join(os.tmpdir(), "reasonix-pe-subsystem-")); |
| 31 | const executable = path.join(directory, "reasonix-desktop.exe"); |
| 32 | try { |
| 33 | fs.writeFileSync(executable, peImage(3)); |
| 34 | assert.throws( |
| 35 | () => verifyWindowsGUISubsystem(executable), |
| 36 | /expected Windows GUI subsystem 2, got 3/, |
| 37 | ); |
| 38 | } finally { |
| 39 | fs.rmSync(directory, { recursive: true, force: true }); |
| 40 | } |
| 41 | }); |
| 42 | |
| 43 | test("rejects malformed and unsupported executable headers", () => { |
| 44 | assert.throws(() => readPESubsystem(Buffer.from("not an executable")), /DOS\/PE/); |
| 45 | assert.throws(() => readPESubsystem(peImage(2, 0x999)), /unsupported PE/); |
| 46 | }); |
| 47 |