Ruben had offered to help with nibbling protected Commodore disks, so today he sent me a NIB file that he saved using my nibbling software for IECHost and his Commodore 1571 disk drive.
The protected game he nibbled is “Boulder Dash Construction Kit”, the Epyx/MAXX-OUT release. On Pete Rittwage’s website the title is listed as using Vorpal. It doesn’t say which Vorpal (Early or Later version) so I tried to look for hints in the drive code.
A first section of drive code is loaded into the disk drive’s RAM from sector 18/6 (“hidden” in the DIR track – track 18 – i.e. not allocated in the BAM) with a Block-Execute command:
; File "(c) 1987 epyx"
*=$0809
S0809 LDY #$0D ; Point to command at T0839, "#"
LDA #$F2 ; Secondary address (open channel 2)
JSR S0814
LDY #$00 ; Point to command at T082C, "B-E 2 0 18 6" (channel 2, drive 0, t/s 18/6)
LDA #$FF ; Secondary address (open channel 15)
S0814 PHA
LDA $BA
JSR $FFB1 ; LISTEN: command serial bus device to LISTEN
PLA
JSR $FF93 ; SECOND: send secondary address after LISTEN
B081E LDA T082C,Y
BEQ *+8
JSR $FFA8 ; CIOUT : output byte to serial bus
INY
BNE B081E
JMP $FFAE ; UNLSN : command serial bus device to UNLISTEN
T082C .text "B-E 2 0 18 6"
.byte $00
T0839 .text "#"
.byte $00
The drive code relocates itself to $0700 onward and executes the rest of the code at $0724:
DBOOT SEI
CLD
LDA #$08
STA $1800
LDA #$60 ; Code for RTS
STA $0300
JSR $0300 ; Execute a controlled JSR
TSX ; Retrieve the stack pointer
LDA $0100,X ; Find out in which page the sector was loaded...
STA $15
LDY #$00
STY $14
LDA ($14),Y ; ... and move contents to $0700-$07ff
STA $0700,Y
INY
BNE *-6
JMP $0724 ; Execute drive code
It then loads 4 pages worth of drive code using job queues, fetching them from “hidden” blocks in the DIR track:
B0724 LDX #$0E ; Set up 4 READ jobs
LDA T0745,X
STA $00,X
DEX
BPL *-6
CLI
LDA $00
ORA $01
ORA $02
ORA $03
BMI *-8
CMP #$01 ; Repeat until successful
BNE B0724
LDA #$00
STA $1800
JMP $0403 ; Execute drive code
T0745 .byte $80,$80,$80,$80,$00,$00 ; Request 4 READ jobs
.byte $12,$09 ; t/s 18/9
.byte $12,$0C ; t/s 18/12
.byte $12,$0F ; t/2 18/15
.byte $12,$12 ; t/s 18/18
The rather interesting thing is that Vorpal code is showing up inside these 4 pages of drive code but some of it doesn’t appear to be executed, at least not until the point I load a cave file:
What follows is the Vorpal code that checks for pre-sync bytes and for the length of 17 header and data blocks in track 20. It is perhaps the first time it’s published on the Web (although I might not be aware of other published code). However, it doesn’t appear to be executed.
V0753 SEI
JSR S0796 ; Step to track 19
JSR S0796 ; Step to track 20
LDA $1C00
AND #$9F
ORA #$40
STA $1C00
LDA $1C0C
ORA #$0E
STA $1C0C
JSR B07D7 ; Get past t/s 20/0's track value in header block
LDA #$11 ; 17 sectors to check (1..17)
STA $08
JSR S07BA ; Skip the check on sector 0 data block
B0776 JSR S07BA ; Measure header block size (GCR bytes) and read pre-sync value
CMP #$AF ; Pre-sync value expected for header block
BNE B0793
CPY #$11 ; Number of GCR bytes expected in header block before pre-sync
BNE B0793 ; e.g. for sector 1: 52,56,F5,2D,6E,9A,A6,A5,55,55,AA,AA,AA,AA,AA,AA,AA,AF,FF,FF,FF,FF,FF
JSR S07BA ; Measure data block size (GCR bytes) and read pre-sync value
CMP #$FF ; Pre-sync value expected for data block
BNE B0793
CPY #$4D ; LSB of number of GCR bytes expected in data block before pre-sync (333 = $014D -> LSB = $4D)
BNE B0793
DEC $08 ; One less check to do
BNE B0776 ; All 17 sectors done?
JMP $0403 ; Success
B0793 JMP $EAA0 ; Protection check failed
; Step to next track
S0796 LDX #$02
B0798 LDY $1C00
INY
TYA
EOR $1C00
AND #$03
EOR $1C00
STA $1C00
LDY #$0A
LDA #$C7
SEC
SBC #$01
BCS *-2
DEY
BNE *-8
DEX
BNE B0798
INC $22 ; Current track++
RTS
; Return the number of GCR bytes before the next sync in Y and the pre-sync value in A
S07BA CLV
BVC *+0
CLV
LDY #$00
J07C0 LDX $1C00
BPL B07CF
BVC J07C0
CLV
LDA $1C01
INY
JMP J07C0
B07CF BVC *+7
LDA $1C01
CLV
INY
RTS
; Position the read head in the middle of the header block for t/s 20/0
B07D7 JSR S07EA
B07DA BVC B07DA
CLV
LDA $1C01
CMP T07F6,Y
BNE B07D7
INY
CPY #$05
BNE B07DA
S07EA BIT $1C00
BMI S07EA
LDA $1C01
CLV
LDY #$00
RTS
; GCR values of the first 4 bytes (ID, checksum, sector, track) of the header block at t/s 20/0
; %01010,01001,01011,01110,01010,01010,01011,01110 = $08,$14,$00,$14 -> t/s 20/0
T07F6 .byte $52,$56,$E5,$29,$6E
The way I tested that this code is not executed is by using breakpoints, but also by altering the pre-sync byte in t/s 20/1 from:
52,56,F5,2D,6E,9A,A6,A5,55,55,AA,AA,AA,AA,AA,AA,AA,AF,FF,FF,FF,FF,FF
To:
52,56,F5,2D,6E,9A,A6,A5,55,55,AA,AA,AA,AA,AA,AA,AA,AA,FF,FF,FF,FF,FF
Even after the alteration, I was still able to edit a cave file without problems.
Is it possible that the above Vorpal code is executed later on? Perhaps when saving work to disk? I shall find out next time as it’s already half past midnight now 🙂
Stay tuned for more!