-----------Nuclear Reactions----------- A 4am crack 2015-08-07 --------------------------------------- Name: Nuclear Reactions Genre: educational Year: 1986 Authors: Greneker and Associates Publisher: D.C. Heath and Company Media: single-sided 5.25-inch floppy OS: Diversi-DOS (T02,S02 has the string "C1983 DSR" backwards) Previous cracks: none Similar cracks: Classifying Animals With Backbones (crack no. 204) ~ 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 091 FREE B 002 NOISE B 002 UNPACK B 002 FPMOD *B 013 HRCG B 005 SET B 003 SHAPE B 009 LOGO B 033 GEIGER COUNTER B 033 SOURCE.PIC B 033 HELP B 033 ACT4.PIC B 033 OV.4.PIC B 033 OV.3.PIC A 006 HELLO A 007 MENU A 016 PART1 A 016 PART2 A 020 PART3 A 020 PART4 A 006 OVERVIEW A 014 OV.1 A 013 OV.2 A 013 OV.3 A 016 OV.4 T 007 TEMPDATA *T 002 Polonium-210 *T 002 Strontium-90 *T 002 Cobalt-60 *T 002 Unknown 1 *T 002 Unknown 2 *T 002 Unknown 3 ]RUN HELLO ...hangs... ]PR#5 ... ]LOAD HELLO,S6,D1 ...hangs... That's a neat trick. I have no idea what's going on. (I get similar results with the other BASIC programs.) ]PR#5 ... ]TLIST TEMPDATA,S6,D1 Argon-39,0 0,4 Argon-41,1 1293,78 0,5 Beryllium-10,0 0,6 Cerium-141,1 145,48 581,7 ... That seems to work. Which, honestly, just makes the previous failures more mysterious. 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. (So why did I bother documenting it all? Don't ask me; you're the one who read this far.) 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. 396 ------------------EOF------------------