--------Street Sports Basketball------- A 4am crack 2014-05-26 --------------------------------------- "Street Sports Basketball" is a 1987 arcade game distributed by Epyx, Inc. [The copy protection is very similar to "The Movie Monster Game," also distributed by Epyx. This write-up is therefore quite similar to that one, with a few corrections and updated disassembly listings.] Trying to copy the original disk with COPYA fails immediately with a disk read error. EDD 4 bit copy gives no read errors, but the copy it produces just reboots endlessly. Firing up my trusty Copy ][+ sector editor, I press "P" to get to the Sector Editor Patcher and selected "DOS 3.3 Patched." This option ignores the epilogue bytes after the address field and data field (normally "DE AA EB"). It doesn't work on every disk; lots of disks use non-standard prologue bytes as well, or don't use 16 sectors, or any one of a hundred different ways to deviate from the norm within the tolerance of the Disk II hardware. But it works with this one! Ignoring epilogue bytes, the sector editor can whiz through the entire disk and read all the data from every sector on every track. That means that the easiest way to copy this disk is to use COPYA (from the DOS 3.3 master disk), with one small modification: after booting, I'll go into the monitor and patch the DOS 3.3 RWTS to ignore epilogue bytes. This is similar to what the Copy ][+ Sector Editor Patcher does, and in most cases the difference is immaterial. [S6,D1=DOS 3.3 master disk] ]PR#6 ... ]CALL -151 *B942:18 <-- CLC to indicate no error reading epilogue bytes (was SEC, signifying an error) *3D0G ]RUN COPYA [S6,D1=original disk] [S6,D2=blank disk] ...read read read... ...grind grind grind... ...write write write... (I do this for both sides.) OK, now I have two disks with standard prologue and epilogue bytes, which can be read by any standard tool (including COPYA without any RWTS patches). Unfortunately, the copy does not work; it just reboots endlessly. There must be some additional code designed to detect that the disk is not original. To find out where this code is, I'll need to trace the boot process until I find the offending code, and remove it or bypass it somehow. [S6,D1=original disk] [S5,D1=my work disk] ]PR#5 CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 OK, now I have the very early boot code (colloquially called "boot0") which is loaded by the disk controller ROM from track 0, sector 0. This code's job is to load the next section of code, commonly called "boot1" (usually by re-using part of the disk controller ROM routine at $C600). Then "boot1" either loads the rest of the disk operating system, or (in many commercial games) simply loads the game code directly off the disk and jumps to it. There are variations (of course), but that's the basic idea. Booting a disk is a cumulative process; each step builds on the previous steps. My work disk automatically runs a program called AUTOTRACE1, which interrupts the boot process immediately after the disk controller ROM routine loads the code from track 0, sector 0. It relocates this code (up to 256 bytes worth) to address $2800, then reboots and saves it to a file called BOOT0. I've seen a lot of boot0 code from different copy-protected (and not copy-protected) disks, so I've kind of developed a sense of what a "normal" boot looks like. I can look at almost-but-not-quite normal boot0 code and hone in pretty quickly on the part that's unusual. Maybe it calls a subroutine that isn't normally called, or it does things in a strange order, or it jumps to an unusual place after loading the boot1 code. ]CALL -151 *800<2800.28FFM *801L ... Everything here looks pretty normal (i.e. just like an unprotected DOS 3.3 disk), until it goes to jump to the boot1 code. Usually that happens with an indirect JMP ($08FD), which, in a normal boot0, will end up continuing execution at $B700 which is stored in track 0, sector 1. But in this case, I see: 084A- 4C 00 BB JMP $BB00 Highly suspect. I definitely want to see what evil lurks at $BB00. That area of memory is normally reserved for the denibblizing process when reading data from a sector. It's scratch space, essentially. It's overwritten every time the disk reads itself (after boot1 is loaded). But $BB00 isn't loaded yet, because I interrupted the boot process before it could be loaded. So now I need to trace the boot again, but a little bit further -- far enough for boot0 to load boot1 (including the suspicious code at $BB00), but no further. My work disk has another program, unimaginatively named AUTOTRACE1, which does just that. It loads track 0, sector 0, then patches the boot0 code at $084A to call back to a routine under my control (instead of jumping to the original disk's boot1 code). ]BRUN AUTOTRACE1 CAPTURING BOOT1 ...reboots slot 6... ...reboots slot 5... SAVING BOOT1 Let's see what we have. ]CALL -151 *B600<2000.29FFM *BB00L ; initialize some zero page addresses BB00- A9 00 LDA #$00 BB02- A2 F0 LDX #$F0 BB04- 95 00 STA $00,X BB06- E8 INX BB07- D0 FB BNE $BB04 BB09- A9 0A LDA #$0A BB0B- 85 FC STA $FC ; Turn on the disk motor. Zero page $2B ; contains the slot number x 16. This ; is the standard way to access low- ; level disk commands. BB0D- A6 2B LDX $2B BB0F- BD 89 C0 LDA $C089,X BB12- BD 8E C0 LDA $C08E,X ; a counter of some kind BB15- A9 80 LDA #$80 BB17- 85 FD STA $FD BB19- C6 FD DEC $FD ; $BB8A is what I call "The Badlands" ; i.e. the code from which there is ; no return. Skipping ahead, I can see ; that $BB8A is one branch away from ; tweaking the reset vector and ; rebooting the computer. Which is, ; you know, not what we want. BB1B- F0 6D BEQ $BB8A ; $BBA8 looks for the standard address ; prologue, as a setup for the real ; test which comes next. BB1D- 20 A8 BB JSR $BBA8 ; If, for some reason, that doesn't ; work, off to The Badlands with you. BB20- B0 68 BCS $BB8A ; Search for a specific sequence of ; nibbles in the "dead zone" between ; the address field and data field. ; This area is normally not important, ; so COPYA didn't copy it precisely ; because normal disks don't care. ; (Actually, it's even more evil than ; that, because the original disk is ; written with timing bits in specific ; non-standard places between the ; nibbles in the dead zone. This code ; not only requires the right nibbles ; in the right order, it reads them ; just slightly faster than normal. So ; the timing bits need to be in the ; right places too, or the disk will ; get out of sync and read the wrong ; nibble values. This will trip up even ; the best bit copiers. And you can ; forget about making a disk image for ; emulators -- those don't store timing ; bits at all.) BB22- A5 F9 LDA $F9 BB24- C9 0F CMP #$0F BB26- D0 F1 BNE $BB19 BB28- A0 00 LDY #$00 BB2A- BD 8C C0 LDA $C08C,X BB2D- 10 FB BPL $BB2A BB2F- 88 DEY BB30- F0 58 BEQ $BB8A BB32- C9 D5 CMP #$D5 BB34- D0 F4 BNE $BB2A BB36- A0 00 LDY #$00 BB38- BD 8C C0 LDA $C08C,X BB3B- 10 FB BPL $BB38 BB3D- 88 DEY BB3E- F0 4A BEQ $BB8A BB40- C9 E7 CMP #$E7 BB42- D0 F4 BNE $BB38 BB44- BD 8C C0 LDA $C08C,X BB47- 10 FB BPL $BB44 BB49- C9 E7 CMP #$E7 BB4B- D0 3D BNE $BB8A BB4D- BD 8C C0 LDA $C08C,X BB50- 10 FB BPL $BB4D BB52- C9 E7 CMP #$E7 BB54- D0 34 BNE $BB8A BB56- BD 8D C0 LDA $C08D,X BB59- A0 10 LDY #$10 BB5B- 24 80 BIT $80 BB5D- BD 8C C0 LDA $C08C,X BB60- 10 FB BPL $BB5D BB62- 88 DEY BB63- F0 25 BEQ $BB8A BB65- C9 EE CMP #$EE BB67- D0 F4 BNE $BB5D BB69- EA NOP BB6A- EA NOP BB6B- A0 07 LDY #$07 BB6D- BD 8C C0 LDA $C08C,X BB70- 10 FB BPL $BB6D BB72- 99 F0 00 STA $00F0,Y BB75- EA NOP BB76- 88 DEY BB77- 10 F4 BPL $BB6D ; Wait, it gets better -- this disk ; actually uses the raw nibble data it ; stores in this "dead zone" AS THE ; DECRYPTION KEY FOR THE REST OF BOOT1 BB79- A9 00 LDA #$00 BB7B- A8 TAY BB7C- 85 F8 STA $F8 BB7E- A2 03 LDX #$03 BB80- A9 B7 LDA #$B7 BB82- 20 97 BB JSR $BB97 . . . BB97- 85 F9 STA $F9 BB99- B5 F0 LDA $F0,X BB9B- 51 F8 EOR ($F8),Y BB9D- 91 F8 STA ($F8),Y BB9F- 88 DEY BBA0- D0 F7 BNE $BB99 BBA2- E6 F9 INC $F9 BBA4- CA DEX BBA5- 10 F2 BPL $BB99 BBA7- 60 RTS ; now that the boot1 code is decrypted, ; jump to it as normal BB85- A6 2B LDX $2B BB87- 4C 00 B7 JMP $B700 ; The Badlands (don't end up here!) BB8A- C6 FC DEC $FC BB8C- F0 03 BEQ $BB91 BB8E- 4C 15 BB JMP $BB15 BB91- EE F4 03 INC $03F4 BB94- 6C FC FF JMP ($FFFC) ; subroutine (called from $BB1D) to ; find the next address prologue and ; skip over the address field to ; position the drive head to read the ; special nibbles in the dead zone BBA8- A0 FD LDY #$FD BBAA- 84 F0 STY $F0 BBAC- C8 INY BBAD- D0 04 BNE $BBB3 BBAF- E6 F0 INC $F0 BBB1- F0 3D BEQ $BBF0 BBB3- BD 8C C0 LDA $C08C,X BBB6- 10 FB BPL $BBB3 BBB8- C9 D5 CMP #$D5 BBBA- D0 F0 BNE $BBAC BBBC- EA NOP BBBD- BD 8C C0 LDA $C08C,X BBC0- 10 FB BPL $BBBD BBC2- C9 AA CMP #$AA BBC4- D0 F2 BNE $BBB8 BBC6- A0 03 LDY #$03 BBC8- BD 8C C0 LDA $C08C,X BBCB- 10 FB BPL $BBC8 BBCD- C9 96 CMP #$96 BBCF- D0 E7 BNE $BBB8 BBD1- A9 00 LDA #$00 BBD3- 85 F1 STA $F1 BBD5- BD 8C C0 LDA $C08C,X BBD8- 10 FB BPL $BBD5 BBDA- 2A ROL BBDB- 85 F0 STA $F0 BBDD- BD 8C C0 LDA $C08C,X BBE0- 10 FB BPL $BBDD BBE2- 25 F0 AND $F0 BBE4- 99 F8 00 STA $00F8,Y BBE7- 45 F1 EOR $F1 BBE9- 88 DEY BBEA- 10 E7 BPL $BBD3 BBEC- A8 TAY BBED- EA NOP BBEE- 18 CLC BBEF- 60 RTS BBF0- 38 SEC BBF1- 60 RTS Because the next stage of the boot is encrypted, I can't simply bypass this copy protection routine. I need to let it run at least once, from the original disk, so that it can decrypt the rest of the code. The decryption happens at $BB97..$BBA7, then execution continues at $BB85 to continue to the real start of boot1 ($B700, just like a normal DOS 3.3 disk). TRACE1A will let this copy protection run (off the original disk), then interrupt the boot process immediately after the decryption loop and jump to a routine under my control. Then I can capture the decrypted RWTS and save it to my work disk, and eventually, to track 0 of my non-working copy to make it boot properly. *9600