Captain Bible Reverse Engineering

De FreeDOS/QEMU-omgeving en de geplande statische en dynamische analyse zijn voltooid. De bronnen voor de twee gepubliceerde boeken bevinden zich onder docs/ en spec/. Raadpleeg PLAN.md voor de actuele checklist en docs/src/progress-log.md voor het volledige activiteitenlogboek.

Documentatie

  • Reverse-engineering documentatie: Legt het onderzoeksproces, bewijsmateriaal, herstelde formaten, analyse van uitvoerbare bestanden en de projectvoortgang vast.
  • Clean-room engine specificatie: Definieert de gamemechanieken en het portable compatibiliteitscontract voor het implementeren van een engine zonder afhankelijk te zijn van de internals van het DOS-programma.

Vereisten

Voor dit project zijn de volgende tools nodig:

  • QEMU met qemu-system-i386 en qemu-img
  • mtools (mformat, mcopy, mmd, mdir en mtype)
  • unzip
  • Python 3
  • Pillow (voor ART/PAL rendering)
  • Een C-compiler, pkg-config en GLib development headers voor DOS tracing
  • Een POSIX shell
  • mdBook (voor de onderzoeks- en specificatieboeken)
  • Rizin (voor het meegeleverde symbol-script en verdere disassembly)
  • Een actuele stabiele Rust toolchain, SDL3 en pkg-config (voor de clean-room engine)

De setup is ontwikkeld en getest met QEMU 11.0.2 en mdBook 0.5.3 op macOS/Apple Silicon.

De game uitvoeren

Voer vanuit de root van de repository het volgende uit:

./run.sh

Het script opent QEMU en start Captain Bible automatisch. Bij de eerste uitvoering wordt een persistent play-image aangemaakt op build/captain-bible/captain-bible.img. Opgeslagen spellen worden naar dit image geschreven en blijven beschikbaar bij latere runs.

Op macOS gebruikt de game de zichtbare Cocoa-display van QEMU met zoom-to-fit=on. Voordat QEMU opent, print het script zowel de bestandsnaam van het host-image als het guest-pad C:\CBDOME\CB.EXE.

De game ondersteunt zowel muis- als toetsenbordinput. Als QEMU de cursor vastlegt (capture), gebruik dan Control-Option-G om deze op macOS vrij te geven. Sluit de game via het Escape-menu voordat u QEMU afsluit, zodat lopende schrijfacties van saves netjes worden voltooid.

QEMU presenteert Sound Blaster 16 en AdLib-hardware aan de game, maar maakt gebruik van de stille none audio backend. Het Cocoa-venster blijft zichtbaar terwijl het game-geluid op de host wordt onderdrukt.

Aanvullende opties voor run.sh

  • Images voorbereiden of controleren zonder QEMU te openen:

``bash ./run.sh --setup-only ``

  • Het play-image opnieuw maken vanuit de huidige CB/ directory:

``bash ./run.sh --rebuild ` Let op: --rebuild` vervangt het persistente play-image en reset hiermee alle opgeslagen spellen die alleen daarin staan.

  • Deterministische vergelijkingen (RNG-aligned) tussen DOS en Rust:

Voor actie-voor-actie vergelijkingen tegen dezelfde gamedata en save state, start DOS met een unsigned 16-bit initiële staat: ``bash ./run.sh --rng-seed 1 ` De launcher reconstrueert een gepatcht uitvoerbaar bestand onder build/, plaatst dit in een unieke tijdelijke kloon van het play-image, verifieert de guest-kopie en draait de kloon met QEMU snapshot writes. Het wijzigt nooit CB/CB.EXE. Zodra het normale play-image bestaat, blijven deterministische runs deze ongewijzigd, tenzij --rebuild` expliciet wordt aangevraagd.

De normale launch verwijdert de per-run kloon na het afsluiten van QEMU; --setup-only behoudt de geprinte directory voor inspectie.

Rust engine

De clean-room native implementatie bevindt zich in rust-engine. Deze maakt gebruik van dezelfde originele CB/ datadirectory en bevat een engine core (alleen standaardbibliotheken) plus terminal- en SDL3-frontends. SDL3 en pkg-config zijn harde build-vereisten.

Valideer de volledige meegeleverde resource-set en start de standaard SDL3-frontend met:

cd rust-engine
cargo run --release -- --data ../CB --validate
cargo run --release -- --data ../CB
cargo run --release -- --data ../CB --rng-seed 1

Gebruik --headless voor de terminal of deterministische tick frontend. Raadpleeg de README van de engine voor SDL3-setup, besturing, deterministische smoke runs, tekstexport, tests en huidige beperkingen van de host-frontend.

FreeDOS opnieuw opbouwen

Het basis image van het besturingssysteem wordt non-interactief geconstrueerd vanuit de officiële FreeDOS 1.4 LiteUSB distributie:

tools/setup_freedos_image.py

Het resultaat is build/freedos/freedos.img. De builder verifieert de gepubliceerde SHA-256, behoudt de bronbootcode, construeert een nieuwe FAT16-partitie en kopieert het FreeDOS-bestandssysteem met mtools. Het voert de FreeDOS-installer niet uit of automatiseert deze niet.

Het huidige workspace image bevat ook de volledige game op C:\CBDOME, toegevoegd nadat het basis image was gebouwd. Als u dat image direct boot, voer dan uit:

CD \CBDOME
CB

Het opnieuw opbouwen van het basis image verwijdert die handmatige game-kopie. Het uitvoeren van ./run.sh zal echter nog steeds automatisch het aparte play-image (met de game) aanmaken of gebruiken.

Voer de gefocuste unit tests uit met:

python3 -m unittest discover -s tests -v

Analyse van het uitvoerbare bestand

CB.EXE is een 16-bit MZ-uitvoerbaar bestand dat is gecomprimeerd met Microsoft EXEPACK. Genereer het onafhankelijk geverifieerde uitgepakte uitvoerbare bestand en vergelijk dit, indien de geregistreerde QEMU-dump aanwezig is, met het verplaatste procesimage:

tools/analyze_cb_exe.py CB/CB.EXE \
--output build/analysis/CB_UNPACKED.EXE \
--memory-dump build/dumps/title-physical-1m.bin \
--load-segment 0x627

Laad de huidige high-confidence namen in Rizin met:

rizin -b 16 -i analysis/cb.rz build/analysis/CB_UNPACKED.EXE

Controleer alle 140 benoemde functies, 134 verschillende BIN-handlers en 9 datasymbolen tegen het Rizin-script, met per item confidence en bewijs, via:

tools/inspect_symbol_map.py

Vergelijk onafhankelijk alle 145 opcode dispatch-items en operand-reader paden met de decoder, alle 134 verschillende handler-symbolen en alle 25.829 meegeleverde commando's via:

tools/audit_bin_opcodes.py

Het gecontroleerde resultaat per opcode staat in analysis/opcode-audit.tsv.

Gegenereerde uitvoerbare bestanden en memory dumps blijven in de genegeerde build/ map staan. Onderzoeksresultaten, adresconventies, functienamen, command-line gedrag en de herstelde save-layout bevinden zich in de mdBook-bronnen.

Inspecteer de geïnstalleerde Miles AIL/MIDPAK OPL timbre library met:

tools/inspect_midpak_ad.py CB/SOUND.4
tools/inspect_midpak_ad.py CB/SOUND.4 --list

Het hoofdstuk over sound-drivers brengt alle 34 game-side int 66h sites en de DIGPAK- en MIDPAK service contracts in kaart. ./run.sh --trace-dos registreert zowel DOS int 21h als driver int 66h calls en returns, terwijl het Cocoa-venster zichtbaar blijft en host-audio is gedempt.

DD1.DAT extraheren

Het hoofd resource-archief heeft een hersteld directory-formaat van 24 bytes en custom LZW-familie compressie. Lijst of extraheer de 369 leden met:

tools/extract_dd1.py --list CB/DD1.DAT
tools/extract_dd1.py \
--extract RUN.ART \
--output build/dd1/RUN.ART \
CB/DD1.DAT
tools/extract_dd1.py --extract-all build/dd1/all CB/DD1.DAT

De output van alle leden wordt geprefixed met elke directory-index, zodat herhaalde archiefnamen onderscheidbaar blijven. De extractor valideert de directory, payload magic, compressed stream, expanded size en exact inputverbruik. Formaatdetails en de corresponderende executable routines staan in het DD1.DAT-hoofdstuk van mdBook.

Artwork renderen

Geëxtraheerde ART-resources bevatten 12-byte frame descriptors gevolgd door row-major eight-bit pixels. Hun kleuren komen uit aparte 768-byte VGA PAL resources. Inspecteer of render ze met:

tools/render_art.py build/dd1/all/003_LOGO.ART --list
tools/render_art.py \
build/dd1/all/002_LOGO.PAL \
--canvas --scale 2 \
--output build/graphics/logo.png

De renderer kan ook één frame schrijven met --frame of elk frame met --all-frames. Palette index 0 is standaard transparant voor sprite previews; gebruik --opaque-zero bij het reproduceren van een opaque draw. Het graphics-hoofdstuk in mdBook documenteert het formaat en de byte-voor-byte correlatie met QEMU VGA-geheugen.

Genereer een geannoteerd contactvel van elk full-screen ART frame, waarbij PAL-associaties worden afgeleid uit de scene programs:

tools/render_fullscreen_gallery.py \
CB/DD1.DAT \
--output build/graphics/full-screen-gallery.png

Gebruik --scale 2 voor een vergroot sheet via nearest-neighbor.

Scene bytecode inspecteren

De 62 geëxtraheerde BIN-resources bevatten scene programs. De herstelde decoder kent de operand layout en dispatch effect van alle 145 opcodes. Het wijst semantische namen toe aan elke waarde, inclusief conservatieve low-level namen voor de 23 waarden die ontbreken in de meegeleverde scripts:

tools/inspect_bin.py build/dd1/all/005_INTRO.BIN
tools/inspect_bin.py build/dd1/all/001_LOGO.BIN --objects
tools/inspect_bin.py build/dd1/all/327_BOSS.BIN --choices
tools/inspect_bin.py \
build/dd1/all/337_COMBAT7.BIN --animations --actions
tools/inspect_bin.py \
build/dd1/all/334_ROOM3.BIN --start 0x0c96 --limit 0x1754

De meeste resources zijn van begin tot eind code. CP2.BIN heeft een data-trailer, en ROOM3.BIN heeft drie command-regio's gescheiden door nul-gevulde reserved blocks; deze regio's vereisen expliciete --start en --limit waarden. Het scene-bytecode hoofdstuk in mdBook beschrijft de interpreter, het command schema, de startup sequentie, QEMU-geheugencorrelatie en de volledige opcode catalogus. Het registreert ook de gecorrigeerde two-word layout van opcode 0x69, wat 11 fantoomcommando's uit het lineaire corpus verwijdert, en de onafhankelijke executable-CFG audit van elk gedeclareerd operand pad.

  • --objects view: Vat de display records samen in lineaire commandvolgorde, inclusief thread/animatie types en coördinaten, schaal, flags, frame en ART slot van directe objecten. Zie het scene-display-object hoofdstuk voor de live ten-byte layout en control-flow caveat.
  • --choices view: Lijst dialogue-choice source offsets, absolute branch targets en inline tekst. Zie het conversation-flow hoofdstuk voor de six-byte runtime table, studiebijbel-integratie en live QEMU correlatie.
  • --animations view: Groepeert elke animatieheader met zijn aaneengesloten nine-byte steps.
  • --actions view: Lijst schermcoördinaten, absolute targets, selectors en herstelde combat- en hall-action labels.

Het combat-runtime hoofdstuk documenteert hun runtime tables, BIN scheduler, action outcome branches, faith effects, de gedeelde victory/retreat epiloog en map transitions.

Patch beide scene-name velden — en indien nodig beide coördinaatkopieën — in een tijdelijke 2.752-byte state voor gecontroleerde scene-entry experimenten, en vergelijk vervolgens een physical-memory capture met de BIN-definities via:

tools/patch_save_scene.py input.SVQ COMBAT1 output.SVQ
tools/patch_save_scene.py input.SVQ ROOM3 output.SVQ --coordinate 13 6
tools/inspect_runtime_tables.py memory.bin \
--data-segment 0x14e1 \
--bin build/dd1/all/343_COMBAT1.BIN

Zonder --coordinate wijzigt de patcher alleen de twee opgeslagen 20-byte scene-name velden. De optionele coördinaten vervangen variabelen 11 en 12 in zowel het checkpoint als de live variable blocks. Gebruik dit alleen op research kopieën. De runtime inspector decodeert de getelde action- en animation tables plus tien BIN-thread records. Met --bin vergelijkt het de action targets en animation definition velden met de statische command stream.

CP2.BIN eindigt met de complete 16-node Unibot navigatiegraaf. Inspecteer de vier richtingsuitgangen, zeven pylon nodes, Tower, rechtsonder-map coördinaten en per-node transitiewaarden met:

tools/inspect_unibot.py build/dd1/all/315_CP2.BIN

Het Unibot and endgame hoofdstuk volgt de zeven rescue boarding gate via alle pylon encounters, het eenmalige Annoy Cyber event, de Tower gate en de succesvolle en gefaalde ending chains.

Audio resources inspecteren

De 41 ABT-leden zijn gecomprimeerde 9.000 Hz unsigned eight-bit mono geluidseffecten. Inspecteer er één of converteer het naar een standaard WAV-bestand met:

tools/convert_abt.py build/dd1/all/306_D003.ABT
tools/convert_abt.py \
build/dd1/all/306_D003.ABT \
--output build/audio/d003.wav

De 32 XMI-leden zijn one-sequence IFF/XMIDI muziek resources. Valideer en vat hun containers, timbres en event streams samen met:

tools/inspect_xmi.py build/dd1/all/267_MUS001.XMI

Game tekst inspecteren

De extensieloze resources in DD1.DAT bevatten vertalingsspecifieke vers-indexen. Deze vormen een paar met de DDLA tot DDLR bestanden die leugens, parafrases, vragen, uitleg en conversaties bevatten. Inspecteer een gecombineerd record met:

tools/inspect_text_resources.py \
CB/DD1.DAT --data-dir CB \
--translation N --bank A --record 0

Vertalingen zijn K, N, R en T; banks zijn A t/m G en R. Het text-format hoofdstuk in mdBook documenteert zowel de binaire layouts als hun validatie tegen de ingebouwde study-file exporter van de game.

Beide tools wijzen structurele inconsistenties af en consumeren hun inputs exact. Het audio-hoofdstuk in mdBook documenteert de formaten, de executable decoder en een byte-voor-byte vergelijking tussen host-decoded D003.ABT en zijn live QEMU PCM buffer.

Opgeslagen spellen inspecteren

Elk spelersprefix heeft een 243-byte .SV0 label index, negen normale state bestanden en een aparte .SVQ quick save. Inspecteer elk vast formaat met:

tools/inspect_save.py CB/DDGAMES.SV0
tools/inspect_save.py CB/DDGAMES.SV3 --descriptors
tools/inspect_save.py CB/DDGAMES.SV9 --variables

De inspector valideert exacte formaten, decodeert de negen vaste C-string label buffers, scheidt live en checkpoint state blocks en exposeert de opgeslagen instellingen en tekstdescriptors. Het save-format hoofdstuk in mdBook documenteert de 2.752-byte state layout, spelersprefix-gedrag, quick-save suffix wijzigingen, snapshot kopieren, foutgedrag en bewijsmateriaal van alle meegeleverde saves.

De --variables view decodeert de 100 signed script words, benoemde map- en faith fields, de ingebedde 128-bit flag bank, powerups and victim-rescue flags.

Wereldkaarten inspecteren

Het archief bevat 21 wereldkaarten: levels A t/m G op Easy, Normal en Difficult instellingen. Elke kaart is een row-major 16×16 grid van drie-byte mutable cells. Toon het location-kind grid en optioneel de nonzero cellen:

tools/inspect_map.py CB/DD1.DAT --map CE
tools/inspect_map.py CB/DD1.DAT --map CE --cells
tools/inspect_map.py CB/DD1.DAT --map CE --rooms
tools/inspect_map.py CB/DD1.DAT --map CE --hall-features
  • Cell view: Benoemt de vier verbindingsrichtingen.
  • Room view: Decodeert de vijf room classes (Victim, Trap, Prayer, Communications en Jump Tunnel), samen met de ingangszijde en mutable parameters van elke kamer.
  • Hall-feature view: Identificeert de zeven Cyber types, verborgen Spider triggers, Scripture stations, geklaarde encounters en level exits, terwijl onopgeloste omgevingsstaten onbenoemd blijven.

Vergelijk een originele kaart met het live grid dat is geserialiseerd in een save:

tools/inspect_map.py \
CB/DD1.DAT --map CE --compare-save CB/DDGAMES.SV3

Het world-map hoofdstuk in mdBook documenteert resource naming, cell addressing, packed fields, room dispatch en orientation encoding, scene commands, hallway entities en transitions, exploration bits, map-screen gedrag en de byte-level identificatie van meegeleverde save grids.

QEMU DOS-call tracing

Run de game met de QEMU TCG tracer en monitor socket ingeschakeld:

./run.sh --trace-dos

Het Cocoa-venster blijft zichtbaar en host-audio blijft gedempt. De trace mode gebruikt één guest instructie per TCG translation block, zodat registerwaarden bemonsterd kunnen worden bij DOS- en driver interrupt grenzen; het is daardoor langzamer dan een normale run. De gegenereerde plugin, trace, monitor socket, screenshots en memory dumps worden bewaard in de genegeerde build/qemu-trace/ directory.

De trace activeert bij het gereconstrueerde entry point 0627:CB5C en registreert BIOS keyboard int 16h, DOS int 21h, mouse int 33h en sound-driver int 66h calls en returns vanuit code segment 0627, inclusief live AX en de andere argument/result registers. Deze adressen zijn stabiel voor het huidige deterministische FreeDOS image. Als de DOS-omgeving of bootconfiguratie wijzigt, moet het load segment opnieuw worden vastgesteld voordat u op het filter vertrouwt.

Documentatie

Voer de documentatie integriteitscontrole uit en bouw beide boeken met:

tools/check_documentation.py
mdbook build docs
mdbook build spec

De checker valideert SUMMARY dekking, lokale hoofdstuklinks en anchors, en repository commando's gebruikt in shell-voorbeelden in beide boeken. Het hoofdstuk Reproducing the Results in het onderzoeksboek geeft een enkele end-to-end command sequentie voor elk hersteld formaat en systeem. Known Gaps and Evidence Boundaries scheidt bevestigde resultaten van opzettelijk onbenoemde velden en de limieten van gecontroleerde scene-entry captures.

Het gerenderde boek wordt geschreven naar docs/book/. Een aangepast stylesheet verwijdert de vaste 750-pixel inhoudslimiet van mdBook, zodat tabellen en disassembly listings de volledige browserbreedte gebruiken.

De clean-room specificatie is geschreven naar spec/book/. De bron begint bij spec/src/SUMMARY.md en is georganiseerd als een implementatiecontract: spelermechanieken, lifecycle en input, elk resource formaat, alle 145 scene opcodes, runtime services, maps, dialoog, combat, progressie en het endgame, saves, configuratie, conformiteitstests en expliciet begrensde ongespecificeerde details.

Pushes naar main die het onderzoeksboek of de publicatieworkflow wijzigen, bouwen en publiceren de output via GitHub Actions. De specificatie blijft een aparte lokale build. De workflow kan ook handmatig worden gestart vanuit het Actions-tabblad. Het installeert de geteste mdBook 0.5.3 Linux binary, verifieert de SHA-256, uploadt docs/book/ als Pages artifact en deployt dit naar: https://peterkelly.github.io/captain-bible-re/