Track Skew Protection
Contents
Track Skew Protection
The protection does not use any extra track, bad sector or signature. It checks the track skew: the angular position of each track relative to its neighbour. A duplicator writes all tracks in a fixed relation to each other. A normal disk copier writes each track independently, starting at an arbitrary point of the rotation, so the copied data is correct but the tracks' positions relative to each other are random.
The same drive routine, encrypted the same way (XOR $37), was
found on releases by Ariolasoft, Rushware and others (see
Releases). The description below follows
Power-Pack (Rushware, 1987, sources 2, 3 and 6).
Disk layout
- Tracks 1–35 use the ordinary CBM DOS layout. There is nothing beyond track 35.
- Disk ID and DOS type in the BAM are
$14 $14(control characters). - The first directory entry is named
LOADER",8,1and shown with 0 blocks. The file is actually about 1,800 bytes long and loads to$0300. Its first bytes overwrite the BASIC vectorsIERROR,IMAINandICRNCHwith$0340, so it starts itself after loading. - The loader contains a BASIC menu ("POWER-PACK DISK COMPILATION … WHICH GAME DO YOU REQUIRE ?"). Before the menu it loads
"POWER",8,1and starts it withSYS 7280($1C70). POWER(607 bytes) is identical on all four disk sides and contains the check.- Other releases carry the routine in their own loader files, for example
FUGGER/XXon Die Fugger.
The check
C64 side (POWER)
POWER decrypts itself in three stages: $1C90 with
EOR $12, then $1D2B with EOR $20, then
$1DDD with EOR $37. After that it:
- uploads 256 bytes of drive code with
M-Wto drive$0300(in 32-byte chunks); - starts it with
M-E $0300; - reads the result table back with
M-Rfrom drive$0381into C64$5000; - compares 14 bytes of the table with a fixed table.
$1CC2 A9 50 LDA #$50 $1CC4 8D F2 1C STA $1CF2 ; patch the compare below: $E000 -> $5000 $1CC7 4C EE 1C JMP $1CEE ... $1CEE A2 00 LDX #$00 $1CF0 BD 00 50 LDA $5000,X ; table read from the drive $1CF3 DD D0 1C CMP $1CD0,X ; expected: 04 05 06 ... 11 $1CF6 D0 08 BNE $1D00 $1CF8 E8 INX $1CF9 E0 0E CPX #$0E ; 14 entries (tracks 2-15) $1CFB 90 F3 BCC $1CF0 $1CFD A9 00 LDA #$00 ; all equal: A = $00 $1CFF 2C A9 37 BIT $37A9 ; (hides "LDA #$37" at $1D00) $1D02 85 02 STA $02 $1D04 C9 37 CMP #$37 $1D06 D0 04 BNE $1D0C $1D08 A9 00 LDA #$00 ; mismatch: $01 = $00 -> all ROMs and $1D0A 85 01 STA $01 ; I/O switched off, the machine crashes $1D0C A9 00 LDA #$00 $1D0E 8D A6 02 STA $02A6 $1D11 60 RTS
On a mismatch the code writes $00 to the processor port
$01. That switches off BASIC, KERNAL and I/O, and the program
crashes on return.
Drive side ($0300)
The drive code measures, for each track from 16 down to 2, which sector header the drive meets first after arriving on that track:
$0308 A9 10 LDA #$10 $030A 85 06 STA $06 ; job 0 track: 16 (counts down) $030C A9 0F LDA #$0F $030E 85 07 STA $07 ; index: 15 (counts down) $0310 78 SEI $0311 A9 20 LDA #$20 $0313 8D 07 1C STA $1C07 ; fast stepper timing $0316 8D 05 1C STA $1C05 $0319 58 CLI $031A A9 B0 LDA #$B0 $031C 85 00 STA $00 ; SEEK job: head to track $06, $031E A5 00 LDA $00 ; synchronized to a header there $0320 30 FC BMI $031E ... $032D A9 F0 LDA #$F0 ; further job $F0 $032F 85 00 STA $00 ... $033C A9 FE LDA #$FE $033E 20 76 D6 JSR $D676 ; ROM: step the head one track $0341 A9 00 LDA #$00 ; (two half-steps) behind DOS's back $0343 85 22 STA $22 ; DOS: "current track unknown" $0345 A9 B0 LDA #$B0 $0347 85 00 STA $00 ; SEEK again: DOS must read the first $0349 A5 00 LDA $00 ; header that passes under the head $034B 30 FC BMI $0349 ... $0354 A5 19 LDA $19 ; sector number of that header $0356 A6 07 LDX $07 $0358 9D 80 03 STA $0380,X ; -> result table $0381-$038F $035B C6 06 DEC $06 $035D C6 07 DEC $07 $035F D0 B0 BNE $0311 ; next track ... $0370 ... ; finally: wipe $0300-$036F (ROR)
- The time from reading a header, through stepping the head, to arriving on the next track is always the same. So the first sector found on arrival depends only on the angular offset between the two neighbouring tracks.
- On the original disk, this sector number rises by exactly one per track. The expected table for tracks 2–15 is
04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11. - After measuring, the drive code overwrites itself (
$0300–$036F) with aRORloop.
Notes:
- The Newsroom: the drive routine is present on disk 1 (track 33, sector 16, unencrypted), but no program on the disk uses it and no check was found. The Newsroom is therefore not listed as using this protection.
Copying and imaging
- A copy made track by track with an ordinary copier has the correct data but random track positions. The table doesn't match, and the loader crashes.
- A G64 passes only if the conversion preserves each track's angular position relative to the index hole. A D64 image cannot pass.
- Verified: rotating only track 9 of a working image by a third of a revolution changes exactly the two table entries that involve track 9 (
… 0A 04 13 0D …instead of… 0A 0B 0C 0D …), and the check fails. The data on the track is unchanged.
Pages that refer to this protection
- Descriptions of old disk copy protections (← links)
- Zarjaz (← links)
- Power-Pack (← links)
- Jump Jet (← links)
- Pile-Up (← links)
- Centurions: Power X Treme (← links)
- Future Games 64 (← links)
- Input 64 (← links)
- Hybrid (← links)
- They $tole a Million (← links)
- Mountie Mick's Deathride (← links)
- Werner: Mach hin! (← links)
- Die Fugger (← links)