---------Spellakazam revision 2-------- A 4am crack 2014-09-02 --------------------------------------- "Spellakazam" is a 1983 educational game distributed by DesignWare, Inc. in association with Silver Burdett. There is an existing disk image on the Asimov FTP site called spellakazam.dsk. Both that image and my disk appear the same at first glance, but the sector- by-sector disk contents are wildly different. After minutes of furious research, I found that T22,S09 of the existing disk image contains the string "GAME DISK- SPELLAKAZAM", but my disk contains the string "GAME DISK-SPELLAKAZAM2". I have therefore labeled this one "Spellakazam revision 2". [The copy protection is identical to "Spellicopter," distributed by DesignWare. This write-up is therefore quite similar to that one, with a few corrections.] COPYA copies the disk with no disk read errors, but the copy does not work. It boots, loads several tracks (slowly, but no slower than the original), then prints "SORRY ? DISK ERROR" and exits to a BASIC prompt. EDD 4 bit copy fares no better. There is no VTOC on track $11 (so no CATALOG). Listening to the original disk boot, there doesn't seem to be a standard DOS loaded from tracks 2, 1, then 0. Time for boot tracing with AUTOTRACE. [S5,D1=my work disk] [S6,D1=original disk] ]PR#5 ... CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 CAPTURING BOOT1 ...reboots slot 6... ...reboots slot 5... SAVING BOOT1 SAVING RWTS For those of you just tuning in, my work disk uses a custom program that I affectionately call "AUTOTRACE" to automate the process of boot tracing as far as possible. For some disks, this just captures track 0, sector 0 (saved in a file called "BOOT0") and stops. For other disks that load in the same way that an unprotected DOS 3.3 disk loads (like this one, apparently), it captures the next stage of the boot process in a file called "BOOT1". BOOT1 contains sectors 0-9 on track 0, which are loaded into memory at $B600..$BFFF. This generally contains the RWTS routines which the program uses to read the rest of the disk, plus whatever nastiness the original developer can stuff into the limited free space. It also captured the RWTS, which can be useful if the disk uses a non-standard nibble encoding. This disk was copyable with COPYA, so I don't need the RWTS file. But I will look at the BOOT1 file to see why my copy isn't booting. ]BLOAD BOOT1,A$2600 ]CALL -151 *B600<2600.2EFEM *B700L ; normal initialization stuff here, ; setting up the RWTS parameter table ; at $B7E8 B700- 8E E9 B7 STX $B7E9 B703- 8E F7 B7 STX $B7F7 B706- A9 01 LDA #$01 B708- 8D F8 B7 STA $B7F8 B70B- 8D EA B7 STA $B7EA B70E- AD E0 B7 LDA $B7E0 B711- 8D E1 B7 STA $B7E1 B714- A9 00 LDA #$00 B716- 8D EC B7 STA $B7EC B719- AD E2 B7 LDA $B7E2 B71C- 8D ED B7 STA $B7ED B71F- AD E3 B7 LDA $B7E3 B722- 8D F1 B7 STA $B7F1 B725- A9 01 LDA #$01 B727- 8D F4 B7 STA $B7F4 B72A- 8A TXA B72B- 4A LSR B72C- 4A LSR B72D- 4A LSR B72E- 4A LSR B72E- 4A LSR B72F- AA TAX B730- A9 00 LDA #$00 B732- 9D F8 04 STA $04F8,X B735- 9D 78 04 STA $0478,X ; hey now, what's all this then? B738- 20 00 BB JSR $BB00 Interesting. It sets up an RWTS parameter table, but instead of calling the usual multi-sector read routine at $B793, it calls $BB00. I know from experience (and from reading "Beneath Apple DOS") that there shouldn't be any code in the $BB00 page. The standard DOS 3.3 RWTS uses this page as scratch space for converting nibbles to bytes, which means it gets stomped on with every disk read. So any code that's there during boot is non-standard and disk-specific, and therefore suspicious. BB00- 86 1B STX $1B ; a neat trick to get the high byte of ; the return address from the stack ; without actually pulling it off the ; stack and pushing it back. BB02- BA TSX BB03- BD 02 01 LDA $0102,X ; $B7 --> zero page $03 BB06- 85 03 STA $03 BB08- 18 CLC BB09- 69 04 ADC #$04 ; $BB --> zero page $05 BB0B- 85 05 STA $05 BB0D- A0 00 LDY #$00 BB0F- 84 02 STY $02 BB11- A0 40 LDY #$40 BB13- 84 04 STY $04 BB15- A0 39 LDY #$39 BB17- A9 93 LDA #$93 ; $93 --> $B739 BB19- 91 02 STA ($02),Y BB1B- C8 INY BB1C- A5 03 LDA $03 ; $B7 --> $B73A BB1E- 91 02 STA ($02),Y ; $BB40..$BBBF --> $0800..$087F BB20- A0 7F LDY #$7F BB22- B1 04 LDA ($04),Y BB24- 99 00 08 STA $0800,Y BB27- 88 DEY BB28- 10 F8 BPL $BB22 ; restore X register and jump to ; relocated code BB2A- A6 1B LDX $1B BB2C- 4C 00 08 JMP $0800 Oh, that's clever. This subroutine erases any evidence that it was ever called, by changing the JSR instruction that called it from JSR $BB00 to JSR $B793. Then it relocates some other code to $0800 and jumps there. This is not innocent code. Innocent code does not cover its tracks to make it seem like it was never called. This code does not have my best interests at heart. Let's see what ends up at $0800. *BB2C:4C 59 FF *B738G *800L 0800- A9 00 LDA #$00 0802- A0 EC LDY #$EC ; ($02) points to $B700 at this point, ; so this looks like it's setting up ; the RWTS parameter table again. ; $B7EC holds the track number (0). 0804- 91 02 STA ($02),Y 0806- C8 INY ; $B7ED holds the sector number (0). 0807- 91 02 STA ($02),Y 0809- A9 09 LDA #$09 080B- A0 F1 LDY #$F1 ; $B7F1 holds the destination address, ; so it looks like we're going to read ; a bunch of sectors from track 0 ; into $0900 and up. 080D- 91 02 STA ($02),Y 080F- A9 08 LDA #$08 0811- A0 E1 LDY #$E1 ; $B7E1 holds the number of sectors ; to read (8). 0813- 91 02 STA ($02),Y ; set up a JMP instruction at $01 (WTF) 0815- A9 4C LDA #$4C 0817- 85 01 STA $01 0819- A9 93 LDA #$93 081B- 85 02 STA $02 ; call $B793 to read multiple sectors 081D- 20 01 00 JSR $0001 Despite the odd indirection, this part isn't suspicious at all. It's using the standard multi-read routine at $B793 to read the rest of track 0 into memory. But look what comes next: 0820- A0 00 LDY #$00 0822- 84 02 STY $02 0824- A5 1E LDA $1E 0826- 85 08 STA $08 0828- 0A ASL 0829- 90 01 BCC $082C 082B- C8 INY 082C- 48 PHA 082D- 68 PLA 082E- D0 F8 BNE $0828 0830- C0 02 CPY #$02 0832- 69 FF ADC #$FF 0834- 85 1F STA $1F Wait a minute. Wait wait wait wait wait. The standard DOS 3.3 RWTS doesn't use zero page $1E, so at this point it should be uninitialized and essentially random. But this loop seems to be doing some bit math on it (specifically, counting how many bits are 0 and storing that in the Y register), so either something is setting it or I'm being punked. With my trusty Copy ][+ sector editor, I found a few instances of $1E in track 0. The only one that looked like actual RWTS code was T00,S0F,$3F. After some manual cross-referencing, it appears that this sector is loaded at $B900 by the RWTS loader bootstrap in sector 0. Here is the relevant code: B925- BC 8C C0 LDY $C08C,X B928- 10 FB BPL $B925 B92A- D9 00 BA CMP $BA00,Y B92D- D0 13 BNE $B942 B92F- BD 8C C0 LDA $C08C,X B932- 10 FB BPL $B92F B934- B8 CLV B935- BD 8C C0 LDA $C08C,X B938- 10 FB BPL $B935 B93A- B8 CLV B93B- 1E 8C C0 ASL $C08C,X B93E- 26 1E ROL $1E B940- 50 5C BVC $B99E B942- 38 SEC B943- 60 RTS Normally, this code would be checking for the nibble sequence "DE AA", the standard epilogue after the data field. But instead, this disk accepts any two nibbles, then does some bit math to twiddle zero page $1E based on the timing bits that follow. Since that relocated routine at $0800 reads 8 sectors, zero page $1E gets twiddled 8 times, giving it a fully defined value despite never being initialized. Never a dull moment in the land of Apple II copy protection. Obviously the value in zero page $1E is important. Let's capture it. ]PR#5 ]CALL -151 *9600 This is repeatable; the original disk always ends up with $F7 in zero page $1E. If my theory is correct (that this is the crux of the copy protection), then running the same capture utility on my non-working copy should yield a different result. [S5,D1=my work disk] [S6,D1=non-working copy] ]PR#5 ]BRUN CAPTURE 1E ... 00 This is also repeatable. Copies (even the bit copy I made with EDD 4) end up with $00 in zero page $1E. Now I'm wondering if I can simply fake this data by ignoring the value of $1E and hard-coding the expected value. I suppose there's only one way to find out... Using my trusty Copy ][+ sector editor, I found the $BB00 routine in sector 3 of track $00. I made one small change after the disk reading but before the bit counting: to ignore the value in zero page $1E and always load a value of $F7 instead. T00,S03,$64 change "A5 1E" to "A9 F7" Success! The program boots and runs without complaint. There doesn't seem to be any further copy protection. Quod erat liberandum. --------------------------------------- A 4am crack No. 124 ------------------EOF------------------