----------Success with Typing---------- A 4am crack 2015-03-04 --------------------------------------- Name: Success with Typing Version: 1.2 (May 12, 1986) Genre: educational Year: 1986 Credits: Designed by Jeffrey Siegel and Mitchell Balsam Programmed by Mitchell Balsam Programming Assistance from David K. Lew Publisher: Scholastic Media: double-sided 5.25-inch floppy OS: custom Other versions: none (preserved here for the first time) Identical cracks: House-a-Fire! (4am crack no. 144) Only side A is bootable, so I'll start there. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA immediate disk read error Locksmith Fast Disk Backup unable to read any track EDD 4 bit copy (no sync, no count) no errors, but copy reboots endlessly Copy ][+ nibble editor all tracks use standard prologues (address: D5 AA 96, data: D5 AA AD) but modified epilogues (address: FF FF FF, data: FF FF FF) Disk Fixer ["O" -> "Input/Output Control"] set Address Epilogue to "FF FF FF" set Data Epilogue to "FF FF FF" all tracks readable T00 -> looks like a DOS 3.3 RWTS no other signs of DOS though no disk catalog on any track Why didn't COPYA work? modified epilogue bytes (every track) Why didn't Locksmith FDB work? modified epilogue bytes (every track) Why didn't my EDD copy work? probably a nibble check during boot (disks do not reboot unless someone tells them to) Next steps: 1. capture RWTS with AUTOTRACE 2. convert disk to standard format with Advanced Demuffin 3. find nibble check and bypass it ~ Chapter 1 In Which We Attempt To Use The Original Disk As A Weapon Against Itself [S6,D1=original disk, side A] [S6,D2=blank disk] [S5,D1=my work 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 /!\ NIBBLE CHECK AT $BB00 ]BRUN ADVANCED DEMUFFIN 1.5 ["5" to switch to slot 5] ["R" to load a new RWTS module] --> At $B8, load "RWTS" from drive 1 ["6" to switch to slot 6] ["C" to convert disk] --v-- ADVANCED DEMUFFIN 1.5 (C) 1983, 2014 ORIGINAL BY THE STACK UPDATES BY 4AM =======PRESS ANY KEY TO CONTINUE======= TRK:................................... +.5: 0123456789ABCDEF0123456789ABCDEF012 SC0:................................... SC1:................................... SC2:................................... SC3:................................... SC4:................................... SC5:................................... SC6:................................... SC7:................................... SC8:................................... SC9:................................... SCA:................................... SCB:................................... SCC:................................... SCD:................................... SCE:................................... SCF:................................... ======================================= 16SC $00,$00-$22,$0F BY1.0 S6,D1->S6,D2 --^-- [S6,D1=demuffin'd copy] ]PR#6 ...reboots endlessly... Let's go find that nibble check. ~ Chapter 2 In Which We Go Code Spelunking ]PR#5 ]BLOAD BOOT1,A$2600 ]CALL -151 *FE89G FE93G ; disconnect DOS *B600<2600.2FFFM ; move RWTS into place *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 0A LDA #$0A B716- 8D EC B7 STA $B7EC B719- A9 09 LDA #$09 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 B72A- 8A TXA B72B- 4A LSR B72C- 4A LSR B72D- 4A LSR Most of that looks relatively normal. I mean, it's reading from track $0A, sector $09, which is unusual, but it appears to be setting up a standard RWTS parameter table to do so. That first line is definitely unusual, though. That jumped out to me right away. *BC1AL ; this is the instruction I was ; expecting at $B700 (but it called ; this subroutine instead) BC1A- 8E E9 B7 STX $B7E9 ; initialize current track for RWTS BC1D- A9 00 LDA #$00 BC1F- 8D 78 04 STA $0478 BC22- 48 PHA BC23- A6 2B LDX $2B ; seek to track $20 BC25- A9 40 LDA #$40 BC27- 20 A0 B9 JSR $B9A0 ; hello BC2A- 20 03 BB JSR $BB03 ; now clean up and restore everything BC2D- 68 PLA BC2E- 08 PHP BC2F- A6 2B LDX $2B ; seek back to trace 0 BC31- 20 A0 B9 JSR $B9A0 BC34- 28 PLP BC35- 60 RTS *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 ; onward 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 ; and continue elsewhere BC15- A6 2B LDX $2B BC17- 4C 30 BB JMP $BB30 *BB30L ; turn on the drive motor manually ; (always suspicious) BB30- A6 2B LDX $2B BB32- BD 89 C0 LDA $C089,X BB35- BD 8E C0 LDA $C08E,X ; probably an address BB38- A9 AE LDA #$AE BB3A- 85 1E STA $1E BB3C- A9 BB LDA #$BB BB3E- 85 1F STA $1F ; probably a death counter 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 ; if zero page $08 reaches 0, fail BB4A- F0 5C BEQ $BBA8 ; read next available address field BB4C- 20 44 B9 JSR $B944 ; if that failed, give up BB4F- B0 57 BCS $BBA8 ; look for sector $0A BB51- A5 2D LDA $2D BB53- C9 0A CMP #$0A ; loop until we find it BB55- D0 F1 BNE $BB48 ; look for $D5 nibble BB57- A0 00 LDY #$00 BB59- BD 8C C0 LDA $C08C,X BB5C- 10 FB BPL $BB59 BB5E- 88 DEY BB5F- F0 47 BEQ $BBA8 ; fail BB61- C9 D5 CMP #$D5 BB63- D0 F4 BNE $BB59 ; 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 slower than normal. So ; the timing bits need to be in the ; right places too, or else this code ; will read the wrong nibble values ; while it's out of sync. 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.) BB65- A0 00 LDY #$00 BB67- BD 8C C0 LDA $C08C,X BB6A- 10 FB BPL $BB67 BB6C- 88 DEY BB6D- F0 39 BEQ $BBA8 ; fail 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 BB7A- D0 2C BNE $BBA8 ; fail BB7C- BD 8C C0 LDA $C08C,X BB7F- 10 FB BPL $BB7C BB81- C9 E7 CMP #$E7 BB83- D0 23 BNE $BBA8 ; fail ; kill some time to get out of sync ; with the "proper" start of nibbles) BB85- BD 8D C0 LDA $C08D,X BB88- A0 10 LDY #$10 BB8A- 24 FF BIT $FF ; now start looking for nibbles that ; don't really exist (except they do, ; because we're out of sync and reading ; timing bits as data) BB8C- BD 8C C0 LDA $C08C,X BB8F- 10 FB BPL $BB8C BB91- 88 DEY BB92- F0 14 BEQ $BBA8 ; fail BB94- C9 EE CMP #$EE BB96- D0 F4 BNE $BB8C ; check for nibble sequence stored ; in reverse order at $BBAE BB98- A0 07 LDY #$07 BB9A- BD 8C C0 LDA $C08C,X BB9D- 10 FB BPL $BB9A BB9F- D1 1E CMP ($1E),Y BBA1- D0 05 BNE $BBA8 ; fail BBA3- 88 DEY BBA4- 10 F4 BPL $BB9A BBA6- 18 CLC BBA7- 60 RTS ; all failures end up here -- try a few ; more times then give up completely BBA8- C6 09 DEC $09 BBAA- D0 98 BNE $BB44 ; 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 ; success path branches to here BB2D- A6 2B LDX $2B BB2F- 60 RTS Which is exactly the behavior I saw: endless rebooting. 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 restore that original instruction at $B700, it should bypass all the protection-related code and continue with the normal boot. ~ Chapter 3 In Which We Remove All Traces Of Copy Protection Using An Automated Tool That I Wrote For Just Such An Occasion [S6,D1=demuffin'd copy] [S5,D1=my work disk] ]PR#5 ]BRUN PDP T00,S01,$00 change 201ABC to 8EE9B7 Advanced Demuffin converted side B with the same RWTS I captured from side A. The RWTS is permissive enough that it doesn't require any changes to read the unprotected copy. Quod erat liberandum. --------------------------------------- A 4am crack No. 239 ------------------EOF------------------