DARKER Research archive

Darker executable: first-pass investigation

Follow-up: the startup has now been traced and the executable unpacked. See Executable unpacking and the first internal map for the verified 64 KiB image, reconstructed MZ, and newly identified tables. This document retains the observations and uncertainty of the original pass.

Investigation date: 2026-09-18. This records the supplied installation, not an assumed original retail executable. Original files were not modified.

Result

darker/X.EXE is a 52,936-byte DOS MZ executable with an unusually opaque, self-modifying entry sequence. Its DOS container can be described precisely; its original compiler, linker, runtime, sound middleware and game-code layout cannot yet be identified reliably. Compression or protection is a reasonable working hypothesis, not an identified format.

This copy has been confirmed to run. The local exploratory execution attempts did not establish a successful game startup or a trustworthy failure diagnosis. Do not classify the executable as corrupt on the basis of this investigation.

Specimen and reproducibility

SHA-256 of darker/X.EXE:

0e211d7bee660a9956bfd8a896bdfbda82f1d946a71942177eb8b77460fbb819

From the repository directory:

python3 tools/inspect_exe.py
objdump -D -b binary -m i8086 --start-address=32 --stop-address=288 darker/X.EXE

The Python script uses only the standard library. It reads the executable and writes analysis/executable/mz-report.json and strings.txt. The saved entry-disassembly.txt is a linear decoding of the on-disk bytes, not a validated control-flow listing or a recovered startup routine. Offsets in these artifacts are file offsets unless expressly stated otherwise.

DOS container

Property Value Interpretation
Signature MZ DOS executable container
Header size 0x20 / 32 bytes Two paragraphs
File pages 104 Pages are 512 bytes
Final-page bytes 200 Declared size exactly matches physical size
Loaded image 0x20..0xCEC7, 52,904 bytes Bytes after the header
Trailing data outside declared image 0 bytes No appended overlay outside the MZ size
DOS relocation count 0 DOS performs no relocation-table fixups
Relocation-table offset 0x1E No entries to read at that location
Initial CS:IP load segment + 0000:0000 Entry at file 0x20
Initial SS:SP load segment + 1161:0086 Stack address is image-relative 0x11696
Minimum extra allocation 0x7AEF paragraphs 503,536 bytes beyond the rounded image
Maximum extra allocation 0xFFFF paragraphs Permits DOS to allocate available conventional memory
Checksum 0000 Does not provide an integrity check
Overlay number 0 Main MZ module

The minimum allocation implied by the header is 556,704 bytes including the 256-byte PSP, after paragraph rounding. That is approximately 543.7 KiB. It is not a measurement of actual working memory, and says nothing conclusive about additional EMS/XMS use. The initial stack lies beyond the file-backed image but within the requested allocation; that is not itself an error.

There is no normal Windows extended header demonstrated here. In particular, offset 0x3C is inside the loaded image, not an established e_lfanew field of a larger DOS header. The outer MZ format establishes real-mode DOS entry; it does not prove that all later code remains real-mode or uses only 16-bit instructions.

Zero DOS relocations likewise does not prove a single code segment or position-independent game code. Startup code could relocate a recovered image itself. Absence of a trailing overlay does not preclude modules loaded from the external data files.

The startup puzzle

The four header bytes at 0x1C are:

01 00 44 31              ...D1

D1 is a useful candidate marker. Its meaning is unknown. It is tempting to associate it with the supplied readme's “Day 1” production credit, but two characters are insufficient to establish that connection or name a packer.

The declared entry begins:

file offset   bytes          16-bit interpretation
00000020      D0 EC          shr ah, 1
00000022      99             cwd
00000023      FD             std
00000024      E4 08          in al, 08h
00000026      23 F2          and si, dx
00000028      F6 EE          imul dh
0000002A      8B FE          mov di, si
0000002C      FE 06 9D 01    inc byte ptr [019Dh]

The instruction at 0x2C is especially useful. Under normal DOS EXE loading, DS points at the PSP and the image starts 256 bytes later. Here initial CS is the image segment. Thus DS:019D corresponds to image offset 0x9D, or file offset 0xBD. The on-disk byte there is FF; the increment changes it to 00. This is concrete self-modification at startup, not a guessed compiler idiom.

A limited Unicorn experiment, using a synthetic PSP and zero-initialized RAM, also observed changes to later instruction bytes. It did not recover a game entry point. That experiment lacked a complete DOS/BIOS/hardware environment; its branches, interrupts and stopping point are not authoritative evidence of what happens during the working game launch. In particular, it does not yet establish a decompression algorithm, an anti-debugging mechanism, or an unpacked image size.

Consequence: following an on-disk linear disassembly as though the bytes remain unchanged would produce misleading function boundaries and references. We need an execution trace plus memory snapshots around the startup writes.

Fingerprints and build attribution

Whole-file Shannon entropy is about 7.889 bits/byte. Across 4 KiB windows it ranges approximately 7.55–7.90 bits/byte. There are very few convincing plaintext strings; printable runs mostly look incidental. These observations are consistent with packed/encoded contents, but entropy alone cannot distinguish compression, encryption, or mixed binary data.

Case-sensitive plaintext searches found none of the following markers:

DOS/4G  DOS/32A  CWSDPMI  Borland  Microsoft  Watcom
PKLITE  LZ90  LZ91  dlz  DARKER  BLASTER  Miles  AIL  HMI  DIGPAK

These are negative string-search results, not proof that the corresponding components are absent. A component's strings could be encoded, omitted, or stored elsewhere. Even the game's own name is absent in plaintext.

Deark recognized the MZ container but did not identify/extract a supported packed format in its automatic inspection. A reference review of common MS-DOS packer signatures did not yield a justified attribution. This was not an exhaustive application of every Detect It Easy rule.

Consequently, this pass does not support claims such as “Watcom C with DOS/4GW”, “Borland Pascal”, “Miles sound”, or “entirely handwritten assembly”. The small file size and custom-looking startup are not enough to choose among those possibilities. Any outer protection/packing stage may also obscure evidence of an otherwise conventional build.

Reference implementations consulted:

Installation clues

DARKER.BAT contains:

X Lang=0 Mus=1

This establishes the intended executable and two supplied arguments. Their names suggest language and music settings; accepted values, defaults and exact effects remain to be confirmed in the recovered argument parser.

PLAY.BAT and JOGAR.BAT instead attempt to display AVISO.txt, pause, then run X.EXE without arguments. AVISO.txt is absent from this directory. The different wrappers suggest a repackaged installation, but do not establish that the executable itself was modified.

The included READ.ME credits a Day 1 production, Jas.C.Brooke for writing, Lyndon Brooke for artwork, and PC Music for music. These are credits, not compiler or audio-driver signatures; “PC Music” must not be mistaken for an identified playback library.

The five DARKER.00–.04 files total 5,523,083 bytes. Their names and sizes make external game data plausible, but this pass has not decoded them or established their record/container format. Only directory metadata and a short header peek were used. DARKER.SAV is 6,600 bytes; its structure is also left for a later pass.

Next investigation

  1. Reproduce the known-working launch in a debugger-capable DOS environment, retaining emulator version/configuration and the executable hash.
  2. Break at the DOS entry and watch writes to the loaded image, beginning with image offset 0x9D. Record executed bytes rather than only original bytes.
  3. Identify the transition from startup transformation to stable code and dump that memory with its segment/load-address information.
  4. Repeat strings, runtime and compiler fingerprinting on that recovered image. Trace DOS file opens to locate the archive reader before interpreting the external files. Map video, input, sound and memory interfaces from actual reachable call sites.

That will provide a sound basis for separating game logic, embedded tables, procedural generation and external assets. None of those boundaries is yet established by this initial container inspection.