--------------Dive Bomber-------------- A 4am crack 2015-03-02 --------------------------------------- Name: Dive Bomber Genre: games/simulation Year: 1988 Authors: Acme Animation, Inc. Publisher: Epyx Media: single-sided 5.25-inch floppy OS: custom Other versions: DataWiz / 6502 Crew ~ 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 just reboots Copy ][+ nibble editor modified address and data epilogues (FF FF EB) Disk Fixer ["O" -> "Input/Output Control"] set Address Epilogue to "AA DE EB" set Data Epilogue to "AA DE EB" all tracks readable T00,S00 -> custom boot that relocates to $0200 no evidence of disk catalog anywhere no evidence of any standard OS Why didn't COPYA work? modified epilogue bytes Why didn't Locksmith FDB work? ditto Why didn't my EDD copy work? probably a nibble check during boot Next steps: 1. use Super Demuffin to convert disk to standard format 2. patch RWTS to read standard format (if necessary) 3. find nibble check and bypass it ~ Chapter 1 In Which Our Adventure Begins But We Encounter Ominous Foreshadowing Almost Immediately [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 I'll look at that later. First I want to use Super Demuffin to convert the disk to a standard format. ]BRUN SUPER DEMUFFIN --v-- SUPER-DEMUFFIN AND FAST COPY Modified by: The Saltine/Coast to Coast Address prologue: D5 AA 96 Address epilogue: FF FF EB DISK ^^^^^ ORIGINAL was "DE AA"-------+++++ Data prologue: D5 AA AD Data epilogue: FF FF EB ^^^^^ was "DE AA"-------+++++ Ignore write errors while demuffining! D - Edit parameters - Advance to next parm - Exit edit mode R - Restore DOS 3.3 parameters O - Edit Original disk's parameters C - Edit Copy disk's parameters G - Begin demuffin process --^-- Pressing "G" switches to the Locksmith Fast Disk Copy UI. --v-- LOCKSMITH 7.0 FAST DISK BACKUP R................................... W*********************************** HEX 00000000000000001111111111111111222 TRK 0123456789ABCDEF0123456789ABCDEF012 0................................... 1................................... 2................................... 3................................... 4................................... 5................................... 6................................... 7................................... 8................................... 9................................... A................................... B................................... C................................... D................................... 12 E................................... F..................................D [ ] PRESS [RESET] TO EXIT --^-- Hmm, can't read T22,S0F. The original disk has no problems booting, so I'm guessing that's part of the copy protection. [S6,D1=Super Demuffin'd copy] ]PR#6 ...swings to high track then hangs... Let's go find that nibble check. ~ Chapter 2 In Which We Twist And Turn, And Things Get Interesting ]PR#5 ]BLOAD BOOT0,A$800 ]CALL -151 *801L 0801- D8 CLD 0802- 78 SEI ; copy boot0 to $0200, but don't jump ; to it 0803- A0 00 LDY #$00 0805- B9 00 08 LDA $0800,Y 0808- 99 00 02 STA $0200,Y 080B- C8 INY 080C- D0 F7 BNE $0805 ; store slot number (x16) 080E- 8E 71 02 STX $0271 0811- 8E 7F 02 STX $027F ; set input and output vectors 0814- A9 FD LDA #$FD 0816- 85 37 STA $37 0818- 85 39 STA $39 081A- A9 F0 LDA #$F0 081C- 85 36 STA $36 081E- A9 1B LDA #$1B 0820- 85 38 STA $38 ; self-modifying code alert! ; change $0801 to "JMP $0247" 0822- A9 4C LDA #$4C 0824- 8D 01 08 STA $0801 0827- A9 47 LDA #$47 0829- 8D 02 08 STA $0802 082C- A9 02 LDA #$02 082E- 8D 03 08 STA $0803 ; set up ($3E) to point inside disk ; controller ROM routine so we can ; read sectors 0831- 8A TXA 0832- 4A LSR 0833- 4A LSR 0834- 4A LSR 0835- 4A LSR 0836- 09 C0 ORA #$C0 0838- 85 3F STA $3F 083A- A9 5C LDA #$5C 083C- 85 3E STA $3E ; switch to language card RAM bank 2 083E- 2C 81 C0 BIT $C081 0841- 2C 81 C0 BIT $C081 0844- 2C 83 C0 BIT $C083 ; call a subroutine that used to be at ; $0896 but was copied to low memory 0847- 20 96 02 JSR $0296 *296<896.8FFM *296L 0296- CE 7B 02 DEC $027B 0299- 30 FA BMI $0295 ; ->RTS 029B- CE 79 02 DEC $0279 029E- AD 79 02 LDA $0279 02A1- 85 27 STA $27 02A3- CE 75 02 DEC $0275 02A6- AC 75 02 LDY $0275 02A9- B9 B4 02 LDA $02B4,Y 02AC- 85 3D STA $3D 02AE- AE 71 02 LDX $0271 02B1- 6C 3E 00 JMP ($003E) This is weird, but not the weirdest thing I've ever seen on T00,S00. The disk controller ROM routine will read a sector and jump to $0801. Since $0801 now jumps to $0247, which calls this routine, this is a multi-sector read loop. It terminates when $027B goes negative and $0299 branches to $0295 (which is an RTS). The stack unwinds and execution continues at $084A after the initial JSR. $027B - sector count (starts at $08) $0279 - page (start at $00, but it's decremented before first read, so this reads 8 sectors into $F800..$FFFF) $0275 - logical sector (starts at $09, but it's decremented before the first read, so sectors $01 through $08 contain the code loaded into $F800..$FFFF) ; more self-modifying code -- ; now $0801 jumps to $025E 084A- A9 5E LDA #$5E 084C- 8D 02 08 STA $0802 ; change the parameters used by the ; multi-sector read loop so we're ; reading 7 sectors into $5F00..$66FF 084F- A9 07 LDA #$07 0851- 8D 7B 02 STA $027B 0854- A9 66 LDA #$66 0856- 8D 79 02 STA $0279 0859- A9 10 LDA #$10 085B- 8D 75 02 STA $0275 ; call multi-sector read routine, which ; returns here (because of new jump at ; $0801) and eventually continues after ; this instruction 085E- 20 96 02 JSR $0296 ; smash low-level reset vector (defense ; against copy cards) 0861- A0 05 LDY #$05 0863- B9 FA FF LDA $FFFA,Y 0866- 99 FA FF STA $FFFA,Y 0869- 88 DEY 086A- 10 F7 BPL $0863 086C- 78 SEI ; jump to next stage of the boot 086D- 4C 00 5F JMP $5F00 ~ Chapter 3 In Which We Bump Into An Old Friend Who Has Grown Mean And Crotchety I need to capture the code at $5F00 (called from $086D). *9600 *C500G ... ]BSAVE BOOT1 5F00-65FF,A$5F00,L$700 ]CALL -151 *5F00L 5F00- A9 00 LDA #$00 5F02- 8D DF FF STA $FFDF ; probably positioning the drive head ; to track $22 5F05- A9 44 LDA #$44 5F07- A6 2B LDX $2B 5F09- 20 A3 FB JSR $FBA3 ; initialize death counter 5F0C- A9 0A LDA #$0A 5F0E- 85 FC STA $FC ; turn on drive motor manually 5F10- A6 2B LDX $2B 5F12- BD 89 C0 LDA $C089,X 5F15- BD 8E C0 LDA $C08E,X ; secondary death counter 5F18- A9 80 LDA #$80 5F1A- 85 FD STA $FD 5F1C- C6 FD DEC $FD ; if this hits 0, nibble check fails 5F1E- F0 71 BEQ $5F91 ; subroutine looks for next available ; address field 5F20- 20 AF 5F JSR $5FAF ; can't find one --> fail immediately 5F23- B0 6C BCS $5F91 ; check if it's sector $0F 5F25- A5 F9 LDA $F9 5F27- C9 0F CMP #$0F ; loop until it is 5F29- D0 F1 BNE $5F1C Hey, now we're positioned on T22,S0F -- the one sector that I couldn't read. What a coincidence! (*) (*) not guaranteed, actual coincidence may vary 5F2B- A0 00 LDY #$00 5F2D- BD 8C C0 LDA $C08C,X 5F30- 10 FB BPL $5F2D 5F32- 88 DEY 5F33- F0 5C BEQ $5F91 5F35- C9 D5 CMP #$D5 5F37- D0 F4 BNE $5F2D ; 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 Super Demuffin 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 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.) 5F39- A0 00 LDY #$00 5F3B- BD 8C C0 LDA $C08C,X 5F3E- 10 FB BPL $5F3B 5F40- 88 DEY 5F41- F0 4E BEQ $5F91 ; fail 5F43- C9 E7 CMP #$E7 5F45- D0 F4 BNE $5F3B 5F47- BD 8C C0 LDA $C08C,X 5F4A- 10 FB BPL $5F47 5F4C- C9 E7 CMP #$E7 5F4E- D0 41 BNE $5F91 ; fail 5F50- BD 8C C0 LDA $C08C,X 5F53- 10 FB BPL $5F50 5F55- C9 E7 CMP #$E7 5F57- D0 38 BNE $5F91 ; fail ; kill some time to get out of sync ; with the "proper" start of nibbles) 5F59- BD 8D C0 LDA $C08D,X 5F5C- A0 10 LDY #$10 5F5E- 24 80 BIT $80 ; 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) 5F60- BD 8C C0 LDA $C08C,X 5F63- 10 FB BPL $5F60 5F65- 88 DEY 5F66- F0 29 BEQ $5F91 5F68- C9 EE CMP #$EE 5F6A- D0 F4 BNE $5F60 5F6C- EA NOP 5F6D- EA NOP ; store next 8 nibbles in zero page 5F6E- A0 F8 LDY #$F8 5F70- BD 8C C0 LDA $C08C,X 5F73- 10 FB BPL $5F70 5F75- 99 00 00 STA $0000,Y 5F78- EA NOP 5F79- C8 INY 5F7A- 30 F4 BMI $5F70 5F7C- A9 00 LDA #$00 5F7E- A8 TAY 5F7F- 85 F0 STA $F0 5F81- A2 02 LDX #$02 5F83- A9 F8 LDA #$F8 5F85- 20 9E 5F JSR $5F9E *5F9EL ; decrypt part of the RWTS based on the ; magic nibble sequence 5F9E- 85 F1 STA $F1 5FA0- B5 F8 LDA $F8,X 5FA2- 51 F0 EOR ($F0),Y 5FA4- 91 F0 STA ($F0),Y 5FA6- 88 DEY 5FA7- D0 F7 BNE $5FA0 5FA9- E6 F1 INC $F1 5FAB- CA DEX 5FAC- 10 F2 BPL $5FA0 5FAE- 60 RTS This is particularly evil, because it means I can't just bypass this nibble check. Part of the RWTS ($F800..$F9FF) is encrypted on disk, and the key to decrypt it is out-of-phase in the unreadable T22,S0F. *5F88L ; move drive head back to track $00 5F88- A6 2B LDX $2B 5F8A- 98 TYA 5F8B- 20 A3 FB JSR $FBA3 ; continue with real boot1 code (now ; decrypted) 5F8E- 4C 00 F8 JMP $F800 ; The Badlands -- decrement death ; counters and eventually reboot 5F91- C6 FC DEC $FC 5F93- F0 03 BEQ $5F98 5F95- 4C 18 5F JMP $5F18 5F98- EE F4 03 INC $03F4 5F9B- 6C FC FF JMP ($FFFC) I'm going to need to trace past this nibble check, then interrupt it before it jumps to the (decrypted) $F800 to load the game. ~ Chapter 4 In Which We Decide We Don't Need Friends Like That Anyway, So We Steal His Key And Run Away, I Don't Know, This Analogy Got Weird *9600