---------The Otters' Adventure--------- A 4am crack 2015-08-21 --------------------------------------- Name: The Otters' Adventure Genre: educational Year: 1985 Credits: - created by Intentional Educations, Inc. - written by Norma Arnow and Susan Christie Thomas with Kathleen DeBoer - programmed by Jay Roberts and Alex Rose - graphics by Lauren Sullivan Publisher: Grolier Publishing Media: single-sided 5.25-inch floppy OS: Diversi-DOS (T02,S02 has the string "C1983 DSR" backwards) Previous cracks: none Identical cracks: Nuclear Reactions (crack no. 396) EduCalc (crack no. 220) ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no errors, but the copy hangs on boot Locksmith Fast Disk Backup ditto EDD 4 bit copy (no sync, no count) ditto Copy ][+ nibble editor nothing suspicious Disk Fixer T00,S00 -> standard DOS 3.3 boot0 T00-02 -> looks like DOS 3.3 T01,S09 -> startup program is blank?! T11 -> DOS 3.3 disk catalog Why didn't any of my copies work? probably a nibble check during boot Next steps: 1. Capture bootloader with AUTOTRACE 2. Find nibble check and disable it 3. There is no step 3 ~ Chapter 1 In Which We Have A Few False Starts, Then Our Adventure Begins In Earnest [S6,D1=original 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 ]CATALOG,S6,D1 C1983 DSR^C#254 090 FREE A 002 HELLO B 006 DDMOVER B 098 TEST B 010 TITLESCR.OVR B 017 ENDGAME.OVR B 016 DECIS.OVR B 017 INSTRUC.OVR B 011 I/ERRAND1.TXT B 011 ANIMATE.OVR B 010 I/ERRAND2.TXT B 017 UTILITY.OVR B 020 IENPB.BALLOONSCENE B 016 IENPB.THROWSCENE B 015 IENPB.PARTYSCENE B 016 IENPB.TIPCAPSCENE B 014 IENPB.FISHSCENE B 003 IENC.LETTER B 010 IENC.TOWN B 005 MAP B 002 IENC.CLOUD B 005 PLAYERS B 012 I/ERRAND3.TXT B 018 IENPB.PAYOFFS B 006 IENPB.TITLEPAGE B 004 IENPB.GROL.OPEN B 012 I/ERRAND4.TXT B 004 ASCII.CHR B 013 I/ERRAND5.TXT ]RUN HELLO ?SYNTAX ERROR IN 43452 ]LIST 43452 M INPUT ROT= HOME PR# q q HOME INVERSE DRAW a 60406 FLASH UNDEF'D STATEMENT STRING TOO LONG TYPE MISMATCH TYPE MISMATCH HGR2 READ NEXT ERROR DRAW CAN'T CONTINUE ^ GOTO AT ^ SPC( TAB( COS ABS COLOR= POKE 39567 DEL SGN H STORE _ GOTO NOTRACE INT SHLOAD CONT HGR2 +q NEW COLOR= LIST < - LET CONT CONT POP ^ POKE RECALL GOSUB ON SPC( ASC RETURN SYNTAX + CAN'T CONTINUE REM ( + h VTAB REDIM'D ARRAY > UNDEF'D STATEMENT q POKE OUT OF MEMORY ILLEGAL DIRECT TYPE MISMATCH That's a neat trick. I have no idea what's going on. Let's back up. ]BLOAD BOOT1,A$2600,S5,D1 ]CALL -151 *FE89G FE93G *B600<2600.2FFFM *B700L . . nothing unusual, until... . B738- 20 03 BB JSR $BB03 *BB03L BB03- 4E 06 BB LSR $BB06 Uh oh. Self-modifying code. The 6502 processor has no instruction cache, so one instruction can literally change the next instruction in memory, and the CPU will execute the new instruction. Which is what's happening here. ~ Chapter 2 In Which We Learn The True Meaning Of Patience To capture this self-modifying code, I need to reproduce the modifications without running the modified code. I'll start with a pristine copy (at $2B00), copy it into place (at $BB00), then reproduce the modifications and inspect the results. Lather, rinse, repeat. 2000- A0 00 LDY #$00 2002- B9 00 2B LDA $2B00,Y 2005- 99 00 BB STA $BB00,Y 2008- C8 INY 2009- D0 F7 BNE $2002 200B- 4E 06 BB LSR $BB06 200E- 60 RTS *2000G *BB03L BB03- 4E 06 BB LSR $BB06 BB06- 38 SEC BB07- 6E 0A BB ROR $BB0A More self-modifying code. *200E:38 6E 0A BB 60 *2000G *BB0AL BB0A- A0 27 LDY #$27 BB0C- 6E 0F BB ROR $BB0F More. *2012:A0 27 6E 0F BB 60 *2000G *BB0FL BB0F- 6E 1B BB ROR $BB1B BB12- 6E 15 BB ROR $BB15 More. *2017:6E 1B BB 6E 15 BB 60 *2000G *BB15L BB15- 6E 1E BB ROR $BB1E BB18- 6E 25 BB ROR $BB25 BB1B- B9 00 BB LDA $BB00,Y More. *201D:6E 1E BB 6E 25 BB B9 00 BB 60 *2000G *BB1EL BB1E- 59 00 B8 EOR $B800,Y BB21- 99 00 BB STA $BB00,Y BB24- C8 INY BB25- D0 F4 BNE $BB1B More, now using the page at $B800 as an encryption key. *2026:59 00 B8 99 00 BB C8 D0 F4 60 *2000G *BB27L BB27- A0 55 LDY #$55 BB29- B9 00 BC LDA $BC00,Y BB2C- 59 00 B8 EOR $B800,Y BB2F- 99 00 BC STA $BC00,Y BB32- 88 DEY BB33- 10 F4 BPL $BB29 More. *202F:A0 55 B9 00 BC 59 00 B8 99 00 BC 88 10 F4 60 *2000G *BB35L Finally some real code. ; cover our tracks in memory (overwrite ; the call to $BB03) BB35- A9 93 LDA #$93 BB37- 8D 39 B7 STA $B739 BB3A- A9 B7 LDA #$B7 BB3C- 8D 3A B7 STA $B73A ; push an address to the stack BB3F- A9 B5 LDA #$B5 BB41- 48 PHA BB42- A9 18 LDA #$18 BB44- 48 PHA ; save some other values on the stack BB45- AD EC B7 LDA $B7EC BB48- 48 PHA BB49- AD ED B7 LDA $B7ED BB4C- 48 PHA ; set up an RWTS read BB4D- A9 00 LDA #$00 BB4F- 8D EC B7 STA $B7EC BB52- A9 06 LDA #$06 BB54- 8D ED B7 STA $B7ED BB57- A9 01 LDA #$01 BB59- 8D F4 B7 STA $B7F4 ; $BB00 is going to get overwritten by ; the RWTS (it's used as scratch space) ; so this relocates the rest of the ; copy protection routine to as-yet- ; unused memory BB5C- A0 00 LDY #$00 BB5E- B9 6A BB LDA $BB6A,Y BB61- 99 00 B4 STA $B400,Y BB64- C8 INY BB65- D0 F7 BNE $BB5E BB67- 4C 00 B4 JMP $B400 *B400 and hangs until you press something else. That part is skipped for now, but I'm guessing it's called later. Location | Description | Value -------------+------------------+------ $B474 | length of data | $03 $B475/$B476 | starting address | $A502 $B477..$B479 | data The 3 bytes at $B477 end up at $A503, which is the tail end of the RUN entry point. It's just a JMP to the code that was just patched earlier: A503- 4C 36 9E JMP $9E36 Thus, trying to break to the prompt during boot will hang until you press something else. (Even if you did manage to get to the prompt, the RUN flag would ensure you couldn't do anything useful. Defense in depth!) Location | Description | Value -------------+------------------+------ $B47A | length of data | $30 $B47B/$B47C | starting address | $B749 $B47D..$B4AC | data The $30 bytes at $B47D end up at $B74A, which is normally the part of the disk initialization routine that writes DOS to a freshly initialized disk. The new code looks like this: B74A- 60 RTS B74B- A0 20 LDY #$20 B74D- B9 59 B7 LDA $B759,Y B750- 99 00 03 STA $0300,Y B753- 88 DEY B754- 10 F7 BPL $B74D B756- 4C 00 03 JMP $0300 B759- A9 BF LDA #$BF B75B- 85 01 STA $01 B75D- A0 00 LDY #$00 B75F- 84 00 STY $00 B761- 91 00 STA ($00),Y B763- C8 INY B764- D0 FB BNE $B761 B766- C6 01 DEC $01 B768- A5 01 LDA $01 B76A- C9 08 CMP #$08 B76C- B0 F3 BCS $B761 B76E- AD 81 C0 LDA $C081 B771- 20 93 FE JSR $FE93 B774- 20 89 FE JSR $FE89 B777- 4C 00 E0 JMP $E000 Looks like this is going to be The Badlands routine that wipes main memory and exits. Location | Description | Value -------------+------------------+------ $B4AD | length of data | $01 $B4AE/$B4AF | starting address | $B7C1 $B4B0 | data | $60 This puts an RTS instruction at $B7C2, which would normally set up the RWTS parameters for writing DOS after INIT. Location | Description | Value -------------+------------------+------ $B4B1 | length of data | $03 $B4B2/$B4B3 | starting address | $9E72 $B4B4..$B4B6 | data This modifies DOS's image of the page 3 jump vectors so that will jump to $B74B, a.k.a. The Badlands. Location | Description | Value -------------+------------------+------ $B4B7 | length of data | $02 $B4B8/$B4B9 | starting address | $A396 $B4BA..$B4BB | data | 18 60 This patch neutralizes the SAVE handler at $A397 so it does nothing but claims to have succeeded. Location | Description | Value -------------+------------------+------ $B4BC | length of data | $03 $B4BD/$B4BE | starting address | $A38A $B4BF..$B4C1 | data This patch adds a "JMP $A582" to the end of the BLOAD command handler that starts at $A35D. Location | Description | Value -------------+------------------+------ $B4C2 | length of data | $32 $B4C3/$B4C4 | starting address | $A57E $B4C5..$B4F6 | data The $32 bytes at $B4C5 end up at $A57F, where they look like this: A57F- 4C 84 9D JMP $9D84 A582- 20 71 A4 JSR $A471 A585- A5 68 LDA $68 A587- 48 PHA A588- A5 67 LDA $67 A58A- 48 PHA A58B- 38 SEC A58C- AE 61 AA LDX $AA61 A58F- AC 60 AA LDY $AA60 A592- D0 01 BNE $A595 A594- CA DEX A595- 88 DEY A596- 8A TXA A597- E8 INX A598- 6D 73 AA ADC $AA73 A59B- 85 68 STA $68 A59D- AD 72 AA LDA $AA72 A5A0- 85 67 STA $67 A5A2- C6 68 DEC $68 A5A4- 20 BC A3 JSR $A3BC A5A7- CA DEX A5A8- D0 F8 BNE $A5A2 A5AA- 68 PLA A5AB- 85 67 STA $67 A5AD- 68 PLA A5AE- 85 68 STA $68 A5B0- 60 RTS The previous patch set up a jump to $A582 at the end of the BLOAD handler. It looks like this is reusing the on-the-fly decryption routine at $A3BC (already used for Applesoft programs) for binary programs as well. Encrypt all the things! Location | Description | Value -------------+------------------+------ $B4F7 | length of data | $02 $B4F8/$B4F9 | starting address | $A351 $B4FA..$B4FB | data | 9A A3 This sets up a jump to $A39A in the middle of the BSAVE command handler. Location | Description | Value -------------+------------------+------ $B4FC | length of data | $02 $B4FD/$B4FE | starting address | $A35A $B4FF..$B500 | data | A6 A3 This sets up a jump to $A3A6 at the end of the BSAVE command handler. Location | Description | Value -------------+------------------+------ $B501 | length of data | $15 $B502/$B503 | starting address | $A396 $B504..$B518 | data The $15 bytes at $B504 end up at $A397, overwriting the SAVE command handler. They look like this: A397- EA NOP A398- 18 CLC A399- 60 RTS A39A- 8D 61 AA STA $AA61 A39D- 8C 60 AA STY $AA60 A3A0- 20 E0 A3 JSR $A3E0 A3A3- 4C 85 A5 JMP $A585 A3A6- 20 FF A3 JSR $A3FF A3A9- 4C 85 A5 JMP $A585 It looks like this *encrypts* binary files on-the-fly. One branch of the BSAVE handler jumps to $A39A; the other jumps to $A3A6. The latter routes the data in memory through the routine at $A3FF, which serves as both an encryption and decryption routine (it's just XOR after all). That's it. The next byte is $00, so the BEQ at $B583 branches and the patch loop exits gracefully via RTS. The result is a really messed up DOS that is maximally unfriendly to prying eyes and maximally incompatible with any other version of DOS. It decrypts both BASIC and binary files on the fly, traps , traps , sets the RUN flag, and disables the SAVE command. It does not, however, hinder copying the disk itself. The only patch I need to bypass the actual copy protection is at $BB03, to unconditionally push $B5/$18 to the stack and jump to $B793. BB03- A9 B5 LDA #$B5 BB05- 48 PHA BB06- A9 18 LDA #$18 BB08- 48 PHA BB09- 4C 93 B7 JMP $B793 T00,S05,$03 change "4E 06 BB 71 6E 0A BB 40 27" to "A9 B5 48 A9 18 48 4C 93 B7" Quod erat liberandum. --------------------------------------- A 4am crack No. 411 ------------------EOF------------------