----PlayWriter: Adventures in Space---- A 4am crack 2020-12-31 --------------------------------------- Name: PlayWriter: Adventures in Space Genre: productivity Year: 1984 Publisher: Woodbury Computer Associates Platform: Apple ][+ or later Media: 5.25-inch disk Sides: 1 OS: DOS 3.3 Previous cracks: none ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA fails about halfway through Locksmith Fast Disk Backup copies everything except T14,S06, but copy loads almost all the way then says "PlayWriter Can ONLY Be Run from Your Original Master Diskette" and hangs EDD 4 bit copy (no sync, no count) works Copy ][+ nibble editor "bad" sector seems to exist and appears normal Disk Fixer as expected, reading the "bad" sector fails, but going to INPUT/OUTPUT CONTROL (press "O") and setting CHECKSUM ENABLED = NO, the sector is readable and appears empty Why didn't COPYA work? intentionally corrupted sector Why didn't Locksmith FDB work? presumably a runtime check to ensure the corrupted sector is unreadable EDD worked. What does that tell us? probably just a runtime check on the bad sector and not anything crazy like half or quarter tracks Booting the original disk, I hear the familiar disk grinding / recalibration of a failed attempt to read a bad sector, but it's very late in the boot process -- after the title screen, after the copyright text screen, while it says "loading Playfiler". Tracing from the earliest stage of the boot process is overkill, so I will tackle it from another direction. ~ Chapter 1 In Which We Flail in All Directions Firstly, always search for the error message, in case the protection code is nearby. I searched for different parts of the (rather long) protection failure message, and eventually I found it in low-ASCII on track $1D: --v-- -------------- DISK EDIT -------------- TRACK $1D/SECTOR $08/VOLUME $FE/BYTE$F8 --------------------------------------- ... $C8: 54 CF 0D 49 0B 65 00 50 TO.I.e.P $D0: 6C 61 79 57 72 69 74 65 layWrite $D8: 72 20 43 61 6E 20 4F 4E r Can ON $E0: 4C 59 20 42 65 20 52 75 LY Be Ru $E8: 6E 20 66 72 6F 6D 20 59 n from Y $F0: 6F 75 72 20 4F 72 69 67 our Orig $F8:>69<6E 61 6C 20 4D 61 73 inal Mas --^-- Unfortunately, the surrounding bytes do not appear to be code. At least, they are recognizable as neither assembly language nor BASIC. Secondly, always check the disk map in Copy ][+, in case the corrupted sector is part of a file. (I have seen this on other disks. It allows you to write the protection logic entirely in BASIC or some other high-level language.) --v-- TRACK 1 2 0123456789ABCDEF0123456789ABCDEF012 S0 ...GALUWT MKEH.AAAAAGDGGEEDCBBBB E1 ...GALUWT MKEH.AAAAAGDGGEEDCBBBB C2 ...RAFUW MKEH.AAAAAGDGGEEDBBBBB T3 ...RAFUW Q MKEH.AAAAAGDGGEEDBBBBB O4 ...RAFUW QJMJEH.AAAAAGGGGEEDBBBBB R5 ...RACPW OJXJEH.AAAAAGGGGEEDBBBBB 6 ...RACPW OMXJEH.AA.AAGGGFEEDBBBBB 7 ...RABPW MMXIIE.AAAAAGGGFEEDBBBBB 8 ...RABPW MMNIID.AAAAAGGGFEEDBBBBB 9 ...RABPW MN ID.AAAAAGGGFEEDBBBBB .A ...RABZW MK ID.AAAAAGGGFEEDBBBBB B ...RAYZV S MK ID.AAAAAAGGFEECBBBBB C ...RAYIV S MK ID.AAAAAAGGFEDCBBBBB D ...RLYIV Q MK ID.AAAAAAGGFEDCBBBBB E ...RLYIH MK HD.AAAAAAGGFEDCBBBBB F ...RLYWH MKEHD.AAAAAAGGEEDCBBBBB --^-- Tracks 0-2 are DOS; track $11 is the disk catalog. The only sector that is marked as used but not mapped to a file is... T14,S06, the unreadable sector. Combined with the fact that the original disk audibly grinds like any DOS 3.3 disk would when it tries and fails to read a sector, this strongly implies that I am looking for a standard sector read followed by code that checks that the read failed successfully. How do you read a sector under DOS 3.3? Since there's no file mapped to that sector, we're probably looking for an assembly language routine. (It would be difficult, though not impossible, to set up the parameters entirely from BASIC.) - JSR $BD00, the most "low-level" entry point that doesn't involve fiddling with softswitches. Searching the disk for "20 00 BD" finds only the one expected match on T00,S01, which is part of DOS. - JSR $B7B5, the "higher level" entry point. Searching the disk for "20 B5 B7" finds only the expected matches within the DOS area on tracks 0-2. I am nowhere. ~ Chapter 2 In Which We Have A Flash of Insight (*) And Finally Get Somewhere (*) Luck Still nowhere in finding the protection routine, I have a crazy idea: put my original disk in slot 6, but boot my non-working copy from slot 5. Hear me out. The disk boots DOS 3.3 (seemingly unmodified) and the program is file-based, which means it should boot from any slot unless they're going out of their way to force slot 6. But the protection routine might assume the disk is in slot 6. (Many protection routines do this.) [S6,D1 = original disk] [S5,D1 = non-working copy] ]PR#5 ...read read read... ...switches to slot 6 briefly... ...grinds... ...protection check passes... ...continues to main menu... Aha! But how does this help us? I'm not sure yet. But the bad sector is track $14, sector $06. Maybe the protection routine has its own RWTS parameter table, including a hard-coded reference to slot 6? Turning once again to my trusty Disk Fixer sector editor, a search for the byte sequence $14 $06 finds several matches: --v-- ------------- DISK SEARCH -------------- $0D/$03-$05 $0D/$03-$0E $0D/$08-$16 $13/$0E-$4A $1C/$0C-$E6 --^-- Most of those are unrelated data... except the match on track $1C, which looks like this: --v-- -------------- DISK EDIT -------------- TRACK $1C/SECTOR $0C/VOLUME $FE/BYTE$E6 --------------------------------------- $B8: CF 0B 5A B5 19 BB 8F D0 OKZ5Y;.P $C0: 2B D6 B9 61 CF A9 00 85 +V9!O)@. $C8: 09 A9 61 A0 FA 20 D9 03 I)! z YC $D0: AD 07 62 C9 40 D0 05 A9 -G"I@PE) $D8: 00 85 08 60 A9 01 D0 F9 @.H )APy $E0: 00 00 01 60 01 FE>14<06 @@A A~TF $E8: 0B 62 89 52 00 00 01 00 K".R@@A@ $F0: 00 60 01 00 01 EF D8 00 @ A@AoX@ $F8: 00 00 00 00 00 00 00 00 @@@@@@@@ --^-- Thta is definitely an RWTS parameter table, starting at byte offset $E2. As I thought, it hard-codes the slot and drive ($60 for slot 6, $01 for drive 1) as well as the track and sector number of the intentionally corrupted sector. But wait, there's more! Immediately before this parameter table looks like executable code. --v-- ----------- DISASSEMBLY MODE ---------- 00C5:A9 00 LDA #$00 00C7:85 09 STA $09 ; address of RWTS parameter table 00C9:A9 61 LDA #$61 00CB:A0 FA LDY #$FA ; execute RWTS command (read) 00CD:20 D9 03 JSR $03D9 ; check RWTS error code 00D0:AD 07 62 LDA $6207 ; is it "drive error"? 00D3:C9 40 CMP #$40 ; no -> branch to failure path 00D5:D0 05 BNE $00DC ; read failed successfully (original) 00D7:A9 00 LDA #$00 00D9:85 08 STA $08 00DB:60 RTS ; read unexpectedly succeeded (copy) 00DC:A9 01 LDA #$01 00DE:D0 F9 BNE $00D9 --^-- Several things to note here. Firstly, I forgot that there was an even higher- level entry point to the DOS 3.3 RWTS, the vector at $3D9. This contains a JMP $B7B5, unless you have a really old program running on a really old Apple II with less than 48K, in which case the RWTS entry point will be at a lower address like $77B5 or even $37B5. Silly me for forgetting this. Secondly, and more importantly, I see that the protection routine is not directly tied to the error message. If it fails, the only difference is the value that ends up in zero page $08 -- #$00 for an original, #$01 for a copy. To bypass the protection, we just need to ensure that $08 ends up with #$00. ; change code at offset $C9 to branch ; to success path at offset $D7 T1C,S0C,$C9: A9 61 -> F0 0E The final code looks like this: --v-- ----------- DISASSEMBLY MODE ---------- 00C5:A9 00 LDA #$00 00C7:85 09 STA $09 ; always branches 00C9:F0 0E BEQ $00D9 ... 00D9:85 08 STA $08 00DB:60 RTS --^-- Quod erat liberandum. --------------------------------------- A 4am crack No. 2303 ------------------EOF------------------