Measure: SHI.EXE, 119,618 bytes, 0.0268 % of the disc. Real-mode MZ,
Borland C++ 1991. The page arithmetic closes on the file length with residue
0; all 1,684 relocations land inside the load image. It detects VGA through
the BIOS, sets mode 13h, writes segment A000h directly, and reads
the mouse through INT 33h. There is no NE anywhere in it.
python tools/mz.py SHI.EXE
| field | ||
|---|---|---|
e_cblp |
322 | bytes used in the last page |
e_cp |
234 | 512-byte pages |
e_crlc |
1,684 | relocation entries |
e_cparhdr |
480 | paragraphs = 7,680 bytes of header |
e_minalloc |
251 | = 4,016 bytes |
e_maxalloc |
0xFFFF |
take all available memory |
e_ss:e_sp |
1C47:0080 |
|
e_cs:e_ip |
0000:0000 |
entry at file offset 7,680 |
e_lfarlc |
0x3E |
where the relocation table starts |
The check. (234 − 1) × 512 + 322 = 119,618, and the file is 119,618
bytes. Residue 0. The header says how long the image is; the file system
says how long the file is; they agree. Nothing is appended — no overlay, no
self-extracting tail, no packer's payload.
This was derived before the file was opened, from the sixteen bytes the pre-briefing quoted, and written into 00-predictions.md as clause C31.
And a correction to the pre-briefing. It reports "e_lfanew (u16 @0x3c)
0", and concludes from that there is no NE header. The conclusion is right;
the reading is not. e_lfanew is a u32 at 0x3C, and here it reads
0x00010000. But that does not matter either, because:
e_lfarlc = 0x3E
The relocation table starts at 0x3E, which is the second half of the
field a Windows-era binary would put e_lfanew in. The bytes at
0x3C..0x3F are 00 00 01 00: two bytes of DOS-era reserved space, and then
the first relocation entry's offset word. The field is not zero. It does
not exist. There is no room for it, because a linker that puts relocations
at 0x3E is a linker that has never heard of an extended header.
That is a better statement than "e_lfanew is 0", and it is the one this
disc supports:
occurrences of NE anywhere in the file |
0 |
occurrences of LE |
0 |
occurrences of LX |
0 |
occurrences of PE\0\0 |
0 |
pe.py, written last session for PE32+, was run because the standing rule is
that a refusal is a measurement:
ValueError: SHI.EXE: no PE signature at 0x10000
exit 1
Recorded, not skipped.
1,684 entries at 0x3E, 6,736 bytes, ending at 0x1A8E. The header is 7,680
bytes, so 882 bytes of slack follow the table and every one of them is
zero — paragraph alignment, written clean.
All 1,684 entries land inside the 111,938-byte load image. 1,684 of
1,684, none out of range, across 32 distinct segments. A 32-segment
real-mode program with 1,684 fixups is a large-model C build, which is what
Borland C++ 1991 produces and what the string at 0x1BA14 says it is.
The pre-briefing's own list of what was not done opened with "no interrupt
vector, port address or BIOS call was located in either binary, so nothing is
known about how either talks to hardware", and _pre/question.txt called
the display path "a real disassembly question and the strongest single test
available, because the answer is a specific instruction and not an
inference."
There are four INT 10h sites in the whole executable. All four, read by
hand:
| offset | bytes | what |
|---|---|---|
+0x0CC43 |
b8 00 1a cd 10 3c 1a 75 07 80 fb 07 72 … |
AX=1A00h — read display combination code; require AL=1Ah, then BL ≥ 7. This is the VGA test behind "Please make sure your graphics card is VGA compatible." |
+0x0CC5E |
b4 00 b0 13 cd 10 |
AH=0, AL=13h — VGA mode 13h, 320 × 200, 256 colours |
+0x0CC66 |
b4 50 b0 01 b2 00 cd 10 |
AH=50h, AL=01, DL=00 — not a standard IBM VGA BIOS function |
+0x0CCDF |
b4 00 b0 03 cd 10 |
AH=0, AL=3 — back to 80 × 25 text on exit |
Then the frame buffer, three times:
+0x0CC6F b8 00 a0 mov ax,0A000h
2e a3 23 00 mov cs:[0x23],ax
b8 40 01 mov ax,0140h ; 320
A000h and 320, loaded together, stored together. That is a mode 13h
program writing pixels itself, exactly as the platform notes describe their
own DispDib path — except through DOS, with no Windows anywhere near it.
And the mouse, INT 33h, nine sites, one initialisation sequence:
33 c0 cd 33 AX=0000 reset the driver
b8 0c 00 b9 07 00 cd 33 AX=000C install event handler, mask 7
b8 04 00 b9 3f 01 ba 63 00 cd 33 AX=0004 position cursor at 319, 99
b8 07 00 b9 00 00 ba 7f 02 cd 33 AX=0007 horizontal range 0 .. 639
b8 08 00 b9 00 00 ba c7 00 cd 33 AX=0008 vertical range 0 .. 199
0..639 horizontal, 0..199 vertical is the mouse coordinate space of a
mode 13h screen, where X counts in half-pixels. The cursor is parked at
(319, 99) — the exact centre. This is a textbook Microsoft-mouse
initialisation for a 320 × 200 VGA application, and it is why the disc ships
MOUSE.COM.
python tools/vistokens.py over the two executables only:
in SHI.EXE |
|
|---|---|
Tandy, VIS, Video Information System |
0 |
tlaunch, MODULAR, Modular Windows |
0 |
HC.DLL, DISPDIB, MMSYSTEM, WIN87EM |
0 |
WIN.INI, SYSTEM.INI, KERNEL, USER.EXE |
0 |
EnterDVA, StretchDIBits, waveOut, timeGetTime |
0 |
OPL3 ports 0x388 / 0x389 as immediates |
0 |
DAC / Sound Blaster base 0x220 as an immediate |
0 |
Nothing in this binary knows what machine it is on, and nothing in it
touches either audio port the VIS platform notes document. How it plays
8.5 MB of SOUND.DAT and 143 MB of interleaved PCM without naming a port is
17-not-done.md's third entry — the likely answer is a
computed port from a configuration this disc does not carry, and that is a
hypothesis and not a finding.
Run over all 193 files instead of the two executables, the same search
returns 230 hits on 0xA000, 7 on 0x388, 4 on 0x389, 300 on the string
VIS, 773 on DVA and 1,387 on GDI — every one of them inside .IMV
compressed video, where 429,867,008 bytes of high-entropy data contain every
three-byte sequence hundreds of times by arithmetic.
The previous session's lesson was that its own dumper's hexadecimal offset column produced eight false hits on a project name. This session's version is larger and the same shape: the loudest scanner in the room was mine. The tool now refuses to print a bare count and prints file names and offsets instead, and the code-pattern search is documented as belonging on executables.
Only 39 printable runs of 8 or more bytes in 119,618 bytes, and these are nearly all of them:
0x01BA14 Borland C++ - Copyright 1991 Borland Intl.
0x01BBC2 Could not initialize heap manager.
0x01BC67 There is not enough free memory to play Sherlock.
0x01BCD7 Could not initialize mouse.
0x01BCF3 Please make sure your mouse is connected and the mouse drivers are installed.
0x01BD42 Could not initialize graphics card.
0x01BD66 Please make sure your graphics card is VGA compatible.
0x01BD9E Could not initialize sound manager.
0x01BDC3 L O A D I N G . . .
0x01BDD7 RESOURCE.DAT
0x01BDF8 There has been a read error on the CD. Please make sure it is inserted.
0x01BE49 QUIT GAME
0x01BE53 Please insert the disk. Click to continue.
0x01CDDE Could not find Sherlock Holmes data files.
RESOURCE.DAT is the only filename in the executable. Not CDPLAYER.DIB,
not NEXTPAGE.DIB, not SOUND.DAT, not GAMESCEN, not HOLMES, not
SCENES, and — on a disc that is 96 % of them — not IMV, not once.
Every path the program opens comes out of a data file at run time, in the
container format of 07-the-container.md, written as
.\MC\SCENES\MC1.IMV.
paths.py over all 193 files, coverage 100 %: 36 drive-lettered raw hits,
0 real. All 36 are in .IMV — X:\9\9, L:/.7G\u, C:\g\7CC. Zero
absolute build paths, zero source-tree paths, and none of the 36 in either
executable or any text file. The previous session's row was one path on
28.59 % coverage for a structural reason; this one is zero on 100 %,
because a 1992 disc has nothing to hide behind.
MOUSE.COM, 56,448 bytes, is the Microsoft DOS mouse driver —
*** This is Copyright 1983-1992 Microsoft ***, 636 printable runs of 10+
bytes, HorizontalSensitivity, DoubleThreshold,
ActiveAccelerationProfile, CursorDisplayDelay, and a list of language
names. It is named first in CONTROL.TAT's program list, with A: in front
of it (10-the-vendor-block.md).
CDPLAYER.DIB and NEXTPAGE.DIB, 8,454 bytes each, are the only Windows
artefacts on this disc — 16,908 bytes, 0.0038 %. Both parse exactly:
BM, declared size == actual, pixel data at 174, 40-byte
BITMAPINFOHEADER, 90 × 90, 1 plane, 8 bpp, BI_RGB, stride 92,
biSizeImage 8,280 == computed, 174 + 8,280 = 8,454, residue 0, 2 of 2.
And they carry 30 palette entries while their pixels use indices 1 and 231–255. A DIB whose pixels index past its own colour table is a DIB drawn against the Windows system palette — the idiom of a palette-managed Windows 3.1 display, where the top and bottom of the 256 entries are the static system colours. That palette is in the console's ROM, not on this disc, so the true colours of these two files are not recoverable from the disc alone.
Rendered with the file's own thirty colours laid over the range its pixels
use, CDPLAYER.DIB is a 90 × 90 circular icon with radial detail — a CD.
Neither filename appears in SHI.EXE. They are consumed by something that is
not on this pressing, and that makes them the second piece of evidence in
11-the-question.md after the vendor block.