GFL Championship Football (Activision/Gamestar) V-Max V0 V-Max loader is in two sectors on track 18, then loads the rest from track 1 using the drive's job queue. There are 3 sectors of drive code on track 1 that are encrypted: t/s 1/14 (stored in buffer $0400) t/s 1/17 (stored in buffer $0500) t/s 1/4 (stored in buffer $0600) The decryption key is built by performing a checksum of $94 bytes starting at the sector header. This includes the header gap bytes and the byte before/after the data-block sync, which software nibblers will not copy. This is repeated for 4 sectors, building a 4-byte key. Key returned by protection check: 63 B6 18 41 Protection code: (this code is loaded from track 1, sector 7) .8:0300 A9 05 LDA #$05 .8:0302 8D 4D 01 STA $014D ; up to 5 retries allowed .8:0305 A9 02 LDA #$02 .8:0307 85 00 STA $00 .8:0309 78 SEI ; Disable interrupts .8:030a A2 05 LDX #$05 .8:030c BD 8F 03 LDA $038F,X .8:030f 95 08 STA $08,X ; populate the job queue with the encrypted sectors to read (see $38F below) .8:0311 CA DEX .8:0312 10 F8 BPL $030C .8:0314 E8 INX .8:0315 A9 80 LDA #$80 .8:0317 95 01 STA $01,X ; issue sector read command .8:0319 58 CLI ; enable interrupts so job queue can process .8:031a B5 01 LDA $01,X .8:031c 30 FC BMI $031A ; wait for job to finish .8:031e C9 01 CMP #$01 .8:0320 F0 0A BEQ $032C ; check for successful result and branch .8:0322 A9 C0 LDA #$C0 .8:0324 95 01 STA $01,X ; ..otherwise bump the head .8:0326 B5 01 LDA $01,X .8:0328 30 FC BMI $0326 .8:032a 10 E9 BPL $0315 ; ..and read the sector again .8:032c E8 INX .8:032d E0 03 CPX #$03 ; read 3 sectors .8:032f 90 E4 BCC $0315 .8:0331 A9 00 LDA #$00 .8:0333 85 05 STA $05 ; initialize error count variable to 0 .8:0335 20 95 03 JSR $0395 ; call protection check / get decrypt key .8:0338 A5 05 LDA $05 .8:033a F0 08 BEQ $0344 ; branch if no errors were encountered .8:033c CE 4D 01 DEC $014D ; decrease retry counter .8:033f D0 C4 BNE $0305 ; try again if retries remain .8:0341 4C EC 03 JMP $03EC ; otherwise just continue, which will crash .8:0344 68 PLA ; pull byte from stack (low byte of return address) .8:0345 4D A0 01 EOR $01A0 ; EOR it with a byte of the decryption key .8:0348 8D A0 01 STA $01A0 ; store it back .8:034b 68 PLA ; pull byte from stack (high byte of return address) .8:034c 4D A1 01 EOR $01A1 ; EOR it with a byte of the decryption key .8:034f 8D A1 01 STA $01A1 ; store it back .8:0352 A9 00 LDA #$00 .8:0354 85 1C STA $1C .8:0356 18 CLC .8:0357 08 PHP .8:0358 A0 00 LDY #$00 .8:035a B9 00 04 LDA $0400,Y ; decrypt the 3 sectors loaded at $0400-$06FF using... .8:035d 4D A3 01 EOR $01A3 ; ...the decryption key stored at $01A0-$01A3 .8:0360 99 00 04 STA $0400,Y .8:0363 28 PLP .8:0364 2E A3 01 ROL $01A3 .8:0367 6E A2 01 ROR $01A2 .8:036a 2E A1 01 ROL $01A1 .8:036d 6E A0 01 ROR $01A0 .8:0370 90 08 BCC $037A .8:0372 AD A1 01 LDA $01A1 .8:0375 49 A5 EOR #$A5 .8:0377 8D A1 01 STA $01A1 .8:037a 08 PHP .8:037b C8 INY .8:037c D0 DC BNE $035A .8:037e EE 5C 03 INC $035C ; modify above code to process next buffer area .8:0381 EE 62 03 INC $0362 ; modify above code to process next buffer area .8:0384 AE 62 03 LDX $0362 .8:0387 E0 07 CPX #$07 ; repeat until we're at the $0700 buffer .8:0389 90 CF BCC $035A .8:038b 28 PLP .8:038c 4C EC 03 JMP $03EC >8:038f 01 0e 01 11 01 04 .8:0395 78 SEI ; Disable interrupts .8:0396 A9 EE LDA #$EE .8:0398 8D 0C 1C STA $1C0C ; Attach overflow flag to byte-ready .8:039b 20 0A F5 JSR $F50A ; Find start of data block .8:039e B8 CLV .8:039f 50 FE BVC $039F ; wait for byte-ready .8:03a1 20 E5 03 JSR $03E5 ; wait for sync .8:03a4 2C 01 1C BIT $1C01 .8:03a7 B8 CLV .8:03a8 50 FE BVC $03A8 ; wait for byte-ready .8:03aa 2C 01 1C BIT $1C01 .8:03ad B8 CLV .8:03ae A2 03 LDX #$03 ; repeat 4 times .8:03b0 C6 00 DEC $00 .8:03b2 F0 15 BEQ $03C9 .8:03b4 A9 00 LDA #$00 .8:03b6 A0 94 LDY #$94 .8:03b8 50 FE BVC $03B8 ; wait for byte ready .8:03ba B8 CLV .8:03bb 4D 01 1C EOR $1C01 ; EOR $94 bytes to get 1/4 of decrypt key .8:03be 88 DEY .8:03bf D0 F7 BNE $03B8 .8:03c1 9D A0 01 STA $01A0,X ; store 1 of 4 bytes for decrypt key .8:03c4 CA DEX .8:03c5 10 ED BPL $03B4 .8:03c7 30 17 BMI $03E0 .8:03c9 A9 00 LDA #$00 .8:03cb A0 94 LDY #$94 .8:03cd 50 FE BVC $03CD .8:03cf B8 CLV .8:03d0 4D 01 1C EOR $1C01 .8:03d3 88 DEY .8:03d4 D0 F7 BNE $03CD .8:03d6 DD A0 01 CMP $01A0,X ; Run the check again just to verify everything is the same .8:03d9 F0 02 BEQ $03DD .8:03db E6 05 INC $05 ; increase error count variable .8:03dd CA DEX .8:03de 10 E9 BPL $03C9 .8:03e0 A5 00 LDA $00 .8:03e2 D0 B1 BNE $0395 ; move to next sector header and calculate checksum .8:03e4 60 RTS .8:03e5 2C 00 1C BIT $1C00 ; wait for sync .8:03e8 30 FB BMI $03E5 .8:03ea B8 CLV .8:03eb 60 RTS .8:03ec A0 ED LDY #$ED ; Erase protection/decryption code .8:03ee 98 TYA .8:03ef 99 00 03 STA $0300,Y .8:03f2 88 DEY .8:03f3 D0 F9 BNE $03EE .8:03f5 60 RTS ; Done, RTS to wait-loop at $EBFF. Crack: Method #1: Hardcode the decrypt key. Block-load track 1 sector 7, assemble the following changes, block-save it back. .8:0395 A9 63 LDA #$63 .8:0397 8D A0 01 STA $01A0 .8:039a A9 B6 LDA #$B6 .8:039c 8D A1 01 STA $01A1 .8:039f A9 18 LDA #$18 .8:03a1 8D A2 01 STA $01A2 .8:03a4 A9 41 LDA #$41 .8:03a6 8D A3 01 STA $01A3 .8:03a9 60 RTS Method #2: save the decrypted sectors back and modify the code to skip decryption routine. No real advantage to this method.