Difference between revisions of "GMA86"

From Software Archive
Jump to navigation Jump to search
Line 39: Line 39:
 
title uses:
 
title uses:
  
# '''Track 38''' (<code>$26</code>) — '''C64-side bulk decrypt.''' The
+
# '''Track 38''' (<code>$26</code>) — '''C64-side bulk decrypt.'''
   measured byte is sent to the C64 over a raster-synced <code>$DD00</code>
+
   The measured byte is sent to the C64 over a raster-synced <code>$DD00</code>
 
   handshake and used as a single repeating-byte XOR key over almost the
 
   handshake and used as a single repeating-byte XOR key over almost the
 
   entire game, decrypted in place in one pass before jumping straight into
 
   entire game, decrypted in place in one pass before jumping straight into

Revision as of 02:52, 28 August 2026

Pages that refer to this protection

GMA86

GMA86 is a Commodore 64 disk copy protection scheme spanning a run of 1986 releases from Firebird, Domark, Alligata, Hewson, Robtek, Thalamus and others, and the middle generation of the "GMA" protection family — successor to GMA85, predecessor to GMA87. It shares that family's naming convention: each disk's BAM label carries a build-date stamp (gma<DDMMYY>, e.g. gma140486 = 14 Apr 1986 for Robin of the Wood), and the loader chain keeps the same file-naming pattern used throughout the family (a boot stub → gm1/gma1 second-stage loader → game data files).

Where GMA85 never derives a key at all, and GMA87's surveyed titles converge on one architecture (a C64-side bulk decrypt, with Eagles as a single confirmed drive-side exception), GMA86 is the generation where a real, disk-specific decryption key first becomes the norm — but it is not architecturally uniform. Of eleven surveyed titles, seven use a C64-side bulk decrypt, three use a drive-side per-sector decrypt otherwise thought unique to Eagles, and one carries the ancestral GMA85 presence-only check forward unchanged, with no key at all. All three mechanisms share the exact same underlying drive-upload plumbing and sync-length measurement primitive; what differs is only what happens to the measured byte afterward, and which out-of-range track it's read from.

Mechanism

Every GMA86 title uploads a short machine-code program to the 1541's own drive RAM over the serial bus (the standard DOS M-W/M-E commands), and has the drive itself seek an out-of-range track, search for the family's standard byte-aligned marker (69 xx xx xx A9, not decoded to the usual 5-bit GCR nibble boundaries), and — for two of the three mechanisms below — measure ten raw sync-to-sync pulse-width samples there, folding them into a single byte via the same CMP/ROL technique documented for GMA87's Cholo and Triaxos. Which out-of-range track is targeted correlates exactly with which of the three mechanisms a given title uses:

  1. Track 38 ($26) — C64-side bulk decrypt.
 The measured byte is sent to the C64 over a raster-synced $DD00
 handshake and used as a single repeating-byte XOR key over almost the
 entire game, decrypted in place in one pass before jumping straight into
 the result. Seven of eleven surveyed titles: Sanxion, Split Personalities,
 Cyrus II Chess, The Sentry, Filemaster 64, Pub Games, and The Graphic
 Adventure Creator.
  1. Track 39 ($27) — drive-side per-sector decrypt.
 The measured byte is instead baked as a literal EOR #imm
 operand into a second, freshly-uploaded drive-resident program, and the
 1541's own 6502 decrypts every subsequent sector before it ever reaches
 the C64, streaming the result out over a bit-banged serial link one byte
 at a time. Three of eleven surveyed titles, all Hewson-published: Firelord,
 Uridium, and Iridis Alpha — matching GMA87's Eagles almost byte-for-byte,
 including the identical $035C/$035D
 key-injection address.
  1. Track 37 ($25) — presence-only, no key. The
 drive reads two raw 256-byte blocks off the track and reports success
 unconditionally; nothing is ever folded, compared, or sent. This is the
 ancestral GMA85 mechanism, carried forward unmodified. One of eleven
 surveyed titles: Robin of the Wood, whose disk-label date
 (gma140486) places it firmly within the GMA86 era despite
 running GMA85-generation drive code.

On any genuine failure — marker not found within the retry budget, or a failed job status — the drive hangs permanently in an infinite self-loop rather than reporting an error the C64 could act on, the same "hang, never produce wrong output" convention used throughout the whole GMA family.

Signature measurement: the shared drive-side routine

Confirmed byte-for-byte identical (Firelord, Uridium, Iridis Alpha) or structurally identical down to the exact same offsets (the C64-side titles, confirmed point-by-point against Cholo's own upload routine) to the mechanism already documented in detail for GMA87. The only things that vary between tracks 38 and 39 are the literal target-track constant and, for the drive-side variant, what happens to the result afterward (see below):

; ---- sync-marker search, 90-attempt retry budget ----
$0300  AD 00 1C    LDA $1C00
$0303  29 9F       AND #$9F
$0305  8D 00 1C    STA $1C00
$0308  A0 5A       LDY #$5A            ; Y = 90 - sync-retry budget
$030A  88          DEY                 ; <-- retry entry point
$030B  D0 05       BNE $0312
$030D  A9 02       LDA #$02            ; error $02 = HEADER NOT FOUND
$030F  4C 69 F9    JMP $F969           ; ERRR - retries exhausted, report failure
$0312  2C 00 1C    BIT $1C00
$0315  30 FB       BMI $0312           ; sync-wait poll
$0317  AD 01 1C    LDA $1C01           ; discard first raw byte after sync
$031A  B8          CLV
$031B  A2 04       LDX #$04
$031D  50 FE       BVC $031D           ; CLV/BVC byte-ready wait (classic 1541 trick)
$031F  B8          CLV
$0320  AD 01 1C    LDA $1C01           ; read raw GCR byte
$0323  9D 00 05    STA $0500,X         ; store into $0500-$0504 (5 bytes)
$0326  CA          DEX
$0327  10 F4       BPL $031D
$0329  C9 A9       CMP #$A9            ; last byte read must be $A9
$032B  D0 DD       BNE $030A           ; mismatch -> retry
$032D  AD 04 05    LDA $0504           ; first byte read (2nd overall)
$0330  C9 69       CMP #$69            ; must be $69
$0332  D0 D6       BNE $030A           ; mismatch -> retry
                                        ; signature "69 xx xx xx A9" confirmed

; ---- 10-sample raw pulse-width (sync-length) measurement ----
$0334  A0 00       LDY #$00
$0336  2C 00 1C    BIT $1C00
$0339  30 FB       BMI $0336           ; wait for next sync
$033B  A2 00       LDX #$00
$033D  E8          INX                 ; <-- pulse-width measurement loop
$033E  2C 00 1C    BIT $1C00
$0341  10 FA       BPL $033D           ; count iterations (X) while bit7=0
$0343  8A          TXA
$0344  99 00 05    STA $0500,Y         ; store sample[Y]
$0347  C8          INY
$0348  C0 0A       CPY #$0A            ; 10 samples total
$034A  D0 EA       BNE $0336

; ---- fold 10 samples into an 8-bit result via CMP/ROL ----
$034C  A2 02       LDX #$02            ; sample[0] discarded, sample[1] = reference
$034E  BD 00 05    LDA $0500,X
$0351  CD 01 05    CMP $0501           ; compare sample[X] to reference
$0354  2E 0A 05    ROL $050A           ; roll carry (>=ref->1, <ref->0) into result byte
$0357  E8          INX
$0358  E0 0A       CPX #$0A            ; samples[2..9], 8 comparisons -> 8-bit result
$035A  D0 F2       BNE $034E
$035C  AE 0A 05    LDX $050A           ; X = computed 8-bit sync-length result

; ---- job setup: target track, submit EXECUTE job, check result ----
        LDA #<track>                   ; $26 (38) for the C64-side variant,
        STA $06                        ;   $27 (39) for the drive-side variant
        ...
        JMP <infinite self-loop>       ; on failure status - hang forever

The remainder — how the result byte is used — is where the three GMA86 mechanisms diverge.

Variant A: C64-side bulk decrypt

The measured byte is sent to the C64 the same way GMA87's Cholo/Triaxos do it: a raster-line-synced read of CIA2's $DD00, decoded through a small set of fixed lookup tables, landing in A at the return of a hijacked GETIN vector. The main loader stashes it (PHA) immediately after the upload-and-execute call, recovers it later (PLA/TAX), and feeds it into a self-modifying XOR loop that walks upward through memory decrypting the game in place before jumping straight into the result — confirmed byte-for-byte structurally identical (just different target addresses and end-page constants) across all seven C64-side titles.

The Graphic Adventure Creator's build (target track $26 = 38, confirmed directly) is the cleanest captured example:

$401F  JSR $C800     ; the fixed drive-upload-and-execute trigger
$4022  PHA           ; stash the measured key
$4023  LDA #$00 / JSR $42AB
$4028  PLA           ; recover it
$4029  TAX           ; X = $C3 (this disk's measured key)
$402A  LDA $01 / PHA / AND #$FE / STA $01   ; bank out BASIC ROM
$4031  TXA / EOR $C900 / STA $C900          ; self-modifying decrypt
$4038  INC $4033 / INC $4036 / BNE $4031
$4040  INC $4034 / INC $4037
       LDA $4034 / CMP #$C9 / BNE $4031
$404D  PLA / STA $01                        ; restore memory config
$4050  ...                                  ; standard KERNAL cold-start-ish sequence

Variant B: drive-side per-sector decrypt

Firelord, Uridium, and Iridis Alpha instead move the decrypt onto the 1541 itself, matching GMA87's Eagles almost line-for-line: once the signature measurement above completes, a second program is uploaded into drive RAM, overwriting the first. It contains a GCR sector-read loop, the standard DOS ROM's own GCRBIN/CHKBLK header-verification calls, and — at the identical $035C/$035D address in every confirmed example — the measured byte baked directly in as an EOR #imm immediate operand, decrypting each data byte as it's read and streaming the already-decrypted result to the C64 over the bit-banged serial link. Confirmed live for Uridium (measured key $97):

$0359  BD 00 06    LDA $0600,Y   ; raw (still-encrypted) byte off the sector buffer
$035C  49 97       EOR #$97      ; the measured sync-length byte, baked in as a
                                  ;   literal immediate operand at upload time
$035E  AA          TAX           ; decrypted byte ready to send/store
       ...

Because the key is injected directly into freshly-uploaded drive code rather than sent as data, a hunt for EOR #<key> (49 xx) across drive RAM after the upload reliably locates this instruction — the same technique used to confirm all three drive-side titles here and Eagles in GMA87. All three drive-side GMA86 titles are Hewson-published, matching Eagles' own publisher; the C64-side titles found in this survey are Domark, Alligata, Firebird, Ariolasoft, Robtek, and Thalamus releases — a suggestive publisher-level correlation, though not established as a rule (Firelord's own publisher wasn't independently confirmed, and no non-Hewson drive-side counterexample was specifically sought).

Variant C: presence-only, no key

Robin of the Wood's disk-label date places it within the GMA86 era, but its drive-side program is confirmed byte-for-byte identical to the GMA85 generation's: target track 37, two raw 256-byte blocks read and discarded, success reported unconditionally. Confirmed experimentally by corrupting the track's surrounding "salt" bytes while preserving the marker — no change in behavior. No sync-length measurement of any kind occurs on this title's out-of-range track. See GMA85 for the full annotated disassembly of this mechanism, including the C64-side loader's $02/EOR #$97 check some (but not all) titles of that generation carry — a plausible code-integrity tripwire against a patched-out upload call, not a disk-content validation, and not specific to Robin of the Wood; it belongs to the inherited GMA85 loader, not to anything introduced in GMA86.

Relationship to GMA85 and GMA87

GMA86 sits directly between the two: it inherits GMA85's presence-only mechanism wholesale (still shipping on at least one GMA86-labeled title), and it establishes — a full year before GMA87 — both real-key architectures GMA87 titles use, including the drive-side variant later found in Eagles and, until this survey, thought to be an isolated architectural outlier within the whole GMA family. It isn't: the drive-side decrypt is an established technique in this author's toolkit that predates Eagles by at least a year, reused essentially unchanged.

See also