--------------Congo Bongo-------------- A 4am crack 2018-09-22 --------------------------------------- Name: Congo Bongo Genre: action Year: 1983 Publisher: SEGA Enterprises Platform: Apple ][+ or later Media: 5.25-inch disk Sides: 1 OS: custom ~ 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) errors on tracks $01, $21, $22 copy crashes shortly after boot Copy ][+ nibble editor Tracks $01, $21, and $22 appear to be unformatted, but I suspect one of them is actually a cleverly disguised protection track. Other tracks are only lightly protected with a modified epilogue ($DE $A9 $EB instead of $DE $AA $EB) Disk Fixer with the proper epilogue, I can read all sectors on all tracks other than tracks $01, $21, and $22 Passport converts disk to standard format (normalizing the epilogues) but no patches So we're going to do this the old fashioned way. Excellent. Why didn't COPYA work? modified epilogues Why didn't Locksmith FDB work? modified epilogues Why didn't my EDD copy work? I don't know. Probably a runtime check against one of those unreadable tracks. Next steps: 1. Trace the boot 2. Find and disable the runtime check 3. Declare victory (*) (*) go to the gym ~ Chapter 1 In Which We Brag About Our Humble Beginnings I have two floppy drives, one in slot 6 and the other in slot 5. My "work disk" (in slot 5) runs Diversi-DOS 64K, which is compatible with Apple DOS 3.3 but relocates most of DOS to the language card on boot. This frees up most of main memory (only using a single page at $BF00..$BFFF), which is useful for loading large files or examining code that lives in areas typically reserved for DOS. [S6,D1=original disk] [S5,D1=my work disk] The floppy drive firmware code at $C600 is responsible for aligning the drive head and reading sector 0 of track 0 into main memory at $0800. Because the drive can be connected to any slot, the firmware code can't assume it's loaded at $C600. If the floppy drive card were removed from slot 6 and reinstalled in slot 5, the firmware code would load at $C500 instead. To accommodate this, the firmware does some fancy stack manipulation to detect where it is in memory (which is a neat trick, since the 6502 program counter is not generally accessible). However, due to space constraints, the detection code only cares about the lower 4 bits of the high byte of its own address. Stay with me, this is all about to come together and go boom. $C600 (or $C500, or anywhere in $Cx00) is read-only memory. I can't change it, which means I can't stop it from transferring control to the boot sector of the disk once it's in memory. BUT! The disk firmware code works unmodified at any address. Any address that ends with $x600 will boot slot 6, including $B600, $A600, $9600, &c. ; copy drive firmware to $9600 *9600 60 Now the boot gets slightly further, swinging out to a higher track before grinding the disk and crashing. Which means I get to patch the RWTS so it can read itself. Returning to my work disk and restoring the captured track 0 code to $B500+, I go spelunking and find a DOS-shaped RWTS except everything is in the wrong place. *B7FEL ; match data field epilogue B7FE- BD 8C C0 LDA $C08C,X B801- 10 FB BPL $B7FE B803- C9 DE CMP #$DE B805- D0 14 BNE $B81B B807- EA NOP B808- BD 8C C0 LDA $C08C,X B80B- 10 FB BPL $B808 ; I can change this $A9 to $AA B80D- C9 A9 CMP #$A9 <-- ! B80F- F0 08 BEQ $B819 *B864L ; match address field epilogue B864- BD 8C C0 LDA $C08C,X B867- 10 FB BPL $B864 B869- C9 DE CMP #$DE B86B- D0 AE BNE $B81B B86D- EA NOP B86E- BD 8C C0 LDA $C08C,X B871- 10 FB BPL $B86E ; I can change this $A9 to $AA B873- C9 A9 CMP #$A9 <-- ! B875- D0 A4 BNE $B81B B877- EA NOP ; match all three epilogue nibbles ; after the address field (unusual) B878- BD 8C C0 LDA $C08C,X B87B- 10 FB BPL $B878 B87D- C9 EB CMP #$EB <-- ? B87F- D0 9A BNE $B81B Let's patch the RWTS so it can read standard epilogues, and also let it ignore the third epilogue nibble after the address field. (The final "release" of this crack will be a .dsk file, so it will be up to emulators to recreate the standard structure of the disk. Guess what? Some of them recreate only two nibbles after the address epilogue, because that's all standard DOS 3.3 requires.) ; normalize second epilogue nibbles T00,S03,$0E: A9 -> AA T00,S03,$74: A9 -> AA ; ignore third address epilogue nibble T00,S03,$80: 9A -> 00 Rebooting with these RWTS patches in place should allow the disk to read itself, stop the grinding, and load the game. ]PR#6 ...boots, crashes... I have missed something. ~ Chapter 6 The Missing Manual It turns out the RWTS doesn't just try to match three epilogue nibbles after the address field. Immediately after matching those three nibbles, we see this weirdness: ; intentionally burning some CPU ; cycles (7 of them) with pointless ; stack manipulation B881- 48 PHA B882- 68 PLA ; store next two nibbles in zero page B883- BD 8C C0 LDA $C08C,X B886- 10 FB BPL $B883 B888- 85 06 STA $06 B88A- EA NOP B88B- EA NOP B88C- BD 8C C0 LDA $C08C,X B88F- 10 FB BPL $B88C B891- 85 07 STA $07 B893- 18 CLC B894- 60 RTS A quick search for "A5 06" (loading the accumulator with zero page $06) finds a routine at -- dun dun dun -- $B62E, which is called from the bootloader (at $0854): *B62EL ; From what I can gather, $B623 is the ; sector number, $B622 is the track ; number, and $B624/25 is the address. ; So we're reading T0A,S00 into $BA21, ; overwriting the protection routine ; that was there earlier. B62E- A9 00 LDA #$00 B630- 8D 23 B6 STA $B623 B633- 85 10 STA $10 B635- A9 0A LDA #$0A B637- 8D 22 B6 STA $B622 B63A- A9 21 LDA #$21 B63C- 8D 24 B6 STA $B624 B63F- A9 BA LDA #$BA B641- 8D 25 B6 STA $B625 ; call RWTS to do a read B644- 20 1B B9 JSR $B91B ; Now check those zero page addresses ; that were set from nibbles after the ; address epilogue (in $06/$07), and ; make sure they differ from their ; previous values (in $08/$09, although ; I'm not sure where these are set). B647- A5 06 LDA $06 B649- C5 08 CMP $08 B64B- D0 11 BNE $B65E B64D- A5 07 LDA $07 B64F- C5 09 CMP $09 B651- D0 0B BNE $B65E ; If the nibbles-after-epilogue are ; the same as the previous read, try ; again, up to 8 times, but finally ; give up and halt. B653- A5 10 LDA $10 B655- 69 00 ADC #$00 B657- 85 10 STA $10 B659- C9 08 CMP #$08 B65B- D0 E7 BNE $B644 ; halt (6502 only) B65D- 02 ??? This is the same kind of protection we saw earlier on track 1, but this time the 0-bits-that-randomly-become-1-bits are spread throughout the entire disk. They're literally everywhere: every track, every sector, after every epilogue, and reading the randomness is baked into the RWTS. That seems a bit excessive, honestly. At any rate, this protection check is also easy to bypass. At $B647, immediately after the RWTS returns, I can branch to $B65E and skip the zero page comparisons altogether. ; if carry is clear after RWTS (which ; it should be, or we have bigger ; problems), branch to success path T00,S01,$47: A506 -> 9015 ]PR#6 ...works, and it is glorious... Quod erat liberandum. --------------------------------------- A 4am crack No. 1818 ------------------EOF------------------