-----------Jumping Math Flash---------- A 4am crack 2014-04-25 --------------------------------------- Jumping Math Flash is a 1988 educational game developed by William H. Kraus and distributed by Mindscape. COPYA fails immediately. EDD 4 bit copy succeeds, but the copy does not work. It boots and almost immediately reboots. My educated guess: a custom RWTS that knows about the disk's non-standard prologue and/or epilogue nibbles, plus a nibble check somewhere in track 0. It's time for AUTOTRACE. [S5D1=my work disk] [S6D1=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 Well that all went flawlessly. Now I have a copy of the RWTS that the original disk uses to read itself. Let's use that against it. [S6D1=my work disk] ]PR#6 ... ]BRUN ADVANCED DEMUFFIN 1.1 [S6,D1=my work disk] ]PR#6 ]BRUN ADVANCED DEMUFFIN 1.1 --> LOAD NEW RWTS MODULE At $B8, load "RWTS" from D1 [S6,D1=original disk] [S6,D2=blank disk] --> FORMAT TARGET DISK ...grind grind grind... --> CONVERT DISK This disk is 16 sectors, and the default options (copy the entire disk, all tracks, all sectors) don't need to be changed. ADVANCED DEMUFFIN 1.1 - COPYRIGHT 1983 WRITTEN BY THE STACK -CORRUPT COMPUTING =======PRESS ANY KEY TO CONTINUE======= TRK:................................... +.5: 0123456789ABCDEF0123456789ABCDEF012 SC0:................................... SC1:................................... SC2:................................... SC3:................................... SC4:................................... SC5:................................... SC6:................................... SC7:................................... SC8:................................... SC9:................................... SCA:................................... SCB:................................... SCC:................................... SCD:................................... SCE:................................... SCF:................................... ======================================= 16 SC $00,$00 TO $22,$0F BY $01 TO DRV2 [S5D1=my work disk] [S6D1=demuffin'd copy] ]PR#6 Hmm, still reboots almost immediately. Let's see why. ]PR#5 ]BLOAD BOOT0,A$800 ]CALL -151 *801L ... Everything here looks perfectly normal. *BLOAD BOOT1,A$2600 *B600<2600.2EFEM *B700L B700- 20 1A BC JSR $BC1A 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 02 LDA #$02 B716- 8D EC B7 STA $B7EC B719- A9 04 LDA #$04 B71B- 8D ED B7 STA $B7ED B71E- AC E7 B7 LDY $B7E7 B721- 88 DEY B722- 8C F1 B7 STY $B7F1 B725- A9 01 LDA #$01 B727- 8D F4 B7 STA $B7F4 Well that all looks perfectly normal... after the first line (JSR $BC1A), which is definitely suspicious. *BC1AL ; this is the instruction I was ; expecting at $B700 (but it called ; this subroutine instead) BC1A- 8E E9 B7 STX $B7E9 ; OK BC1D- A9 00 LDA #$00 BC1F- 8D 78 04 STA $0478 BC22- 48 PHA BC23- A6 2B LDX $2B BC25- A9 22 LDA #$22 ; OK BC27- 20 A0 B9 JSR $B9A0 ; hello BC2A- 20 03 BB JSR $BB03 BC2D- 68 PLA BC2E- 08 PHP BC2F- A6 2B LDX $2B BC31- 20 A0 B9 JSR $B9A0 BC34- 28 PLP BC35- 60 RTS $B9A0 is just some initialization code. But anything in the $BB00 range is automatically suspicious, because in any relatively normal RWTS, that entire page of memory gets overwritten with every disk read during denibblization. (That is totally not a real word.) *BB03L ; save some zero page state BB03- A2 00 LDX #$00 BB05- B5 00 LDA $00,X BB07- 9D 00 50 STA $5000,X BB0A- CA DEX BB0B- 10 F8 BPL $BB05 ; hello BB0D- 20 00 BC JSR $BC00 *BC00L ; set reset vector to reboot BC00- A5 2B LDA $2B BC02- 4A LSR BC03- 4A LSR BC04- 4A LSR BC05- 4A LSR BC06- 09 C0 ORA #$C0 BC08- 8D F3 03 STA $03F3 BC0B- 49 A5 EOR #$A5 BC0D- 8D F4 03 STA $03F4 BC10- A9 00 LDA #$00 BC12- 8D F2 03 STA $03F2 BC15- A6 2B LDX $2B ; hello BC17- 4C 30 BB JMP $BB30 *BB30L ; turn on the disk motor manually: ; always a sign of impending evil bits BB30- A6 2B LDX $2B BB32- BD 89 C0 LDA $C089,X BB35- BD 8E C0 LDA $C08E,X BB38- A9 AE LDA #$AE BB3A- 85 1E STA $1E BB3C- A9 BB LDA #$BB BB3E- 85 1F STA $1F BB40- A9 0A LDA #$0A BB42- 85 09 STA $09 BB44- A9 80 LDA #$80 BB46- 85 08 STA $08 BB48- C6 08 DEC $08 ; looks like the failure path goes ; to $BBA8 BB4A- F0 5C BEQ $BBA8 BB4C- 20 44 B9 JSR $B944 ; fail BB4F- B0 57 BCS $BBA8 BB51- A5 2D LDA $2D BB53- C9 0D CMP #$0D BB55- D0 F1 BNE $BB48 BB57- A0 00 LDY #$00 BB59- BD 8C C0 LDA $C08C,X BB5C- 10 FB BPL $BB59 BB5E- 88 DEY ; fail BB5F- F0 47 BEQ $BBA8 BB61- C9 D5 CMP #$D5 BB63- D0 F4 BNE $BB59 BB65- A0 00 LDY #$00 BB67- BD 8C C0 LDA $C08C,X BB6A- 10 FB BPL $BB67 BB6C- 88 DEY ; fail BB6D- F0 39 BEQ $BBA8 BB6F- C9 E7 CMP #$E7 BB71- D0 F4 BNE $BB67 BB73- BD 8C C0 LDA $C08C,X BB76- 10 FB BPL $BB73 BB78- C9 E7 CMP #$E7 ; fail BB7A- D0 2C BNE $BBA8 BB7C- BD 8C C0 LDA $C08C,X BB7F- 10 FB BPL $BB7C BB81- C9 E7 CMP #$E7 ; fail BB83- D0 23 BNE $BBA8 BB85- BD 8D C0 LDA $C08D,X BB88- A0 10 LDY #$10 BB8A- 24 FF BIT $FF BB8C- BD 8C C0 LDA $C08C,X BB8F- 10 FB BPL $BB8C BB91- 88 DEY ; fail BB92- F0 14 BEQ $BBA8 BB94- C9 EE CMP #$EE BB96- D0 F4 BNE $BB8C BB98- A0 07 LDY #$07 BB9A- BD 8C C0 LDA $C08C,X BB9D- 10 FB BPL $BB9A BB9F- D1 1E CMP ($1E),Y ; fail BBA1- D0 05 BNE $BBA8 BBA3- 88 DEY BBA4- 10 F4 BPL $BB9A BBA6- 18 CLC BBA7- 60 RTS ; any failure ends up here BBA8- C6 09 DEC $09 BBAA- D0 98 BNE $BB44 ; ran out of chances -- set carry and ; exit BBAC- 38 SEC BBAD- 60 RTS OK, so it's a nibble check that clears the carry if it works and sets the carry if it fails. Unwinding the calling stack, we left off here: BB0D- 20 00 BC JSR $BC00 ; save flags BB10- 08 PHP ; restore zero page state BB11- A2 00 LDX #$00 BB13- B9 00 50 LDA $5000,Y BB16- 95 00 STA $00,X BB18- CA DEX BB19- 10 F8 BPL $BB13 ; restore flags BB1B- 28 PLP ; if nibble check passed, continue BB1C- 90 0F BCC $BB2D ; if nibble check failed, push the ; $Cx00 address onto the stack and ; "return" to it (i.e. reboot) BB1E- A5 2B LDA $2B BB20- 4A LSR BB21- 4A LSR BB22- 4A LSR BB23- 4A LSR BB24- 09 C0 ORA #$C0 BB26- A8 TAY BB27- 88 DEY BB28- 98 TYA BB29- 48 PHA BB2A- A9 FF LDA #$FF BB2C- 48 PHA BB2D- A6 2B LDX $2B BB2F- 60 RTS Which is exactly the behavior I saw. OK, so it appears I can simply bypass this entire routine without adverse consequences. Unwinding the stack even further, this all started at $B700, which called $BC1A, which stored the X register in $B7E9 (useful) then did a nibble check (not useful). If I put an RTS at $BC1D, that should bypass the nibble check and let the boot continue normally. T00,S06,$1D change "A9" to "60" Success! The game boots and runs with no further complaint. Quod erat liberandum. --------------------------------------- A 4am crack No. 22 ------------------EOF------------------