Analysis model: GPT-5 (Codex), reasoning level not exposed

Last edited: 2026-08-30

# BBS-A-Holic BBS (2) by The Humble Guys - Technical Dissection

`BBS-A-Holic BBS (2)` is a real 1991 MS-DOS BBStro, but it is a much smaller
kind of production than a realtime cracktro. The only surviving file is a
3,762-byte executable made with GRABBER 3.60. It expands one signed 80x25
colour-text page, copies the resulting 4,000 bytes to `B800h`, waits for a key
and restores the previous display state.

The distinction matters. The large left-hand lettering and bordered board ad
are original CP437/attribute artwork; the decompressor, video setup, optional
timer and key handling belong to G.A. Monroe's generic GRABBER viewer. There
are no vector balls, custom bitmap graphics, music or hidden second screen.

Release year: 1991.

The previous research queue associated this file with a THG *Lemmings*
release. The examined archive does not support that claim: it contains only
`THGSITE!.EXE`, with no game, release note or companion metadata. This page
therefore treats it as a genuine standalone board advert attributed to The
Humble Guys by the surviving catalogues, not as a proven software-bundled
cracktro.

## Sources

- [Demozoo production page](https://demozoo.org/productions/165434/)
- [Scene.org archive](https://archive.scene.org/pub/demos/compilations/lost_found_and_more/bbs/bbs-a-holic_bbs2.zip)
- [Pouet production page](https://www.pouet.net/prod.php?which=68544)

Demozoo identifies the production as a 1991 MS-DOS BBStro by The Humble Guys
and an advert for BBS-A-Holic. Pouet independently gives the same year, group,
platform and board-ad identity. Neither catalogue supplies an artwork credit.
The visible footer in the executable signs the ANSI as `D·ToX <ACiD> / Little
T`; that literal signature is reported without trying to map it to catalogue
person records that are not present.

## Examined Artifact

The archive has one member:

```text
79394f3638b2a09ada655e90310cbd017da0accd7994891d52bc9a279358dce2  bbs-a-holic_bbs2.zip
b7abdb261d044c774520d7b586740679e6d48a0b8293f8bb38c5d50a1a2494e6  THGSITE!.EXE  3,762 bytes
```

Its ZIP timestamp is 22 November 2016, the day the production was added to
Pouet, so it is a preservation timestamp rather than release-date evidence.
The year on this page comes from the catalogues.

The executable identifies its generator internally:

```text
Created by GRABBER (tm) Version 3.60
Copyright (c) G.A. Monroe 1987, 1988, 1989, 1990
```

That tool identity is consistent with the code: a general-purpose viewer
parses `/F`, `/N`, `/K` and `/T` command-tail switches, detects the active
adapter, allocates a screen buffer, expands a stored image and optionally
times the display. The examined default route uses none of those switches.

## Complete Silent DOSBox-X Run

The exact executable was run directly under DOSBox-X 2026.01.02 on 30 August
2026 with `machine=svga_s3` and 3,000 fixed cycles. SDL video and audio used
dummy host drivers; the mixer had `nosound=true`, and Sound Blaster, MIDI, PC
speaker and Tandy audio were disabled. The file neither requires nor attempts
sound output.

One scripted Enter key traversed the complete route. The program displayed its
single page, accepted the key, restored the prior mode and returned normally to
DOS. The capture lasts 8.043 seconds. Its private MPEG-TS diagnostic contains
an empty AAC stream created by the capture container and is not published.

DOSBox-X produced 720x400 video samples with sample aspect ratio `20:27`. The
still below is the complete frame at `00:02`, converted with nearest-neighbour
scaling to 720x540 square pixels without cropping or padding:

![BBS-A-Holic BBS 2 complete text-mode screen at 00:02](images/bbs-a-holic-bbs2-runtime-00-02.png)

The page includes only an area-code placeholder and explicitly tells the
reader to obtain the number elsewhere. No telephone number is present in the
executable, so the complete authored frame can be shown without reproducing
historical contact data.

The emulator log records one benign `INT 16h` extension-probe call before the
screen. That is the viewer's `AX=4752h`, `DL=FFh` capability query, not a
failed runtime gate; the page appears, the later Enter is accepted and the
process exits normally.

## MZ Shape And A 48-Byte Length Quirk

The executable is not packed by PKLITE, LZEXE or a self-modifying wrapper. It
is an ordinary zero-relocation MZ with the GRABBER player and packed page stored
together:

```text
physical file size                 3,762 bytes
MZ-declared file size              3,714 bytes
header                                48 bytes
physical bytes after header        3,714 bytes
MZ-declared load image             3,666 bytes
physical tail beyond declaration      48 bytes
relocations                            0
entry CS:IP                    0008:0000
entry file offset                   00B0h
stack SS:SP                    0000:0080
```

The header fields are `e_cp=8`, `e_cblp=0082h` and `e_cparhdr=3`. Curiously,
the declared total is exactly the physical post-header length, as if GRABBER
computed the module size and forgot to add its 48-byte header. The last 48
physical bytes are not disposable padding: they finish the compressed
attribute plane. The DOSBox-X run proves that its loader made those bytes
available on this route. Exact historical DOS-loader compatibility was not
separately tested, so the malformed size is preserved as an observed artifact
rather than normalized away.

At the MZ entry point, runtime `CS` begins 128 bytes into the load image. The
first instruction jumps over strings and state to the player at runtime
offset `00F7h`:

```asm
0000  jmp  00F7h

00F7  mov  bx,ds
00F9  mov  ax,cs
00FB  mov  ds,ax
00FD  mov  es,ax
00FF  mov  [0043h],bx      ; retain original PSP/data segment
0103  cld
0104  call 0759h           ; shrink/allocate and switch private stack
0107  call 07E7h           ; uppercase command tail in the PSP
```

No relocation fixups are needed because the player keeps code and state
relative to `CS`, stores allocated segment values at runtime, and uses BIOS/DOS
services for the machine-facing operations.

## The Embedded Page Header

The packed-image header starts at runtime offset `0809h`, immediately after the
viewer code:

```text
0809  19          rows = 25
080A  50          columns = 80
080B  03          BIOS mode = 3, colour text
080C  30          border/palette state
080D  A0 0F       expanded byte count = 4,000
080F..081B        viewer state / reserved bytes = zero
081C              first compressed plane
```

The dimensions and byte count agree exactly:

```text
25 rows * 80 columns = 2,000 cells
2,000 cells * (one character + one attribute) = 4,000 bytes
```

The image is stored as two compressed 2,000-byte planes rather than as
interleaved screen words. The character plane occupies 969 bytes from runtime
`081Ch` through `0BE4h`. A six-byte delimiter follows:

```text
0BE5  00 00 52 47 00 00    NUL, "RG", NUL marker
0BEB                       attribute plane begins
```

The attribute plane takes the final 535 bytes and ends at physical EOF.

## Exact GRABBER RLE Decoder

The common decoder begins at runtime `0629h`. `DL` is a rotating one-bit token
selector; every eighth token fetches a new flag byte into `DH`. A clear flag
bit means one literal byte. A set bit means a two-byte `(count,value)` run:

```asm
0629  mov  dx,0080h        ; rotating selector, DH initially zero
062C  mov  bx,[080Dh]      ; 0FA0h expanded interleaved size
0630  add  bx,di           ; terminal destination offset
0632  mov  es,[003Ch]      ; allocated 4,000-byte page buffer

0636  rol  dl,1
0638  lodsb                ; first token byte
0639  cmp  dl,1
063C  jne  0641h
063E  mov  dh,al           ; one flag byte for the next eight tokens
0640  lodsb                ; first data byte
0641  mov  cx,1
0644  test dh,dl
0646  je   064Bh           ; clear bit: AL is a literal
0648  mov  cl,al           ; set bit: AL is repeat count
064A  lodsb                ; repeated value

064B  stosb
064C  or   bp,bp
064E  je   0651h
0650  inc  di              ; text mode: stride two, one plane at a time
0651  loop 064Bh
0653  cmp  di,bx
0655  jb   0636h
0657  mov  ax,cs
0659  mov  es,ax
065B  ret
```

For text modes the caller sets `BP=FFFFh`, so every output byte advances `DI`
twice. The first invocation begins at `DI=0` and fills the even character
positions. The marker scanner then locates `00 00 52 47 00 00`; the second
invocation begins at `DI=1` and fills the odd attribute positions.

The recovered expansion ledger is:

```text
character plane   969 packed bytes   729 tokens   148 runs -> 2,000 bytes
attribute plane   535 packed bytes   293 tokens   205 runs -> 2,000 bytes
separator           6 bytes
combined payload 1,510 bytes                         -> 4,000 bytes
```

Hashes of the independently reconstructed data are:

```text
6c3bd2c143ec647b2fe46d728d9ba40eeaeb9b2876246aaf912117384c115c86  character plane
ea3a8ba12d0ed838dd5f7011b48928526fa4948ee3690afcdbb0b876d6b769bb  attribute plane
c9d27671fec1e758cc913a61bd0e326ee679bc23e7537ee33e0bf14cc27488ce  interleaved B800 page
```

The page has 1,213 non-space character cells. Its 2,000 attributes use 14
values from `01h` through `7Fh`; none has bit 7 set, so the artwork does not
request hardware blink. Large coloured fields are ordinary text-cell
backgrounds, while the title edges use CP437 half blocks and full blocks.

## Allocation, Mode Setup And Full-Page Copy

The setup at runtime `0759h` disables DOS Ctrl-Break checking temporarily,
shrinks the original allocation, reserves a private stack, then allocates an
even-paragraph buffer large enough for the 4,000-byte expanded page. The
resulting screen-buffer segment is stored at `[003Ch]` and used as `ES` by the
decoder.

The display path queries the current video mode through BIOS `INT 10h/AH=0Fh`
and saves the mode, active page and column count. It also reads BIOS data-area
geometry and adapter state. Because the embedded header requests mode 3, the
active colour-text destination is `B800:0000`; monochrome mode 7 would select
`B000:0000` instead.

After both planes have been expanded into their interleaved buffer, one copy
publishes the entire authored screen:

```asm
03C3  mov  ax,B800h
03C6  cmp  word [005Eh],03B4h  ; monochrome CRT controller?
03CC  jne  03D1h
03CE  mov  ax,B000h
03D1  push es
03D2  mov  es,ax
03D4  mov  cx,[080Dh]          ; 0FA0h bytes
03D8  shr  cx,1                ; 07D0h words = 2,000 cells
03DA  mov  di,[0058h]          ; saved display-page offset
03DE  xor  si,si
03E0  push ds
03E4  mov  ds,[003Ch]          ; expanded screen buffer
03E8  rep  movsw
03EA  pop  ds
03EB  pop  es
```

There is no drawing loop after this copy. What looks like a large graphic is
already fully authored in the decompressed cell page.

## Timer Hook, Key Gate And Cleanup

GRABBER supports timed and unattended presentation, so the generic player
saves interrupt vector 8 and installs a tiny tick handler. The handler only
increments a counter and chains to the previous vector:

```asm
06FE  inc  word cs:[0047h]
0703  jmp  far cs:[004Bh]
```

The default route polls with DOS `INT 21h/AH=06h`, `DL=FFh` while the timer
window is active. When it reaches the normal blocking gate, the player uses
`INT 21h` function `0Ch` with subfunction `07h`: flush standard input, then
read one character without echo. The scripted Enter therefore changes no
screen state; it simply releases the single page.

The exit path restores the prior video mode when necessary, resets palette and
cursor state, restores the saved interrupt-8 vector, restores the original DOS
Ctrl-Break flag and terminates through `INT 21h/AH=4Ch`. The observed DOSBox-X
return confirms that this cleanup path completed; no timeout or forced kill
was used.

## Runtime-To-Code Concordance

| Runtime evidence | Recovered mechanism | Conclusion |
|---|---|---|
| One static 80x25 page appears and remains unchanged until Enter | Header bytes specify 25 rows, 80 columns, mode 3 and a 4,000-byte expansion | This is one colour-text page, not a multi-part graphics intro. |
| The left title and right panel use blocks, half-blocks, line characters and many cell colours | Two RLE streams reconstruct 2,000 CP437 bytes and 2,000 attribute bytes | The apparent graphic is ANSI-style cell art, not a bitmap or custom font. |
| The complete page appears at once | `rep movsw` copies exactly 2,000 words from the expanded buffer to `B800h` | There is no incremental renderer, wipe or animation pass. |
| The frame stays silent and static | No sound path exists; the only interrupt hook increments a timer counter | The hook supports viewer timing, not music or motion. |
| One Enter returns cleanly to DOS | Function `0Ch/07h` supplies the blocking key gate; mode, palette, cursor, timer vector and Ctrl-Break state are restored | The direct run covers the complete authored route and normal exit. |
| The page identifies THG and ACiD distribution roles and bears an ANSI footer signature | Those strings are reconstructed from the executable's character plane, while the viewer identifies itself separately as GRABBER 3.60 | The board advert and art are genuine; the playback code is a generic tool, and no parent game is proven. |

The preservation result is thus narrower but firmer than the earlier catalogue
lead: `THGSITE!.EXE` is a real period BBStro, not an invented vector/ball demo,
and its entire visual can be recovered byte-for-byte. Its technical interest is
the compact split-plane RLE representation and the surprisingly complete
generic DOS display wrapper around one signed colour-text page.
