# 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](executable-unpacking.md)
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`:

```text
0e211d7bee660a9956bfd8a896bdfbda82f1d946a71942177eb8b77460fbb819
```

From the repository directory:

```sh
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:

```text
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:

```text
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:

```text
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:

- [Deark executable inspector](https://github.com/jsummers/deark/blob/master/modules/exe.c)
  and [DIET handler](https://github.com/jsummers/deark/blob/master/modules/diet.c).
- [Detect It Easy MS-DOS signature rules](https://github.com/horsicq/Detect-It-Easy/tree/master/db/MSDOS).
- [DOSBox-X DOS executable loader](https://github.com/joncampbell123/dosbox-x/blob/master/src/dos/dos_execute.cpp),
  useful for loader initialization, not proof of Darker's internal architecture.

## Installation clues

`DARKER.BAT` contains:

```bat
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.
