---------------Pitfall II-------------- A 4am crack 2015-11-19 --------------------------------------- Name: Pitfall II: Lost Caverns Genre: arcade Year: 1984 Credits: Designed by David Crane Apple II port by Rex E. Bradford, Microsmiths Publisher: Activision, Inc. Media: single-sided 5.25-inch floppy OS: custom with DOS 3.3 bootloader Previous cracks: The Syndicate The Redhead Similar cracks: #498 H.E.R.O. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA immediate disk read error Locksmith Fast Disk Backup able to read a few sectors from track $00 (specifically, 0, 4, 5, 6, 7, 8, 9, A, B, and F) but nothing else EDD 4 bit copy (no sync, no count) no errors, but copy grinds endlessly Copy ][+ nibble editor modified prologues and epilogues on track 1+ (and those unreadable sectors on track 0) address = AA D5 AB / DE AB * data = AA D5 EB / ED AA EB --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 03 START: 2E71 LENGTH: 015F 2E60: 96 96 96 96 FD FA AB B7 VIEW 2E68: F3 E5 ED AA EB FF FF FF ^^^^^^^^ data epilogue 2E70: FF FD CA F3 B4 FF DB B7 2E78: AD BF D7 AB F7 AA D5 AB ^^^^^^^^ address prologue 2E80: FF FE AB AB AF AF FB FA <-2E81 ^^^^^ ^^^^^ ^^^^^ ^^^^^ v=255 t=$03 s=$0F chksm 2E88: DE AB E9 FF D3 EE BD EB ^^^^^ address epilogue 2E90: AF ED FF DB B7 AA D5 EB ^^^^^^^^ data prologue 2E98: F9 DD DB 9E EF 9D BD CF 2EA0: F4 B6 AD 9A 9E D7 E9 EA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- Disk Fixer ["O" -> "Input/Output Control"] set Address Prologue to "AA D5 AB" set Address Epilogue to "DE AB EB" set Data Prologue to "AA D5 EB" set Data Epilogue to "ED AA EB" Success! T01-T09 readable! T11 has a standard DOS 3.3 disk catalog with a small HELLO in BASIC (probably a ruse) all other tracks (T0A-T10, T13+) are formatted but blank Why didn't COPYA work? modified prologues/epilogues Why didn't Locksmith FDB work? modified prologues/epilogues Why didn't my EDD copy work? I don't know. Disk grinding usually points to a structural protection, but I was able to read the disk with a sector editor once I modified the prologues and epilogues. So maybe a runtime protection check that tries endlessly? 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 But Get Distracted When We Stop And Smell The RWTS [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 Hmm, my AUTOTRACE scripts captured the boot1 but didn't think it contained a DOS 3.3-shaped RWTS. That usually means something... interesting... is afoot. ]BLOAD BOOT1,A$2600 ]CALL -151 ; copy most of boot1 except the last ; page (Diversi-DOS 64K uses $BFxx) *B600<2600.2EFFM *B700L ; stashing the boot slot (x16) B700- 8E 34 B7 STX $B734 B703- 8E 42 B7 STX $B742 ; overwriting the entire RWTS parameter ; table B706- A0 10 LDY #$10 B708- B9 33 B7 LDA $B733,Y B70B- 99 E8 B7 STA $B7E8,Y B70E- 88 DEY B70F- 10 F7 BPL $B708 B711- A0 03 LDY #$03 B713- B9 44 B7 LDA $B744,Y B716- 99 FB B7 STA $B7FB,Y B719- 88 DEY B71A- 10 F7 BPL $B713 ; call the RWTS to read a sector B71C- A9 B7 LDA #$B7 B71E- A0 E8 LDY #$E8 B720- 20 B5 B7 JSR $B7B5 ; and again, with the next sector B723- EE F1 B7 INC $B7F1 B726- EE ED B7 INC $B7ED B729- A9 B7 LDA #$B7 B72B- A0 E8 LDY #$E8 B72D- 20 B5 B7 JSR $B7B5 B72D- 20 B5 B7 JSR $B7B5 ; and jump there (presumably) B730- 4C 00 A8 JMP $A800 Several things to note here: it appears to be using the standard DOS 3.3 RWTS entry point at $B7B5. (Not shown, but that routine is also standard, calling the entry point at $BD00.) But digging a little further into the RWTS itself... now that's where it gets interesting. A lot of code has been moved around (which explains why my automated scripts didn't think there was an RWTS in here). For example, here is the code to read the data field, starting with the (modified) prologue: *B9CDL ; get first nibble of data prologue B9CD- BD 8C C0 LDA $C08C,X B9D0- 10 FB BPL $B9CD ; subroutine is just an RTS (but it ; takes 12 cycles to call and return) B9D2- 20 59 BA JSR $BA59 ; $AA is OK B9D5- C9 AA CMP #$AA B9D7- F0 04 BEQ $B9DD ; but $D5 is also OK B9D9- C9 D5 CMP #$D5 B9DB- D0 EA BNE $B9C7 B9DD- EA NOP ; get second nibble of data prologue B9DE- BD 8C C0 LDA $C08C,X B9E1- 10 FB BPL $B9DE ; $D5 is OK B9E3- C9 D5 CMP #$D5 B9E5- F0 04 BEQ $B9EB ; but so is $AA B9E7- C9 AA CMP #$AA B9E9- D0 EA BNE $B9D5 B9EB- A0 56 LDY #$56 ; third nibble B9ED- BD 8C C0 LDA $C08C,X B9F0- 10 FB BPL $B9ED ; $EB is OK B9F2- C9 EB CMP #$EB B9F4- F0 04 BEQ $B9FA ; and so is $AD B9F6- C9 AD CMP #$AD B9F8- D0 DB BNE $B9D5 Weird. So this RWTS will accept the modified data prologue ("AA D5 EB"), but it will also accept the standard data prologue ("D5 AA AD"). I've seen this sort of "double RWTS" in other programs that need to write to user- formatted data disks, but as far as I know, this game is strictly read-only. But wait, it gets better. After the standard denibblizing routine, this is the code to find the data epilogue: *BA2AL ; get first nibble of data epilogue BA2A- BD 8C C0 LDA $C08C,X BA2D- 10 FB BPL $BA2A ; $DE is OK BA2F- C9 DE CMP #$DE BA31- F0 1C BEQ $BA4F ; $ED is also OK BA33- C9 ED CMP #$ED BA35- D0 21 BNE $BA58 ; but if we find an $ED, we kill even ; more time (cycle counts in margin) BA37- 20 59 BA JSR $BA59 | 12 BA3A- EA NOP | 2 BA3B- EA NOP | 2 BA3C- EA NOP | 2 ; now look at the data latch one more ; time BA3D- BD 8C C0 LDA $C08C,X ; because we killed so much time ; already, this branch will only be ; taken if there was NOT an extra ; "timing bit" after the $ED nibble BA40- 30 16 BMI $BA58 ; found a timing bit, continue BA42- EA NOP BA43- BD 8C C0 LDA $C08C,X BA46- 10 FB BPL $BA43 BA48- C9 AA CMP #$AA BA4A- D0 0C BNE $BA58 BA4C- 4C 5A BA JMP $BA5A BA4F- BD 8C C0 LDA $C08C,X BA52- 10 FB BPL $BA4F BA54- C9 AA CMP #$AA BA56- F0 02 BEQ $BA5A ; failure ends up here (from $BA35 if ; we didn't find the first nibble of ; the epilogue, from $BA35 if we didn't ; find the second nibble, or from $BA4A ; if we didn't find the extra timing ; bit after the second nibble) BA58- 38 SEC BA59- 60 RTS ; success ends up here (from $BA4C or ; $BA56) BA5A- 18 CLC BA5B- 60 RTS This explains why my EDD bit copy would just grind forever. The copy doesn't have those extra timing bits in the right places (after the second epilogue nibble after each data field), so the comparison at $BA40 fails and jumps to $BA58, which sets the carry flag to tell the caller that it couldn't read the sector. The RWTS thinks every sector on the disk is bad. Which, in a sense, is true -- it's "bad" because it's not an original. There's no separate runtime protection check. The test of originality is baked into the RWTS itself. ~ Chapter 2 In Which We Get On With The Business At Hand On the bright side, this RWTS is enough like DOS 3.3 that I should be able to feed it directly into Advanced Demuffin and be able to read the original disk. *BRUN ADVANCED DEMUFFIN 1.5 ["5" to switch to slot 5] ["R" to load a new RWTS module] --> At $B6, load "BOOT1" 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 ...crashes at $BF02... Wait, what? Poking around in the monitor (since, you know, I just crashed into it), I discover something odd: boot1 is being loaded, but it's being loaded in all the wrong places. $BD00 looks correct, but what is this? *B700L B700- 8C C0 10 STY $10C0 B703- FB ??? B704- 59 00 BC EOR $BC00,Y B707- A4 26 LDY $26 B709- 99 00 BC STA $BC00,Y B70C- D0 EE BNE $B6FC B70E- 84 26 STY $26 That is not the bootloader code I saw after I captured the boot sequence from my work disk. (Cross-checking with the "BOOT1" file I captured, that code belongs at $BA00.) Other pages are similarly out of place. This can only mean one thing: the the sector order is wrong. ~ Chapter 3 In Which The Original Disk Strikes Back [S6,D1=demuffin'd copy] [S5,D1=my work disk] ]PR#6 ...crashes... Turning to my trusty Disk Fixer sector editor, I see that the sectors on T00 are no longer in a "weird order" like the original disk. T00,S01 is custom, but it appears to be loaded at $B700. T00,S02-S09 are the RWTS. This is just like a DOS 3.3 disk and quite unlike the original disk. Suddenly it clicks: this disk's logical sectors are mapped in a different order than usual. Here's T00,S00, split for clarity: --v-- -------------- DISK EDIT -------------- TRACK $00/SECTOR $00/VOLUME $FE/BYTE$00 --------------------------------------- $00:>01X-~ $18: 08 6D FF 08 8D FE 08 AE H-.H.~H. $20: FF 08 30 15 BD 4D 08 85 .H0U=MH. $28: 3D CE FF 08 AD FE 08 85 =N.H-~H. $30: 27 CE FE 08 A6 2B 6C 3E 'N~H&+,> $38: 00 EE FE 08 EE FE 08 20 @n~Hn~H $40: 89 FE 20 93 FE 20 2F FB .~ .~ /{ $48: A6 2B 6C FD 08 &+,}H --^-- The first $4C bytes are standard. In fact, they are byte-for-byte identical to DOS 3.3. But look at the table that starts at $084D: --v-- $48: 00 07 0E @GN $50: 05 0C 03 0A 01 08 0F 06 ELCJAHOF $58: 0D 04 0B 02 09 MDKBI --^-- This is the table that the boot0 code uses to map the logical sector it wants (loaded into the X register from $08FF) to the physical sector that is stored on disk (stored in zero page $3D and referenced by the disk controller ROM routine). Here's the same table from a standard DOS 3.3 disk: --v-- $48: 00 0D 0B @MK $50: 09 07 05 03 01 0E 0C 0A IGECANLJ $58: 08 06 04 02 0F HFDBO --^-- Technically this copy of the sector table is only used by boot0. The RWTS has its own copy; usually it starts at $BFB8, but on this disk it appears to start at $BFA2. Sure enough, that table is in the same non-standard order. Now think about how Advanced Demuffin works. It uses the original disk's RWTS to read one sector at a time. "Hey," it says, "let's read track $0, sector $F." "Sure thing," replies the RWTS, and it proceeds to do exactly that. Then, using a completely separate RWTS (built into Advanced Demuffin, starting at $1500), it says "hey, let's write these 256 bytes of data to track $0, sector $F on a regular disk." In other words, Advanced Demuffin normalized the sector order for me in the processing of converting the disk to a standard format, but it didn't patch the RWTS or the boot0 code (because it never does that). T00,S00,$4D change 00 07 0E 05 0C 03 0A 01 08 0F 06 0D 04 0B 02 09 to 00 0D 0B 09 07 05 03 01 0E 0C 0A 08 06 04 02 0F And also the copy that the RWTS itself uses, which is at $BFA2: T00,S09,$A2 change 00 07 0E 05 0C 03 0A 01 08 0F 06 0D 04 0B 02 09 to 00 0D 0B 09 07 05 03 01 0E 0C 0A 08 06 04 02 0F ]PR#6 ...works... As we saw earlier, the RWTS already has "double" logic to accept either the modified prologues/epilogues or the standard ones. Even better (for us), the code that checked for a timing bit only triggered if it found a modified epilogue. Now that we've converted the disk to standard prologues/epilogues, we don't need to change the RWTS at all (beyond the sector order patch). Quod erat liberandum. --------------------------------------- A 4am crack No. 499 ------------------EOF------------------