------------Mission: Algebra----------- A 4am crack 2015-01-20 --------------------------------------- Name: Mission: Algebra Genre: educational Year: 1984 Publisher: DesignWare, Inc. Media: single-sided 5.25" floppy disk Other versions: none (preserved here for the first time) Identical cracks: many other DesignWare disks, including "Delta Drawing" (4am crack no. 114) and "Spellakazam" (4am crack no. 124) ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no read errors, but copy crashes into monitor Locksmith Fast Disk Backup same result EDD 4 bit copy (no sync, no count) same result Copy ][+ nibble editor nothing suspicious (standard prologue and epilogue on address and data fields) Disk Fixer can read every sector T00 sectors are in an odd order no sign of DOS or ProDOS no disk catalog on any track Why don't my copies work? I don't know. Maybe a nibble check that reads a decryption key (some Epyx games) or a seed to calculate the proper track/sector to load next (some Activision games). ~ Chapter 1 In Which We Fail To Find A Nibble Check But Find Something Far More Interesting Instead [S6,D1=original disk] [S5,D1=my work disk] ]PR#5 ... CAPTURING BOOT0 SAVING BOOT0 CAPTURING BOOT1 SAVING BOOT1 SAVING RWTS No nibble check auto-detected. Bummer. ]BLOAD BOOT1,A$2600 ]CALL -151 *FE89G FE93G ; disconnect DOS *B600<2600.2FFFM ; move RWTS into place *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 . . . B738- 20 00 BB JSR $BB00 ; hmm *BB00L BB00- 86 1B STX $1B ; neat trick to get the high byte of ; the return address from the stack 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 I need to know what ends up at $0800. *BB2C:4C 59 FF ; break into monitor *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. 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 zero and storing that in the Y register), so either something is setting $1E or I'm hallucinating. Or possibly both. Disk Fixer --> [F]ind --> [H]ex --> "1E" 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. (Remember, the sectors are in a weird order.) Here is the relevant code, which is supposed to be checking the data epilogue: *B92FL 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. [S6,D1=non-working copy] [S5,D1=my work disk] ]PR#5 ]BRUN CAPTURE 1E ... 00 All my copies (even the EDD 4 bit copy) end up with $00 in zero page $1E. ~ Chapter 2 In Which We Remove All Traces Of Copy Protection Using An Automated Tool That I Wrote For Just Such An Occasion [S6,D1=non-working copy] [S5,D1=my work disk] ]PR#5 ]BRUN PDP T00,S03,$64 change A51E to A9F7 (The patch ignores the value of zero page $1E and always loads a hard-coded value of $F7 instead.) Quod erat liberandum. --------------------------------------- A 4am crack No. 193 ------------------EOF------------------