Analysis model: gpt-5.5 xhigh
Montezuma's Revenge Graffiti by Software Pirates Inc. - Technical Dissection
Montezumas Revenge Graffiti is a source-limited MS-DOS cracktro / graffiti
screen credited by Demozoo to Software Pirates Inc. Demozoo lists the release
date as 15 May 1986 and classifies it as an MS-Dos Cracktro. The visible
public frame itself says Software Pirates, INC., MONTEZUMA'S REVENGE,
pirated 1991, and Press <return> for Menu Screen.
Release year: 1986 in Demozoo metadata; the visible screen carries a conflicting 1991 self-date.
This pass is source-limited. Demozoo provides one public screenshot, but the original executable/archive could not be downloaded from this environment. Defacto2's group page and JSON API endpoints returned HTTP 403 during this pass, so the code sections below are bounded implementation models from the public frame, not recovered disassembly.
The public screenshot contains no phone number, BBS number, street address, or other private contact text.
Sources Checked
- Demozoo production page:
https://demozoo.org/productions/362619/ - Demozoo group page for Software Pirates Inc.:
https://demozoo.org/groups/123017/ - Public Demozoo screenshot:
https://media.demozoo.org/screens/o/c1/db/58c4.354217.png - Defacto2 group page / API probes:
https://defacto2.net/g/software-pirates-inchttps://defacto2.net/api/v1/artifacts?search=Montezumas%20Revenge%20Graffitihttps://defacto2.net/api/v1/artifacts?filename=MONTEZUMA
Defacto2 probe results:
https://defacto2.net/g/software-pirates-inc 403 text/html; charset=UTF-8 5319 bytes
https://defacto2.net/api/v1/artifacts?search=Montezumas%20Revenge%20Graffiti 403 text/html; charset=UTF-8 5464 bytes
https://defacto2.net/api/v1/artifacts?filename=MONTEZUMA 403 text/html; charset=UTF-8 5395 bytes
Local evidence hashes:
dc228b9e422bc6972bcdf346698e31e1dcbefad5a50c7d0b457db064e907a68b montezumas-revenge-graffiti-demozoo.png
16c776ccb8246a29ba7063136bbd99109f6c12289210b68666ae297348ee98d3 montezumas-revenge-graffiti-logical-320x200.png
aee57d062269e26b76b5a517425483a1a8c477454ec7f929e584853bdcf0fc7a montezumas-revenge-graffiti-layout-map.png
Public Frame

The public screenshot is 640x400 and contains exactly four RGB colours:
colour pixels public bbox
#000000 249340 x=0..639, y=0..399
#ffff55 3044 x=80..555, y=192..381
#ff5555 2052 x=160..461, y=160..173
#55ff55 1564 x=144..487, y=80..95
Every public 2x2 block is internally constant, so the screenshot reduces
exactly to a logical 320x200 frame:
public size: 640x400
logical size: 320x200
2x2 mismatches: 0 of 64000

The logical frame has the same four colours:
colour pixels logical bbox
#000000 62335 x=0..319, y=0..199
#ffff55 761 x=40..277, y=96..190
#ff5555 513 x=80..230, y=80..86
#55ff55 391 x=72..243, y=40..47
The colour set is the classic high-intensity CGA palette-0 shape:
pixel code likely colour
00 black
01 bright green
10 bright red
11 yellow
That makes the likely display family a 320x200, two-bit-per-pixel CGA mode.
The screenshot contains no antialiasing and no intermediate capture colours,
which is why the exact 2x reduction works cleanly.
Date Discrepancy
The metadata and the frame disagree:
Demozoo: Released 15 May 1986
Visible frame: pirated 1991
Without the binary, this cannot be resolved honestly. The useful possibilities are:
- Demozoo's record may represent the Software Pirates Inc. catalogue line while the public screenshot comes from a later preserved or reissued artifact.
- The visible
1991text may be an actual later crack/version screen using the older group name. - The date in one source may simply be wrong.
The technical analysis below therefore treats the visible 1991 as real frame
evidence, while keeping the release-year field tied to the available Demozoo
metadata.
Layout Map

Front-page media note: the card uses the public Demozoo screenshot, the exact logical reduction, and the generated layout map directly. I did not make a GIF for this pass because the available evidence is one static public frame, not a timed playback sequence.
The logical screen is almost entirely black, with four horizontal text bands:
logical x/y colour region
72..243, 40..47 green Software Pirates, INC.
80..230, 80..86 red MONTEZUMA'S REVENGE
104..209, 96..103 yellow pirated 1991
40..277, 184..190 yellow Press <return> for Menu Screen
The coordinates are not arbitrary. All left edges are multiples of 8, and the
text rows are aligned to 8-pixel font rows:
green line x=72 -> column 9
red line x=80 -> column 10
yellow mid x=104 -> column 13
bottom x=40 -> column 5
text baselines start at y=40, 80, 96, and 184
This points to a graphics-mode text blitter using an 8x8 bitmap font rather
than a hand-drawn title page. It could be a BIOS graphics text call, but the
small amount of text and the clean colour changes are more naturally explained
by a direct ROM-font or bundled-font glyph loop.
CGA Memory Model
For a 320x200 CGA graphics page:
segment: B800h
page size: 16,384 bytes
stride: 80 bytes per logical scanline
pixel size: 2 bits
byte shape: four pixels per byte
banks: even scanlines at B800:0000h
odd scanlines at B800:2000h
The byte address for a pixel group is:
offset = (y & 1) * 0x2000 + (y >> 1) * 80 + (x >> 2)
shift = (3 - (x & 3)) * 2
mask = 3 << shift
For this frame, all text starts on x coordinates divisible by 8, so each
glyph row begins on a byte boundary. One 8x8 character row consumes exactly
two CGA bytes:
8 pixels / 4 pixels per byte = 2 bytes
That is why the glyph writer can avoid read/modify/write at the left and right edges of every character. If it paints on a black page, it can store two bytes per glyph row directly.
Useful text band addresses:
band x/y first CGA byte offset
green header 72,40 (40 >> 1) * 80 + (72 >> 2) = 0652h
red title 80,80 (80 >> 1) * 80 + (80 >> 2) = 0C94h
yellow self-date 104,96 (96 >> 1) * 80 + (104 >> 2) = 0F1Ah
yellow return prompt 40,184 (184 >> 1) * 80 + (40 >> 2) = 1CCAh
All four starts are on even scanlines, so the first row of each text band lives
in the even bank. The next visual row of the glyph jumps to the odd bank at
+2000h.
Likely Runtime Shape
Variant A: Clear Screen, Then Draw Four Strings
The smallest structured implementation is:
start:
mov ax,0004h ; CGA 320x200 graphics mode
int 10h
; Select high-intensity palette 0. Exact register path varies by code base.
; The visible colours are black, bright green, bright red, yellow.
mov ax,0b800h
mov es,ax
xor di,di
xor ax,ax
mov cx,2000h ; 16384 bytes / 2
rep stosw ; black page
; draw_string(x=72, y=40, colour=1, "Software Pirates, INC.")
; draw_string(x=80, y=80, colour=2, "MONTEZUMA'S REVENGE")
; draw_string(x=104, y=96, colour=3, "pirated 1991")
; draw_string(x=40, y=184, colour=3, "Press <return> for Menu Screen")
The entire visible page can be produced by about sixty glyphs, far smaller than
a raw 16 KiB page image. A raw page copy is possible, but it is an unattractive
encoding for this artifact.
Variant B: BIOS Graphics Text
BIOS int 10h can draw text in graphics modes using the ROM font. A compact
program might position the cursor and print strings through teletype or string
write calls.
That path is plausible because:
- the visible text is aligned like normal
8x8font output; - there is no custom logo art;
- four string calls and one keyboard wait would be enough.
It is less attractive if the cracktro wants predictable exact colour/palette behaviour on early clones. A direct B800h glyph loop is more common in size-conscious loaders because it avoids BIOS variation and gives exact control over CGA byte layout.
Inner Loop: 8x8 Font To CGA Bytes
Assume an 8x8 one-bit font where each row is one byte. For each set font bit,
the output pixel gets a two-bit CGA colour code:
font row bits: b7 b6 b5 b4 b3 b2 b1 b0
CGA byte 0: b7 b6 b5 b4 -> pixels x+0..x+3
CGA byte 1: b3 b2 b1 b0 -> pixels x+4..x+7
The expansion for one nibble is:
expand4(bits, colour):
out = 0
if bits & 8: out |= colour << 6
if bits & 4: out |= colour << 4
if bits & 2: out |= colour << 2
if bits & 1: out |= colour
return out
The direct version of the string routine is:
for each character ch in string:
fontp = font + ch * 8
dst0 = cga_offset(x, y)
for row in 0..7:
bits = fontp[row]
dst = dst0 + cga_row_delta(row)
dst[0] = expand4(bits >> 4, colour)
dst[1] = expand4(bits & 15, colour)
x += 8
In 8088-style assembly, the hot row loop can be implemented with a tiny lookup table instead of testing eight bits for every row:
; Input:
; DS:SI -> 8 font bytes for one character
; ES:DI -> destination byte for character's row 0
; BX -> expansion table for current colour, 512 bytes:
; table[bits*2+0] = high four pixels as CGA byte
; table[bits*2+1] = low four pixels as CGA byte
draw_char:
mov bp,8
.row:
lodsb
xor ah,ah
shl ax,1 ; two bytes per expanded font row
mov dx,[bx+ax] ; DL/DH are the two CGA bytes
mov es:[di],dx
; Advance to next visual scanline in CGA's split memory.
test di,2000h
jz .to_odd
sub di,2000h-80 ; odd row -> next even row
jmp .next
.to_odd:
add di,2000h ; even row -> next odd row
.next:
dec bp
jnz .row
ret
The important detail is the row advance. In a linear framebuffer the next
scanline would be +80. In CGA mode 4 the adjacent display line is in the
other half of the 16 KiB page, so the loop alternates:
even y -> odd y+1: +2000h
odd y -> even y+1: -2000h + 80
That is the classic CGA split-bank trap. Any renderer that ignores it produces two interleaved half-height images instead of the observed text rows.
Inner Loop: Expansion Table Builder
If the program wants three text colours, it can either build three tables or rebuild one table before each colour run. A compact builder for one colour is:
for bits in 0..255:
hi = bits >> 4
lo = bits & 15
table[bits*2 + 0] = expand4(hi, colour)
table[bits*2 + 1] = expand4(lo, colour)
The cost is 512 bytes per colour table. For three colours:
green table: 512 bytes
red table: 512 bytes
yellow table: 512 bytes
total: 1536 bytes
That is too much for a tiny cracktro if the font and strings are already small. A more size-oriented version would avoid the tables and spend cycles expanding bits directly:
expand_nibble:
; AL = four font bits in low nibble, BL = two-bit colour code
xor ah,ah
test al,8
jz @f
mov ah,bl
shl ah,6
@@:
test al,4
jz @f
mov dl,bl
shl dl,4
or ah,dl
@@:
test al,2
jz @f
mov dl,bl
shl dl,2
or ah,dl
@@:
test al,1
jz @f
or ah,bl
@@:
ret
For this screen, the table-free path is plausible because only roughly sixty characters are drawn. The CPU cost is invisible to the user: the page is static and rendered once.
Bottom Prompt And Keyboard Gate
The bottom line says Press <return> for Menu Screen, so the display path is
probably followed by a simple keyboard loop:
wait_return:
xor ah,ah
int 16h ; wait for key
cmp al,0dh
jne wait_return
After that the cracktro can hand control to the game menu:
; restore vectors / state if the loader changed them
; jump to original menu entry or execute original game file
The prompt is useful evidence because this is not merely a title card. It is a
gate in front of a still-accessible game/menu path, like the F1/F2 command
area in Battlezone Graffiti, but reduced to one return-key continuation.
Raw Page Alternative
A raw-page renderer would be trivial:
show_raw_page:
mov ax,0004h
int 10h
mov ax,0b800h
mov es,ax
mov ds,[page_segment]
xor si,si
xor di,di
mov cx,2000h
rep movsw
The problem is data size:
raw CGA page: 16,384 bytes
visible text: about 60 characters * 8 font bytes = about 480 font-row bytes
strings: well under 100 bytes
Even if the code carries its own font subset, string rendering is smaller. If it uses BIOS or ROM font access, the payload becomes smaller still. For a page this sparse, a raw copy only makes sense if the crack was embedded in a larger loader where simplicity mattered more than size, or if the page was stored in a general compressor shared with other assets.
Why This Still Belongs In The Early PC Timeline
Montezuma's Revenge Graffiti is visually plain, but technically it is a useful
data point in the Software Pirates Inc. line:
Sea Dragon Graffitiis likely text mode, built from B800h character cells.Battlezone Graffitiis a static 320x200 graphics page with function-key prompts.Big Top Graffitishows a richer title/high-score pair.Montezuma's Revenge Graffitireturns to the stripped-down form: four graphics-mode font strings, high-intensity CGA palette 0, and one return-key gate.
The interesting part is not a heavy effect; it is the economy of the artifact. The whole visible layer can be explained by:
int 10hmode setup and CGA palette selection.- A black-page clear.
- An
8x8graphics-font loop that knows CGA split-bank row stepping. - A BIOS keyboard wait for return.
- A handoff to the underlying game/menu screen.
That pattern is exactly the bridge between simple cracked-game splash pages and later PC intros: direct video memory, a tiny renderer, a key gate, and a group signature placed over a commercial-game entry path.