----------The Quest revision 2--------- A 4am crack 2015-08-13 --------------------------------------- Name: The Quest Version: revision 2 (not explicitly versioned, but this edition features double hi-res graphics and lists additional credits for them) Genre: adventure Year: 1984 Credits: Dallas Snell, Joe Toler, Joel Rea (original programming) Marsha & Steve Meuse (double hi-res conversion) Publisher: Penguin Software Media: double-sided 5.25-inch floppy OS: DOS 3.3 Previous cracks: none Side B is copyable with COPYA, but booting it simply says "PLEASE TURN OVER THE DISK." and reboots endlessly until you comply. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA (on side A) immediate disk read error Locksmith Fast Disk Backup unable to read any track EDD 4 bit copy (no sync, no count) works Copy ][+ nibble editor modified epilogue bytes ("DA AA EB" instead of "DE AA EB") odd-numbered tracks (1, 3, 5...) also have a modified address prologue ("D4 AA 96" instead of "D5 AA 96") Disk Fixer ["O" -> "Input/Output Control"] set both Epilogues to "DA AA EB" -> even-numbered tracks readable T00 looks like DOS 3.3 boot0/boot1 set Address Prologue to "D4 AA 96" -> odd-numbered tracks also readable T01 looks like a full DOS 3.3 T01,S09 -> startup program is "QA" Why didn't COPYA work? modified prologue/epilogue bytes Why didn't Locksmith FDB work? modified prologue/epilogue bytes EDD worked. What does that tell us? no half or quarter tracks almost certainly no nibble check (just structural changes to prologues and epilogues) Next steps: 1. capture RWTS with AUTOTRACE 2. convert disk to standard format with Advanced Demuffin 3. patch RWTS to read standard format ~ Chapter 1 In Which We Attempt To Use The Original Disk As A Weapon Against Itself And It Goes Flawlessly [S6,D1=original disk] [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 ]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 --^-- ]PR#5 ... ]CATALOG,S6,D2 C1983 DSR^C#254 004 FREE *B 008 QUEST *B 053 TP *B 002 ARRAY *B 002 ARRAY.I% *B 002 ARRAY.D% *B 003 CHAIN *B 012 ARRAY.F% *A 010 QB *A 053 DMQ *B 003 ID *B 002 COPYMON *B 011 PICDRAWL *B 005 DPICDRAWL.QUEST *B 020 DPICDRAWH.QUEST *B 011 DAMP 2.8 *B 017 DT1 *B 017 DT2 *B 012 DT3 *B 009 P0.SPC *B 004 P1.SPC *B 003 P2.SPC *B 003 P3.SPC *B 004 P5.SPC *B 003 P6.SPC *B 002 P7.SPC *B 003 P8.SPC *B 006 P9.SPC *B 005 P10.SPC *B 006 P11.SPC *B 003 P13.SPC *B 005 P14.SPC *B 014 P90.SPC *B 007 P91.SPC *B 006 P92.SPC *B 007 P93.SPC *B 006 P94.SPC *B 005 P95.SPC *B 005 P96.SPC *B 004 P97.SPC *B 011 P98.SPC *B 006 P99.SPC *B 010 P100.SPC *B 006 P101.SPC *B 007 P102.SPC *B 010 P103.SPC *B 006 P104.SPC *A 002 QA *B 006 P105.SPC *B 006 P106.SPC *B 005 P107.SPC *B 012 P108.SPC *B 012 P110.SPC *B 005 P111.SPC *I 002 APPLESOFT *B 009 P112.SPC *B 006 P115.SPC *B 006 P118.SPC *B 004 P120.SPC [S6,D1=demuffin'd copy] ]PR#6 ...grinds and crashes... The demuffin'd copy can't read itself. This is not unusual. ~ Chapter 2 In Which We Stop And Smell The RWTS I want to take a slight detour and look more closely at two lines of this RWTS, because they're beautiful and you should never pass up an opportunity to appreciate beauty. ]PR#5 ... ]BLOAD RWTS,A$2800 ]CALL -151 *FE89G FE93G ; disconnect DOS *B800<2800.2FFFM ; move RWTS into place *B944L ; routine to read address prologue B944- A0 FC LDY #$FC B946- 84 26 STY $26 B948- C8 INY B949- D0 04 BNE $B94F B94B- E6 26 INC $26 B94D- F0 F3 BEQ $B942 ; find prologue nibble #1 B94F- BD 8C C0 LDA $C08C,X B952- 10 FB BPL $B94F B954- 4A LSR <-- ! B955- 49 6A EOR #$6A <-- ! B957- D0 EF BNE $B948 ; find #2 B959- BD 8C C0 LDA $C08C,X B95C- 10 FB BPL $B959 B95E- C9 AA CMP #$AA B960- D0 F2 BNE $B954 B962- A0 03 LDY #$03 ; find #3 B964- BD 8C C0 LDA $C08C,X B967- 10 FB BPL $B964 B969- C9 96 CMP #$96 B96B- D0 E7 BNE $B954 The code to find prologue nibble #1 (specifically, the two instructions at $B954 and $B955) are the key to how this disk can read its odd-numbered tracks (with non-standard address prologue "D4 AA 96"). To understand why, we need to look at the bits. A standard address prologue starts with $D5, and the even-numbered tracks use this. In binary: $D5 = 1101 0101 After LSR: 0110 1010 = $6A But on this disk, the odd-numbered tracks have a custom address prologue that starts with $D4 instead. In binary: $D4 = 1101 0100 After LSR: 0110 1010 = $6A By starting with the address prologue and munging it with LSR + EOR #$6A, the code will match either $D5 or $D4. This allows the program disk (side A) to use any pattern of address prologues "D5 AA 96" or "D4 AA 96". They chose to alternate even and odd tracks, but at this level, the RWTS doesn't care what track it's reading. But wait, it gets better. The game writes to user-supplied DOS 3.3 disks for saved games. The RWTS always writes an address prologue of "D5 AA 96". And that's OK, because the RWTS can read that too. There's no magic to the specific pattern of alternating address prologues on even and odd tracks. The RWTS will accept "D5 AA 96" on any track; it will also accept "D4 AA 96" on any track. So there's no need to switch modes between "read a protected program disk" and "read a standard data disk." There's only one mode. Furthermore (and this is where things get really beautiful), RWTS code is time-critical between reading the last bit of one nibble and reading the first bit of the next. If it's too fast or too slow, it will get out of phase (because the disk spins independently of the CPU). Compare DOS 3.3 (cycle count in margin) B94F- BD 8C C0 LDA $C08C,X B952- 10 FB BPL $B94F B954- C9 D5 CMP #$D5 | 2 B956- D0 F0 BNE $B948 | 2 * B958- EA NOP | 2 B959- BD 8C C0 LDA $C08C,X B95C- 10 FB BPL $B959 (*) on the time-critical path, this branch is not taken, so always 2 ...and this disk's RWTS: B94F- BD 8C C0 LDA $C08C,X B952- 10 FB BPL $B94F B954- 4A LSR | 2 B955- 49 6A EOR #$6A | 2 B957- D0 EF BNE $B948 | 2 * B959- BD 8C C0 LDA $C08C,X B95C- 10 FB BPL $B959 Despite being more "flexible" (matching $D5 or $D4), this disk's RWTS uses the same number of bytes of code and runs in the same number of cycles. Nice. ~ 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 ; fix epilogue byte checking in RWTS T00,S03,$91 change DA to DE T00,S03,$35 change DA to DE ]PR#6 ...works... Quod erat liberand one more thing... ~ Chapter 4 In Which We Have A Gnawing Suspicion That We've Missed Something Important Wait a minute. Side B was already in a standard format, but side A required RWTS patching to read itself once I converted it to a standard format. So how does the original disk read side B? Wait another minute. How does the original disk read the user-supplied save game disks? Oh no. There's an RWTS swapper. They went to all that trouble to make a beautifully flexible prologue checker that didn't need separate modes, then they went with strict epilogue checking and now they need two modes after all. And I haven't found it, which probably means my cracked copy is going to fail after it saves a game (in "standard disk" mode) then tries to re-read side A (in "protected disk" mode). Let's verify that. [S6,D1=cracked copy] ]PR#6 ...game loads from the beginning... -> SAVE Name to save game under: A4AMCRACK_ INSERT A DOS 3.3 DISK THEN PRESS A KEY. [S6,D1=blank DOS 3.3 disk] [press space] RE-INSERT GAME DISK THEN PRESS A KEY. [S6,D1=cracked copy] [press space] ...disk access, then game resumes... OK, now I'm freaking out. Why does this work? All evidence suggests that the game should fail at the point where it tries to read the program disk again. But it doesn't. It works flawlessly, and I don't understand why. This is clearly unacceptable. The two memory addresses in question are $B991 (address epilogue) and $B935 (data epilogue). Turning to my trusty Disk Fixer sector editor, a search for "91 B9" yields nothing. On a lark, I also searched for "92 B9", wondering if perhaps the branch after the compare was simply NOP'd out. Still nothing. A bit desperate, I searched for "93 B9" and got lucky -- a match on T01,S04. --v-- T01,S04 ($A500) ----------- DISASSEMBLY MODE ---------- 0054:8D 93 B9 STA $B993 <-- ! 0057:8D 37 B9 STA $B937 <-- ! 005A:AD 9E B8 LDA $B89E 005D:A9 E0 LDA #$E0 005F:85 D6 STA $D6 0061:78 SEI 0062:D8 CLD 0063:60 RTS --^-- This sector is part of DOS. It's loaded at $A500, so that entry point is $A554. Another sector search for "54 A5" found a match on T01,S01. --v-- T01,S01 ($A200) ----------- DISASSEMBLY MODE ---------- 003C:60 RTS 003D:A9 00 LDA #$00 003F:4C 54 A5 JMP $A554 --^-- This sector is also part of DOS, loaded at $A200. "Beneath Apple DOS" (p. 8-9) tells me that $A23D is the entry point for the "NOMON" command. Now I'm beginning to get the picture. $A23D loads the accumulator with $00 and jumps to $A554, which puts $00 in $B993 and $B937. Here's what that would look like in memory after booting from the original disk: B98B- BD 8C C0 LDA $C08C,X B98E- 10 FB BPL $B98B ; check for non-standard epilogue... B990- C9 DA CMP #$DA ; ...but ignore it, because the branch ; has been modified to continue to the ; next instruction B992- D0 00 BNE $B994 ^^ B994- EA NOP B995- BD 8C C0 LDA $C08C,X B998- 10 FB BPL $B995 B99A- C9 AA CMP #$AA B99C- D0 A4 BNE $B942 B99E- 18 CLC B99F- 60 RTS So if you call $A23D, you'll end up with an RWTS that ignores the first epilogue byte (which varied between the original disk's side A and side B) but still checks the second. Clever. How does "NOMON" come into this? That's the hook that allows the program (which is written partially in BASIC) to call this routine -- in a roundabout way. Instead of a direct CALL, the BASIC program can just execute the DOS command "NOMON", which will eventually be routed to $A23D (as usual), which will reroute to $A554 (unusual) and make the RWTS flexible enough to read both the original program disk and user data disks (and side B). A sector search for the ASCII string "NOMON" yields no matches, but a search for the hex sequence "4E 4F 4D 4F 4E" ("NOMON" with high bit clear, like how it would be stored in a BASIC program) finds a match on T0B,S0E. --v-- T0B,S0E -------------- DISK EDIT -------------- TRACK $0B/SECTOR $0E/VOLUME $FE/BYTE$00 --------------------------------------- $00:>E7<33 0C 08 00 00 A5 AB g3LH@@%+ $08: 36 30 30 30 00 30 08 03 6000@0HC $10: 00 BA 44 24 22 42 4C 4F @:D$"BLO $18: 41 44 41 52 52 41 59 22 ADARRAY" $20: 3A BA 44 24 22 4E 4F 4D ::D$"NOM ^^^^^^^^ ^^^ $28: 4F 4E 22 3A B0 31 35 30 ON":0150 ^^^^^ ^^ $30: 00 4F 08 1E 00 AD 46 25 @OH^@-F% $38: 28 34 2C 4D 25 28 5A 29 (4,M%(Z) $40: 29 C4 AF AB 46 25 28 34 )D/+F%(4 $48: 2C 4D 25 28 5A 29 29 00 ,M%(Z))@ $50: 6A 08 23 00 AD 46 25 28 *H#@-F%( $58: 33 2C 5A 29 CD 4D 25 28 3,Z)MM%( $60: 5A 29 D0 38 31 C4 32 36 Z)P81D26 $68: 30 35 00 9D 08 24 00 B0 05@.H$@0 $70: 31 30 30 3A AD 56 D1 5A 100:-VQZ $78: C4 AD 56 D1 CF C9 33 30 D-VQOI30 --------------------------------------- BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/NORMAL --------------------------------------- COMMAND : --^-- Copy II+'s "DISK MAP" feature tells me this sector is part of the file "DMQ". --v-- DISK MAP SLOT 6 DRIVE 1 DISK VOLUME 254 FILE: DMQ TRACK 1 2 0123456789ABCDEF0123456789ABCDEF012 S0 ......**...*....................... E1 ......**...*....................... C2 ......**...*....................... T3 ......***..*....................... O4 ......***..*....................... R5 ......***..*....................... 6 ......***..*....................... 7 ......***..*....................... 8 ......***..*....................... 9 ......***..*....................... A ......***..*....................... B ......***..*....................... C .......**..*....................... D .......**..*....................... E ...........*....................... F ...........*....................... USE ARROW KEYS TO MAP OTHER FILES --^-- ]PR#5 ... ]LOAD DMQ,S6,D1 ]LIST 0 ONERR GOTO 6000 3 PRINT D$"BLOADARRAY": PRINT D $"NOMON": GOSUB 150 30 IF F%(4,M%(Z)) THEN & GOTO F%(4,M%(Z)) 35 IF F%(3,Z) AND M%(Z) = 81 THEN 2605 36 GOSUB 100: IF V < Z THEN IF V < > - 300 AND V < > - 350 AND V < > - 700 AND V < > - 750 THEN V = Z 37 IF V THEN & GOTO ABS (V) 40 PRINT G$"I'm not sure I unde rstand you.":C$ = "": GOTO 3 5 100 CD$ = "":X = FRE (0): IF C$ = "" THEN PRINT "->";: & INPUT C$: IF C$ = "" THEN GOSUB 1 50: POKE R,0: GOTO 100 ... I assume this program is CHAINed from another program that defines D$ and the other variables. Anyway, there it is, on line 3: it's executing the "NOMON" command, which has been redefined to alter the RWTS to become more flexible. There is no RWTS swapper, per se. But there is an RWTS relaxer, and it's triggered by calling "NOMON" after the game loads. No RWTS patches are required, since the crack already works. But now I know why it works, which is much more important. Quod erat liberandum. --------------------------------------- A 4am crack No. 402 ------------------EOF------------------