-----Now You See It, Now You Don't----- -------------Pick The Part------------- A 4am crack 2015-03-16 --------------------------------------- Name: Now You See It, Now You Don't: Pick The Part Genre: educational Year: 1987 Credits: - Designed by Donna Stanger - Programmed by Todd Rosedahl - Graphics by Barbara Wood and Scott Sahs Publisher: Sunburst Communications Media: single-sided 5.25-inch floppy OS: ProDOS 1.1.1 Other versions: none (preserved here for the first time) Identical cracks: Now You See It, Now You Don't: Was It There? Was It Missing? (4am crack no. 262) ~ 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 read errors, but copy loads ProDOS title screen, then reboots Copy ][+ nibble editor T00 has at least a few sectors, but I'm not sure how many T01+ have no visible structure at all --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 03 START: 3677 LENGTH: 13C7 3670: AA D5 FE FF E7 FF FF FF VIEW 3678: 93 F3 99 E6 99 E6 99 E6 3680: 99 E6 99 E6 99 E6 99 E6 3688: 99 E6 99 E6 99 CA AA A9 3690: 9B 9F BA B4 AA D5 FC 99 3698: E6 99 E6 99 E6 99 E6 99 36A0: E6 99 E6 CA D5 A9 E5 9A 36A8: EB 94 DD B6 BB DA DB DD 36B0: DB A7 D7 AB AB BE D9 97 --------------------------------------- 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"] "CHECKSUM ENABLED" -> "NO" T00,S00 readable T00,S0D readable T00,S0E readable nothing else Why didn't COPYA work? not a 16-sector disk (or maybe a wildly non-standard one) Why didn't Locksmith FDB work? ditto Why didn't my EDD copy work? I don't know. Probably a nibble check in the first .SYSTEM file (assuming this is really ProDOS as it claims). Converting the disk to a standard format will be a challenge. Advanced Demuffin requires a DOS 3.3-shaped RWTS, but this disk uses ProDOS (as far as I can tell). Assuming the disk even uses 16 sectors (and Copy ][+ just can't see the structure), I might be able to extract the RWTS from the PRODOS file and build an RWTS to plug into Advanced Demuffin. I've done that successfully before, but it's finicky. DOS 3.3 and ProDOS are very different beasts. Next steps: 1. Boot trace to capture PRODOS file in memory 2. Extract its RWTS routines to build a DOS 3.3-shaped RWTS file 3. Convert the disk to a standard format with Advanced Demuffin 4. Patch the bootloader and/or the PRODOS file to be able to read a standard format disk 5. Find and bypass the nibble check ~ Chapter 1 In Which We Take Our First Steps [S6,D1=original disk] [S5,D1=my work disk] ]PR#5 CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 ]CALL -151 *800<2800.28FFM *801L ; set up $801 with an "RTS" (probably ; so we can JSR $C65C later to read ; sectors) 0801- A9 60 LDA #$60 0803- 8D 01 08 STA $0801 ; save slot (x16) 0806- 86 43 STX $43 0808- 86 2B STX $2B ; munge slot into $C6 form and store it 080A- 8A TXA 080B- 4A LSR 080C- 4A LSR 080D- 4A LSR 080E- 4A LSR 080F- 09 C0 ORA #$C0 0811- 8D 38 08 STA $0838 ; set reset vector 0814- A0 CE LDY #$CE 0816- A9 08 LDA #$08 0818- 8C F2 03 STY $03F2 081B- 8D F3 03 STA $03F3 081E- A9 AD LDA #$AD 0820- 8D F4 03 STA $03F4 0823- A9 00 LDA #$00 0825- 85 09 STA $09 0827- 85 03 STA $03 ; increment physical sector number 0829- E6 3D INC $3D ; read a sector 082B- 20 36 08 JSR $0836 ; decrement sector count 082E- CE 39 08 DEC $0839 ; loop back to read more sectors 0831- D0 F6 BNE $0829 ; or continue down below 0833- 4C 40 08 JMP $0840 0836- 4C 5C C6 JMP $C65C 0839- [02] 083A- ["PRODOS"] ; execution continues here after all ; sectors are read 0840- A9 02 LDA #$02 0842- 85 02 STA $02 0844- A9 0C LDA #$0C 0846- 85 27 STA $27 ; don't know what this does yet 0848- 20 34 09 JSR $0934 This is where I need to interrupt the boot, to see what ends up at $900 (and $A00) from initial sector read loop. *9600<C600.C6FFM ; set up callback at $0840 after sector ; read loop exits 96F8- A9 4C LDA #$4C 96FA- 8D 40 08 STA $0840 96FD- A9 0A LDA #$0A 96FF- 8D 41 08 STA $0841 9702- A9 97 LDA #$97 9704- 8D 42 08 STA $0842 ; start the boot 9707- 4C 01 08 JMP $0801 ; callback is here -- copy 3 pages to ; graphics page so they survive a ; reboot 970A- A2 03 LDX #$03 970C- A0 00 LDY #$00 970E- B9 00 08 LDA $0800,Y 9711- 99 00 28 STA $2800,Y 9714- C8 INY 9715- D0 F7 BNE $970E 9717- EE 10 97 INC $9710 971A- EE 13 97 INC $9713 971D- CA DEX 971E- D0 EE BNE $970E ; turn off slot 6 drive motor 9720- AD E8 C0 LDA $C0E8 ; reboot to my work disk 9723- 4C 00 C5 JMP $C500 *BSAVE TRACE0,A$9600,L$126 *9600G ...reboots slot 6... ...reboots slot 5... ]BSAVE BOOT0 0800-0AFF,A$2800,L$300 ]CALL -151 *800<2800.2AFFM *934L . . actually boring, it's just setting up . a write translate table . Continuing at $084B... 084B- 20 EF 08 JSR $08EF *8EFL . . appears to read a sector into ($26) . Continuing at $084E... ; look for PRODOS file in disk catalog ; (string at $0839 spells "PRODOS") 084E- A9 04 LDA #$04 0850- 85 00 STA $00 0852- A9 0C LDA #$0C 0854- 85 01 STA $01 0856- A5 00 LDA $00 0858- 18 CLC 0859- 69 27 ADC #$27 085B- 85 00 STA $00 085D- B0 6F BCS $08CE 085F- A0 06 LDY #$06 0861- B1 00 LDA ($00),Y 0863- D9 39 08 CMP $0839,Y 0866- D0 EE BNE $0856 0868- 88 DEY 0869- D0 F6 BNE $0861 ; get block info for PRODOS file 086B- B1 00 LDA ($00),Y 086D- 48 PHA 086E- A0 10 LDY #$10 0870- B1 00 LDA ($00),Y 0872- C9 FF CMP #$FF 0874- D0 58 BNE $08CE 0876- C8 INY 0877- B1 00 LDA ($00),Y 0879- 85 02 STA $02 087B- C8 INY 087C- B1 00 LDA ($00),Y 087E- 85 03 STA $03 0880- A9 FF LDA #$FF 0882- 85 07 STA $07 0884- A9 00 LDA #$00 0886- 85 26 STA $26 0888- 85 00 STA $00 088A- A0 1E LDY #$1E 088C- 68 PLA 088D- C9 26 CMP #$26 088F- F0 0B BEQ $089C ; load data at $2000 0891- A0 20 LDY #$20 0893- 84 27 STY $27 ; read it 0895- 20 EF 08 JSR $08EF ; carry clear on success 0898- 90 1F BCC $08B9 ; carry set on failure 089A- B0 32 BCS $08CE ; loop to read the rest of the file 089C- 84 27 STY $27 089E- 84 01 STY $01 08A0- 20 EF 08 JSR $08EF 08A3- B0 29 BCS $08CE 08A5- E6 07 INC $07 08A7- A4 07 LDY $07 08A9- B1 00 LDA ($00),Y 08AB- 85 02 STA $02 08AD- E6 01 INC $01 08AF- B1 00 LDA ($00),Y 08B1- 85 03 STA $03 08B3- C6 01 DEC $01 08B5- 11 00 ORA ($00),Y 08B7- D0 E7 BNE $08A0 ; execution continues here after all ; sectors are read successfully -- ; turn off drive motor 08B9- BD 88 C0 LDA $C088,X ; set reset vector 08BC- A2 00 LDX #$00 08BE- A0 57 LDY #$57 08C0- A9 F2 LDA #$F2 08C2- 8E F2 03 STX $03F2 08C5- 8C F3 03 STY $03F3 08C8- 8D F4 03 STA $03F4 ; jump to the beginning of PRODOS file 08CB- 4C 00 20 JMP $2000 ; any failure ends up here 08CE- E6 27 INC $27 08D0- A0 00 LDY #$00 08D2- A6 2B LDX $2B ; turn off drive motor 08D4- BD 88 C0 LDA $C088,X ; wipe memory and never return 08D7- 20 DD 08 JSR $08DD 08DA- 4C DA 08 JMP $08DA 08DD- A9 60 LDA #$60 08DF- 91 26 STA ($26),Y 08E1- 99 00 09 STA $0900,Y 08E4- 99 00 0A STA $0A00,Y 08E7- 88 DEY 08E8- D0 F5 BNE $08DF 08EA- C6 27 DEC $27 08EC- 4C DF 08 JMP $08DF So, it really is loading ProDOS, albeit in its own special way. $08CB jumps to the code loaded from the PRODOS file at $2000. ~ Chapter 2 In Which We Take Two Steps Forward, One Step Back, One Twist Sideways, And Worry That We Just Created A New Dance Move *9600<C600.C6FFM ; save all flags and registers 96F8- 08 PHP 96F9- 48 PHA 96FA- 8A TXA 96FB- 48 PHA 96FC- 98 TYA 96FD- 48 PHA ; fill $2000..$95FF with "FD" bytes so ; I can tell how big the PRODOS file is ; later 96FE- A2 76 LDX #$76 9700- A0 00 LDY #$00 9702- A9 FD LDA #$FD 9704- 99 00 20 STA $2000,Y 9707- C8 INY 9708- D0 FA BNE $9704 970A- EE 06 97 INC $9706 970D- CA DEX 970E- D0 F4 BNE $9704 ; set up the callback after PRODOS file ; is loaded 9710- A9 23 LDA #$23 9712- 8D CC 08 STA $08CC 9715- A9 97 LDA #$97 9717- 8D CD 08 STA $08CD ; restore registers and flags 971A- 68 PLA 971B- A8 TAY 971C- 68 PLA 971D- AA TAX 971E- 68 PLA 971F- 28 PLP ; start the boot 9720- 4C 01 08 JMP $0801 ; turn off slot 6 drive motor 9723- AD E8 C0 LDA $C0E8 ; reboot to my work disk (PRODOS file ; loads at $2000, so no relocation is ; necessary) 9726- 4C 00 C5 JMP $C500 *BSAVE TRACE.PRODOS,A$9600,L$129 *BRUN TRACE.PRODOS ...reboots slot 6... ...reboots slot 5... ]CALL -151 [perusing memory, starting at $2000] It looks like $5A00 is the first page that still has repeated $FD bytes. *5A-20 =3A *BSAVE BOOT1.PRODOS,A$2000,L$3A00 Scanning through memory, I found the RWTS code. (Sorry, no magic here. It can be in a number of places, depending on the version of ProDOS. And this is *not* a standard version of ProDOS.) The RWTS is... odd. Here, for example, is the routine that reads the address field (relocated into the language card at $D316 by the time it's used): *5316L 5316- A6 3E LDX $3E 5318- A0 03 LDY #$03 531A- 8C E8 D4 STY $D4E8 531D- 8C F0 D4 STY $D4F0 5320- 84 3F STY $3F 5322- A0 02 LDY #$02 5324- CE F0 D4 DEC $D4F0 5327- D0 05 BNE $532E 5329- CE E8 D4 DEC $D4E8 532C- F0 3A BEQ $5368 ; loop will match "CA AA A9" (that's ; what's at $D4D0, a.k.a. $54D0) 532E- BD 8C C0 LDA $C08C,X 5331- 10 FB BPL $532E 5333- D9 D0 D4 CMP $D4D0,Y 5336- D0 EA BNE $5322 5338- 88 DEY 5339- 10 F3 BPL $532E ; now decode the actual address field 533B- A9 00 LDA #$00 533D- F0 03 BEQ $5342 533F- 99 A7 D4 STA $D4A7,Y ; read only one nibble 5342- BC 8C C0 LDY $C08C,X 5345- 10 FB BPL $5342 ; Address field is not 4-4 encoded! The ; values are progressively decrypted ; against the write translate table at ; $D496 (originally $5496). I won't ; show it here, but this table is also ; non-standard; it looks nothing like ; the one in "Beneath Apple DOS". 5347- 59 00 D4 EOR $D400,Y 534A- A4 3F LDY $3F 534C- C6 3F DEC $3F ; branch back to store this address ; field data in $D4A7,Y 534E- 10 EF BPL $533F ; 4th nibble is the checksum, I think 5350- A8 TAY 5351- D0 15 BNE $5368 ; then match "AA" as an address field ; epilogue 5353- BD 8C C0 LDA $C08C,X 5356- 10 FB BPL $5353 5358- C9 AA CMP #$AA 535A- D0 0C BNE $5368 ; munge one of the address field values ; into the Y register on exit (not sure ; which one) 535C- AD A9 D4 LDA $D4A9 535F- 4A LSR 5360- 4A LSR 5361- A8 TAY ; munge another value into accumulator 5362- AD AA D4 LDA $D4AA 5365- 4A LSR 5366- 4A LSR 5367- 60 RTS 5368- 38 SEC 5369- 60 RTS And here is the heart of the RWTS, the routine that matches the data prologue then converts the data field of nibbles to bytes in memory: *536AL ; set up slot-specific addresses for ; reading the data latch (normal) 536A- 8A TXA 536B- 09 8C ORA #$8C 536D- 8D B0 D3 STA $D3B0 5370- 8D BD D3 STA $D3BD 5373- 8D CF D3 STA $D3CF 5376- 8D E1 D3 STA $D3E1 5379- 8D F6 D3 STA $D3F6 537C- A0 20 LDY #$20 537E- 88 DEY 537F- 30 E7 BMI $5368 ; match "CA D5 A9" data prologue 5381- BD 8C C0 LDA $C08C,X 5384- 10 FB BPL $5381 5386- C9 CA CMP #$CA 5388- D0 F4 BNE $537E 538A- 2C A8 D4 BIT $D4A8 ; odd 538D- BD 8C C0 LDA $C08C,X 5390- 10 FB BPL $538D 5392- C9 D5 CMP #$D5 5394- D0 F0 BNE $5386 5396- 50 03 BVC $539B ; odd 5398- BD 8D C0 LDA $C08D,X ; odd 539B- BD 8C C0 LDA $C08C,X 539E- 10 FB BPL $539B 53A0- C9 A9 CMP #$A9 53A2- F0 07 BEQ $53AB 53A4- 88 DEY 53A5- 10 F4 BPL $539B 53A7- D0 BF BNE $5368 53A9- 30 7E BMI $5429 ; convert nibbles to bytes 53AB- A0 54 LDY #$54 53AD- A9 00 LDA #$00 53AF- AE 8C C0 LDX $C08C 53B2- 10 FB BPL $53AF 53B4- 5D 00 D4 EOR $D400,X 53B7- 84 3F STY $3F 53B9- 29 FC AND #$FC 53BB- AA TAX 53BC- AC 8C C0 LDY $C08C 53BF- 10 FB BPL $53BC 53C1- 59 00 D4 EOR $D400,Y 53C4- 29 FC AND #$FC 53C6- 1D 02 D5 ORA $D502,X 53C9- A4 3F LDY $3F 53CB- 99 00 D6 STA $D600,Y 53CE- AC 8C C0 LDY $C08C 53D1- 10 FB BPL $53CE 53D3- 59 00 D4 EOR $D400,Y 53D6- 29 FC AND #$FC 53D8- 1D 01 D5 ORA $D501,X 53DB- A4 3F LDY $3F 53DD- 99 55 D6 STA $D655,Y 53E0- AC 8C C0 LDY $C08C 53E3- 10 FB BPL $53E0 53E5- 59 00 D4 EOR $D400,Y 53E8- 29 FC AND #$FC 53EA- 1D 00 D5 ORA $D500,X 53ED- A4 3F LDY $3F 53EF- 99 AA D6 STA $D6AA,Y 53F2- 88 DEY 53F3- 10 BA BPL $53AF 53F5- AC 8C C0 LDY $C08C 53F8- 10 FB BPL $53F5 53FA- 59 00 D4 EOR $D400,Y 53FD- 29 FC AND #$FC 53FF- 85 3F STA $3F 5401- 4A LSR 5402- 4A LSR 5403- 05 3F ORA $3F 5405- A6 3E LDX $3E 5407- BC 8C C0 LDY $C08C,X 540A- 10 FB BPL $5407 540C- 59 00 D4 EOR $D400,Y 540F- A0 FF LDY #$FF 5411- 99 00 D6 STA $D600,Y ; appears to be a checksum byte ; (branches to "SEC" if it fails) 5414- BC 8C C0 LDY $C08C,X 5417- 10 FB BPL $5414 5419- 59 00 D4 EOR $D400,Y 541C- 29 FC AND #$FC 541E- D0 09 BNE $5429 ; match "AA" for data epilogue 5420- BD 8C C0 LDA $C08C,X 5423- 10 FB BPL $5420 5425- C9 AA CMP #$AA 5427- F0 16 BEQ $543F 5429- 38 SEC 542A- 60 RTS ... 543F- 18 CLC 5440- 60 RTS I won't do a side-by-side comparison, but this is all completely different from standard ProDOS. I don't just mean the address prologue. Even the routine that converts nibbles to bytes is different. Now what I saw in the nibble editor makes slightly more sense: --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 03 START: 3677 LENGTH: 13C7 3670: AA D5 FE FF E7 FF FF FF VIEW 3678: 93 F3 99 E6 99 E6 99 E6 3680: 99 E6 99 E6 99 E6 99 E6 3688: 99 E6 99 E6 99 CA AA A9 ^^^^^^^^ address prologue 3690: 9B 9F BA B4 AA D5 FC 99 ^^^^^^^^^^^ ^^ address epilogue address field 3698: E6 99 E6 99 E6 99 E6 99 36A0: E6 99 E6 CA D5 A9 E5 9A ^^^^^^^^ data prologue 36A8: EB 94 DD B6 BB DA DB DD 36B0: DB A7 D7 AB AB BE D9 97 --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- Porting this to a DOS 3.3-shaped RWTS is not going to be feasible. This is not just a matter of different prologue or epilogue bytes; the entire nibble- to-byte conversion scheme has been rewritten. I need to rethink my next steps. This disk is, at some level, "ProDOS." It has a custom bootloader to find and load the PRODOS file into memory; it has what appears to be an entirely rewritten floppy device driver; it also has a nibble check somewhere that I haven't even found yet. But it's not entirely custom. About 90% of this file is identical to ProDOS (version 1.1.1, as advertised on the standard ProDOS title screen that it displays during boot). If I could somehow inject a clean, working version of BASIC.SYSTEM and get this PRODOS file to load that instead of the original program, I could theoretically see the files and copy them off to a standard disk. Or maybe I could write a poor-man's Advanced Demuffin to read the disk sector by sector (well, block by block since it's ProDOS), then save the sector data and recreate the disk with a standard RWTS. Next steps: 1. Trace PRODOS file 2. Inject clean BASIC.SYSTEM into memory 3. Copy each file off the disk ~ Chapter 3 In Which We Try Variations Of Our Dance Move And Also Our RWTS [S7,D1=ProDOS hard drive, "A4AMCRACK"] [Copy ][+ 8.4] --> COPY --> FILE --> from SLOT 7, DRIVE 1 --> to SLOT 5, DRIVE 1 --> BASIC.SYSTEM OK, now I have a clean copy of the ProDOS BASIC.SYSTEM file on my DOS 3.3- based work disk. I'll get back to that. ]PR#5 ]BLOAD BOOT1.PRODOS,A$2000 ]CALL -151 *2000L . . nothing unusual, until... . ; set up to read block 2 into $0C00 ; (this is the ProDOS disk catalog) 218F- A2 00 LDX #$00 2191- 86 14 STX $14 2193- A0 02 LDY #$02 2195- A9 0C LDA #$0C 2197- 85 15 STA $15 2199- 8D 07 22 STA $2207 219C- 8C 08 22 STY $2208 219F- 8E 09 22 STX $2209 ; raw disk read (MLI $80) 21A2- 20 00 BF JSR $BF00 21A5- [80 04 22] ; on failure, jump to The Badlands 21A8- D0 19 BNE $21C3 ; check if we've read all the blocks of ; the disk catalog into memory 21AA- A0 03 LDY #$03 21AC- B1 14 LDA ($14),Y 21AE- AA TAX 21AF- 88 DEY 21B0- 11 14 ORA ($14),Y 21B2- F0 0C BEQ $21C0 21B4- B1 14 LDA ($14),Y 21B6- A8 TAY 21B7- A5 15 LDA $15 21B9- 18 CLC 21BA- 69 02 ADC #$02 21BC- C9 14 CMP #$14 21BE- 90 D7 BCC $2197 ; success path continues at $5800 21C0- 4C 00 58 JMP $5800 ; failure path ends up here 21C3- 4C 00 57 JMP $5700 *5700L ; relocate this to $0800 5700- A2 80 LDX #$80 5702- BD 0E 57 LDA $570E,X 5705- 9D 00 08 STA $0800,X 5708- CA DEX 5709- 10 F7 BPL $5702 ; and jump there 570B- 4C 00 08 JMP $0800 ; wipe all memory 570E- 2C 89 C0 BIT $C089 5711- 2C 89 C0 BIT $C089 5714- A2 1F LDX #$1F 5716- A0 00 LDY #$00 5718- 99 00 09 STA $0900,Y 571B- 99 00 20 STA $2000,Y 571E- 99 00 40 STA $4000,Y 5721- 99 00 60 STA $6000,Y 5724- 99 00 80 STA $8000,Y 5727- 99 00 A0 STA $A000,Y 572A- 99 00 D0 STA $D000,Y ; and make a sound while doing it 572D- AD 30 C0 LDA $C030 5730- 88 DEY 5731- D0 E5 BNE $5718 5733- EE 0C 08 INC $080C 5736- EE 0F 08 INC $080F 5739- EE 12 08 INC $0812 573C- EE 15 08 INC $0815 573F- EE 18 08 INC $0818 5742- EE 1B 08 INC $081B 5745- EE 1E 08 INC $081E 5748- CA DEX 5749- 10 CD BPL $5718 574B- 8D F2 03 STA $03F2 574E- 8D F3 03 STA $03F3 5751- 2C 8A C0 BIT $C08A ; and reboot 5754- 6C FC FF JMP ($FFFC) Well, let's try not to end up there! If we read the catalog successfully, execution continues at $5800. *5800L 5800- A2 4B LDX #$4B 5802- 86 02 STX $02 5804- 2C 81 C0 BIT $C081 5807- 2C 81 C0 BIT $C081 580A- A9 D1 LDA #$D1 580C- 8D 04 D1 STA $D104 ; set reset vector 580F- A2 F6 LDX #$F6 5811- A0 BF LDY #$BF 5813- A9 1A LDA #$1A 5815- 8E F2 03 STX $03F2 5818- 8C F3 03 STY $03F3 581B- 8D F4 03 STA $03F4 ; reset drive heads 581E- A5 43 LDA $43 5820- 29 70 AND #$70 5822- 85 3E STA $3E 5824- AA TAX 5825- BD 80 C0 LDA $C080,X 5828- BD 82 C0 LDA $C082,X 582B- BD 84 C0 LDA $C084,X 582E- BD 86 C0 LDA $C086,X ; then turn on drive motor manually ; (suspicious) 5831- BD 89 C0 LDA $C089,X 5834- 24 43 BIT $43 5836- 10 01 BPL $5839 5838- E8 INX 5839- BD 8A C0 LDA $C08A,X ; wait loop ($58A5 is just an RTS) 583C- A9 00 LDA #$00 583E- AA TAX 583F- A8 TAY 5840- 20 A5 58 JSR $58A5 5843- 88 DEY 5844- D0 FA BNE $5840 5846- CA DEX 5847- D0 F7 BNE $5840 ; an address pointer maybe? 5849- 85 44 STA $44 584B- A9 14 LDA #$14 584D- 85 45 STA $45 ; read/write access to RAM bank 1 584F- 2C 8B C0 BIT $C08B 5852- 2C 8B C0 BIT $C08B ; don't know what this does yet 5855- 20 03 D0 JSR $D003 5858- A2 03 LDX #$03 585A- 86 00 STX $00 585C- 86 01 STX $01 585E- A2 15 LDX #$15 5860- 86 03 STX $03 5862- C6 03 DEC $03 5864- 30 12 BMI $5878 ; nor this 5866- 20 0C D0 JSR $D00C 5869- B0 F7 BCS $5862 586B- C0 06 CPY #$06 586D- D0 F3 BNE $5862 ; nor any of this 586F- 20 0F D0 JSR $D00F 5872- 90 19 BCC $588D 5874- C6 01 DEC $01 5876- 10 E6 BPL $585E 5878- A6 02 LDX $02 587A- 30 26 BMI $58A2 587C- A0 12 LDY #$12 587E- BD A6 58 LDA $58A6,X 5881- 99 96 D3 STA $D396,Y 5884- CA DEX 5885- 88 DEY 5886- 10 F6 BPL $587E 5888- 86 02 STX $02 588A- 4C 58 58 JMP $5858 588D- C6 00 DEC $00 588F- 10 CD BPL $585E 5891- A5 01 LDA $01 5893- C9 03 CMP #$03 5895- D0 E1 BNE $5878 ; success path falls through to here ; (I think) 5897- A6 3E LDX $3E ; turn off drive motor 5899- BD 88 C0 LDA $C088,X ; switch to ROM 589C- 2C 8A C0 BIT $C08A ; continue with "stage 2" loader (to ; launch .SYSTEM file, probably) 589F- 4C 00 08 JMP $0800 ; failure path ends up here 58A2- 4C F6 BF JMP $BFF6 *BFF6L BFF6- 2C 80 C0 BIT $C080 BFF9- 4C 00 D1 JMP $D100 I'm guessing that $D100 ends up executing the code that started out at $5700, a.k.a. The Badlands. By the time execution reaches $589F (the success path), ProDOS has done everything it needs to do by relocating itself into the language card, and it's time to find the first .SYSTEM file and load it. But it needs to load the file at $2000, so ProDOS moves its "stage 2" code to $800 to avoid memory conflicts. Oh, and it's modified the RWTS in memory a number of times. How many? I'm not sure yet. I need to interrupt the boot to see what evil lurks at $D003, $D00C, and $D00F. *9600<C600.C6FFM ; set up callback #1 after PRODOS file ; is loaded 96F8- A9 4C LDA #$4C 96FA- 8D CB 08 STA $08CB 96FD- A9 0A LDA #$0A 96FF- 8D CC 08 STA $08CC 9702- A9 97 LDA #$97 9704- 8D CD 08 STA $08CD ; start the boot 9707- 4C 01 08 JMP $0801 ; (callback #1) set up callback #2 just ; before switching on RAM bank 1 970A- A9 4C LDA #$4C 970C- 8D 4F 58 STA $584F 970F- A9 1C LDA #$1C 9711- 8D 50 58 STA $5850 9714- A9 97 LDA #$97 9716- 8D 51 58 STA $5851 ; continue the boot 9719- 4C 00 20 JMP $2000 ; (callback #2) switch to RAM bank 1 ; and dump the entire contents into ; main memory 971C- 2C 8B C0 BIT $C08B 971F- 2C 8B C0 BIT $C08B 9722- A2 30 LDX #$30 9724- A0 00 LDY #$00 9726- B9 00 D0 LDA $D000,Y 9729- 99 00 20 STA $2000,Y 972C- C8 INY 972D- D0 F7 BNE $9726 972F- EE 28 97 INC $9728 9732- EE 2B 97 INC $972B 9735- CA DEX 9736- D0 EE BNE $9726 ; switch back to ROM 9738- 2C 82 C0 BIT $C082 ; reboot to my work disk 973B- 4C 00 C5 JMP $C500 *BSAVE TRACE.D003,A$9600,L$13E *9600G ...reboots slot 6... ...reboots slot 5... ]BSAVE BOOT1.D000-FFFF,A$2000,L$3000 ]CALL -151 *2003L 2003- 4C E5 D2 JMP $D2E5 *22E5L ; This just sets up the absolute ; addresses in the RWTS so it can put ; the sector data in-place in its final ; memory destination. Perfectly normal. ; By the way, ($44) points to $1400; ; that was initialized at $5849, just ; before this call. 22E5- A5 44 LDA $44 22E7- A4 45 LDY $45 22E9- 8D CC D3 STA $D3CC 22EC- 8C CD D3 STY $D3CD 22EF- 8D 12 D4 STA $D412 22F2- 8C 13 D4 STY $D413 22F5- 18 CLC 22F6- 69 55 ADC #$55 22F8- 90 01 BCC $22FB 22FA- C8 INY 22FB- 85 3A STA $3A 22FD- 84 3B STY $3B 22FF- 8D DE D3 STA $D3DE 2302- 8C DF D3 STY $D3DF 2305- 18 CLC 2306- 69 55 ADC #$55 2308- 90 01 BCC $230B 230A- C8 INY 230B- 85 3C STA $3C 230D- 84 3D STY $3D 230F- 8D F0 D3 STA $D3F0 2312- 8C F1 D3 STY $D3F1 2315- 60 RTS *200CL 200C- 4C 16 D3 JMP $D316 OK, I know that routine reads the next available address field. (It was originally at $5316; I already traced it earlier.) *200FL 200F- 4C 6A D3 JMP $D36A This routine was originally at $536A. It reads the data field. Now this entire loop makes more sense. It's literally copying different chunks of code into the middle of the RWTS and trying to find a variation that can read several sectors in a row. Let's list it again and sprinkle some more comments around. The main loop starts at $5858. There are 4 counters, $00, $01, $02, and $03. $00 is the number of times we've tried to read a sector (starts at 3 and decremented). $01 is the number of times it succeeded (starts at 3 and checked after all reads). $02 is used as an index for copying $13-byte chunks of code into the RWTS. When it goes negative, we've tried all of the RWTS variations. $02 starts at $4B (set at $5800). $03 is a death counter for finding the proper sector. 5858- A2 03 LDX #$03 585A- 86 00 STX $00 585C- 86 01 STX $01 ; $03 is an inner loop death counter ; for finding the proper sector 585E- A2 15 LDX #$15 5860- 86 03 STX $03 5862- C6 03 DEC $03 ; when $03 goes negative, give up on ; finding the proper sector (with this ; RWTS variation) 5864- 30 12 BMI $5878 ; read next available address field 5866- 20 0C D0 JSR $D00C ; if that returned an error, loop back ; and try again (decrements $03) 5869- B0 F7 BCS $5862 ; After the routine at $D00C, the Y ; register has an address field value ; (guessing this is a sector number) 586B- C0 06 CPY #$06 586D- D0 F3 BNE $5862 ; try to read a sector worth of data 586F- 20 0F D0 JSR $D00F ; if that worked, branch 5872- 90 19 BCC $588D ; decrement read-data death counter and ; try again 5874- C6 01 DEC $01 5876- 10 E6 BPL $585E ; if we've tried all variations, give ; up entirely, otherwise fall through 5878- A6 02 LDX $02 587A- 30 26 BMI $58A2 ; copy $13 bytes of code into the ; middle of the RWTS routine(!) 587C- A0 12 LDY #$12 587E- BD A6 58 LDA $58A6,X 5881- 99 96 D3 STA $D396,Y 5884- CA DEX 5885- 88 DEY 5886- 10 F6 BPL $587E ; store the index pointer so the next ; time through the loop, we copy a ; different chunk of code into the ; middle of the RWTS routine(!) 5888- 86 02 STX $02 ; start over with this RWTS variation 588A- 4C 58 58 JMP $5858 ; execution continues here (from $5872) ; after a successful sector read -- ; decrement the sector read counter and ; try again 588D- C6 00 DEC $00 588F- 10 CD BPL $585E ; if any of the reads failed, branch to ; try the next RWTS variation 5891- A5 01 LDA $01 5893- C9 03 CMP #$03 5895- D0 E1 BNE $5878 ; success path falls through to here -- ; we have found the working RWTS and we ; are ready to move on with the boot 5897- A6 3E LDX $3E ; turn off drive motor 5899- BD 88 C0 LDA $C088,X ; switch to ROM 589C- 2C 8A C0 BIT $C08A ; continue with "stage 2" loader (to ; launch .SYSTEM file, presumably) 589F- 4C 00 08 JMP $0800 ; failure path ends up here 58A2- 4C F6 BF JMP $BFF6 Here are the four different variations that it copies into the RWTS. Note that the overflow bit will always be set by the time this code is run, so the "BVC" instruction burns 3 cycles but never branches. Each variation burns a different number of CPU cycles (listed in the right margin) before checking the third nibble of the data prologue. #1: 58DF- 50 05 BVC $58E6 | 3 58E1- BD 8D C0 LDA $C08D,X | 4 58E4- 48 PHA | 3 58E5- 68 PLA | 4 58E6- BD 8C C0 LDA $C08C,X 58E9- 10 FB BPL $58E6 58EB- C9 A9 CMP #$A9 58ED- F0 05 BEQ $58F4 58EF- 88 DEY 58F0- 10 F4 BPL $58E6 #2: 58CC- 50 05 BVC $58D3 | 3 58CE- BD 8D C0 LDA $C08D,X | 4 58D1- EA NOP | 2 58D2- EA NOP | 2 58D3- BD 8C C0 LDA $C08C,X 58D6- 10 FB BPL $58D3 58D8- C9 A9 CMP #$A9 58DA- F0 05 BEQ $58E1 58DC- 88 DEY 58DD- 10 F4 BPL $58D3 #3: 58B9- 50 04 BVC $58BF | 3 58BB- BD 8D C0 LDA $C08D,X | 4 58BE- EA NOP | 2 58BF- BD 8C C0 LDA $C08C,X 58C2- 10 FB BPL $58BF 58C4- C9 A9 CMP #$A9 58C6- F0 06 BEQ $58CE 58C8- 88 DEY 58C9- 10 F4 BPL $58BF 58CB- EA NOP #4: 58A6- 50 03 BVC $58AB | 3 58A8- BD 8D C0 LDA $C08D,X | 4 58AB- BD 8C C0 LDA $C08C,X 58AE- 10 FB BPL $58AB 58B0- C9 A9 CMP #$A9 58B2- F0 07 BEQ $58BB 58B4- 88 DEY 58B5- D0 F4 BNE $58AB 58B7- EA NOP 58B8- EA NOP None of these timing variations work on my EDD bit copy, because they all need some timing bits between the second and third nibble of the data prologue, and EDD doesn't preserve those by default. There's no nibble check, per se. The entire structure of the disk itself is designed to foil bit copiers. ~ Chapter 4 In Which We Finally Make Some Forward Progress Let's capture the "stage 2" code that ends up at $0800, then I can see what I need to do to inject BASIC.SYSTEM into memory and launch it. *9600<C600.C6FFM ; set up callback #1 96F8- A9 4C LDA #$4C 96FA- 8D CB 08 STA $08CB 96FD- A9 0A LDA #$0A 96FF- 8D CC 08 STA $08CC 9702- A9 97 LDA #$97 9704- 8D CD 08 STA $08CD ; start the boot 9707- 4C 01 08 JMP $0801 ; (callback #1) set up callback #2 970A- A9 4C LDA #$4C 970C- 8D 9F 58 STA $589F 970F- A9 1C LDA #$1C 9711- 8D A0 58 STA $58A0 9714- A9 97 LDA #$97 9716- 8D A1 58 STA $58A1 ; continue the boot 9719- 4C 00 20 JMP $2000 ; (callback #2) copy stage 2 code from ; $0800 to graphics page so it survives ; a reboot 971C- A2 18 LDX #$18 971E- A0 00 LDY #$00 9720- B9 00 08 LDA $0800,Y 9723- 99 00 28 STA $2800,Y 9726- C8 INY 9727- D0 F7 BNE $9720 9729- EE 22 97 INC $9722 972C- EE 25 97 INC $9725 972F- CA DEX 9730- D0 EE BNE $9720 ; turn off slot 6 drive motor 9732- AD E8 C0 LDA $C0E8 ; reboot to my work disk 9735- 4C 00 C5 JMP $C500 *BSAVE TRACE2,A$9600,L$138 *9600G ...reboots slot 6... ...reboots slot 5... ]BSAVE STAGE2 0800-14FF,A$2800,L$D00 ]CALL -151 *800<2800.34FFM *800L ; this is looking through the disk ; catalog (loaded at $0C00) 0800- A9 0C LDA #$0C 0802- 85 11 STA $11 0804- A9 04 LDA #$04 0806- 2C A5 10 BIT $10A5 0809- 18 CLC 080A- 6D 23 0C ADC $0C23 080D- 85 10 STA $10 080F- B0 12 BCS $0823 0811- 6D 23 0C ADC $0C23 0814- 90 0F BCC $0825 0816- A5 11 LDA $11 0818- 4A LSR 0819- 90 0A BCC $0825 081B- C9 09 CMP #$09 081D- F0 1E BEQ $083D 081F- A9 04 LDA #$04 0821- 85 10 STA $10 0823- E6 11 INC $11 0825- A0 10 LDY #$10 0827- A9 FF LDA #$FF 0829- 51 10 EOR ($10),Y 082B- D0 DA BNE $0807 082D- A8 TAY 082E- B1 10 LDA ($10),Y 0830- F0 D5 BEQ $0807 0832- 29 0F AND #$0F 0834- 8D 80 02 STA $0280 0837- C9 08 CMP #$08 0839- 90 CC BCC $0807 083B- B0 03 BCS $0840 083D- F0 6E BEQ $08AD 083F- 00 BRK 0840- A8 TAY ; $0965 contains the string ".SYSTEM", ; so this is checking whether this file ; ends with the string ".SYSTEM" 0841- A2 06 LDX #$06 0843- B1 10 LDA ($10),Y 0845- 5D 65 09 EOR $0965,X 0848- 0A ASL ; if not, loop to find the next file 0849- D0 BC BNE $0807 084B- 88 DEY 084C- CA DEX 084D- 10 F4 BPL $0843 ; copy the filename into the buffer at ; $0280 and another buffer at $093B (I ; think the second one is used for ; error messages if things go wrong) 084F- A0 00 LDY #$00 0851- C8 INY 0852- B1 10 LDA ($10),Y 0854- 99 80 02 STA $0280,Y 0857- 09 80 ORA #$80 0859- 99 3B 09 STA $093B,Y 085C- CC 80 02 CPY $0280 085F- D0 F0 BNE $0851 ; pad error message with spaces 0861- A9 A0 LDA #$A0 0863- 99 3C 09 STA $093C,Y 0866- 98 TYA 0867- 69 13 ADC #$13 0869- 8D 4F 09 STA $094F ; open file (ProDOS MLI $C8) 086C- 20 00 BF JSR $BF00 086F- [C8 50 09] 0872- D0 46 BNE $08BA ; get file EOF (MLI $D1) 0874- 20 00 BF JSR $BF00 0877- [D1 56 09] 087A- D0 3E BNE $08BA 087C- AD 5A 09 LDA $095A 087F- D0 53 BNE $08D4 0881- AD 59 09 LDA $0959 0884- C9 98 CMP #$98 0886- B0 4C BCS $08D4 0888- 8D 60 09 STA $0960 088B- AD 58 09 LDA $0958 088E- 8D 5F 09 STA $095F ; read file (MLI $CA) 0891- 20 00 BF JSR $BF00 0894- [CA 5B 09] 0897- F0 06 BEQ $089F 0899- C9 56 CMP #$56 089B- F0 37 BEQ $08D4 089D- D0 1B BNE $08BA ; close file (MLI $CC) 089F- 20 00 BF JSR $BF00 08A2- [CC 63 09] 08A5- D0 13 BNE $08BA 08A7- AD 82 C0 LDA $C082 ; jump to beginning of loaded file 08AA- 4C 00 20 JMP $2000 This is where I want to interrupt the boot and inject my clean version of BASIC.SYSTEM. (I could probably do it slightly earlier to avoid loading whichever .SYSTEM file it's opening, but I don't want to run afoul of any expected side effects of having loaded the file through the MLI.) *BLOAD BASIC.SYSTEM,A$6000 *9600<C600.C6FFM ; set up callback #1 96F8- A9 4C LDA #$4C 96FA- 8D CB 08 STA $08CB 96FD- A9 0A LDA #$0A 96FF- 8D CC 08 STA $08CC 9702- A9 97 LDA #$97 9704- 8D CD 08 STA $08CD ; start the boot 9707- 4C 01 08 JMP $0801 ; (callback #1) set up callback #2 970A- A9 4C LDA #$4C 970C- 8D 9F 58 STA $589F 970F- A9 1C LDA #$1C 9711- 8D A0 58 STA $58A0 9714- A9 97 LDA #$97 9716- 8D A1 58 STA $58A1 ; continue the boot 9719- 4C 00 20 JMP $2000 ; (callback #2) set up callback #3 971C- A9 4C LDA #$4C 971E- 8D AA 08 STA $08AA 9721- A9 2E LDA #$2E 9723- 8D AB 08 STA $08AB 9726- A9 97 LDA #$97 9728- 8D AC 08 STA $08AC ; continue the boot 972B- 4C 00 08 JMP $0800 ; (callback #3) move BASIC.SYSTEM into ; place (I manually BLOADed this file ; already at $6000) 972E- A2 28 LDX #$28 9730- A0 00 LDY #$00 9732- B9 00 60 LDA $6000,Y 9735- 99 00 20 STA $2000,Y 9738- C8 INY 9739- D0 F7 BNE $9732 973B- EE 34 97 INC $9734 973E- EE 37 97 INC $9737 9741- CA DEX 9742- D0 EE BNE $9732 ; tell BASIC.SYSTEM not to look for a ; STARTUP file 9744- A9 00 LDA #$00 9746- 8D 06 20 STA $2006 ; continue the boot with the clean ; version of BASIC.SYSTEM 9749- 4C 00 20 JMP $2000 *BSAVE TRACE3,A$9600,L$14C *9600G ...reboots slot 6... ...displays ProDOS title page... ...clears screen... PRODOS BASIC 1.5 COPYRIGHT APPLE 1983-92 ] Son of a biscuit. It actually worked. ~ Chapter 5 In Which We Finally Catch A Break, And Our Adventure Comes To A Sudden But Satisfying Conclusion ]CAT /PRO.PICK NAME TYPE BLOCKS MODIFIED PRODOS SYS 30 9-OCT-86 *CGWL BIN 12 <NO DATE> *PICK BIN 16 24-JUN-87 *CALIB BIN 8 24-JUN-87 *LOADER.SYSTEM SYS 3 <NO DATE> *LOGO BIN 7 <NO DATE> DATA BIN 7 <NO DATE> *HOME.P BIN 7 <NO DATE> *TOYS.S BIN 7 <NO DATE> *TOOLS.P BIN 3 <NO DATE> *FISH.P BIN 5 <NO DATE> *SPACE.P BIN 3 <NO DATE> *TOYS.P BIN 4 <NO DATE> *MAN.P BIN 3 <NO DATE> *WOMAN.P BIN 4 <NO DATE> *KITCHEN.P BIN 4 <NO DATE> *MOUNTAIN.P BIN 4 <NO DATE> *POOL.P BIN 5 <NO DATE> *HOME.S BIN 6 <NO DATE> *FOOD.P BIN 5 <NO DATE> *BALLOONS.P BIN 5 <NO DATE> *KITES.P BIN 5 <NO DATE> *KITCHEN.S BIN 5 <NO DATE> *MOUNTAIN.S BIN 5 <NO DATE> *FISH.S BIN 4 <NO DATE> *MAN.S BIN 4 <NO DATE> *WOMAN.S BIN 3 <NO DATE> *TREE.P BIN 7 <NO DATE> *TOOLS.S BIN 5 <NO DATE> *SAILS.P BIN 4 <NO DATE> *FOOD.S BIN 8 <NO DATE> *BALLOONS.S BIN 5 <NO DATE> *COLOR BIN 8 <NO DATE> *TREE.S BIN 4 <NO DATE> *KITES.S BIN 8 <NO DATE> *SAILS.S BIN 5 <NO DATE> *POOL.S BIN 5 <NO DATE> *SPACE.S BIN 3 <NO DATE> BLOCKS FREE: 37 BLOCKS USED: 243 The custom floppy device driver is in memory, and I have unfettered access to the disk through a clean version of BASIC.SYSTEM. ]PREFIX /PRO.PICK ]BLOAD LOADER.SYSTEM,A$2000,TSYS ]CALL-151 *2000L 2000- A0 00 LDY #$00 2002- B9 00 21 LDA $2100,Y 2005- 99 00 81 STA $8100,Y 2008- C8 INY 2009- D0 F7 BNE $2002 200B- A0 00 LDY #$00 200D- B9 00 22 LDA $2200,Y 2010- 99 00 82 STA $8200,Y 2013- C8 INY 2014- D0 F7 BNE $200D 2016- 4C 00 81 JMP $8100 Un. Fettered. Access. But how do I copy all these files to a standard disk? I could do it one at a time -- the BLOAD command works, so I could simply load each file into memory and reboot and save it. But wait. ProDOS has separate device drivers for floppies and hard drives. Maybe... [S7,D1=ProDOS hard drive, "A4AMCRACK"] ]PREFIX /A4AMCRACK ]CAT /A4AMCRACK NAME TYPE BLOCKS MODIFIED *PRODOS SYS 35 6-AUG-03 RAM.DRV.SYSTEM SYS 4 29-NOV-10 PROSEL.SYSTEM SYS 1 1-APR-88 APPLICATIONS DIR 2 18-DEC-14 BASIC.SYSTEM SYS 21 6-DEC-91 COMMANDS DIR 1 20-MAR-14 DOC DIR 1 20-MAR-14 DOS3.3 DIR 1 20-MAR-14 ARCHIVE DIR 1 8-FEB-15 MERLIN DIR 2 1-OCT-14 INCOMING DIR 1 30-SEP-14 PROSEL BIN 13 17-OCT-14 UTIL DIR 6 20-MAR-14 BLOCKS FREE:60603 BLOCKS USED: 4932 Not only do I have unfettered access to the floppy disk, I have my entire hard drive of utilities at my disposal. ]-/A4AMCRACK/APPLICATIONS/COPYIIPLUS8.4 /UTIL.SYSTEM ...launches Copy ][+... --> CREATE SUBDIRECTORY --> SLOT 7, DRIVE 1 --> SUBDIRECTORY NAME: PRO.PICK --> COPY --> FILES --> from SLOT 6, DRIVE 1 --> to SLOT 7, DRIVE 1, PRO.PICK --> all files It works. Copy ][+ uses the version of ProDOS in memory, including the custom floppy disk driver. As far as Copy ][+ is concerned, there's nothing unusual about this disk or its files. Hooray for abstractions! Now that I have all the files off the original disk, I can safely put it away and never touch it again. (Whew. Good riddance.) [S6,D1=blank disk] ]PR#7 Using Copy ][+ again, I simply recreate the original disk with a clean copy of the PRODOS file. (I have a directory of PRODOS files of different versions for just such an occasion, because that's not weird at all.) [Copy ][+ 8.4] --> FORMAT DISK --> PRODOS --> SLOT 6, DRIVE 1 --> VOLUME NAME: PRO.PICK --> COPY --> FILES --> from SLOT 7, DRIVE 1 --> to SLOT 6, DRIVE 1 --> ARCHIVES/PRODOS1.1.1/PRODOS --> COPY --> FILES --> from SLOT 7, DRIVE 1, PRO.PICK --> to SLOT 6, DRIVE 1 --> all files except PRODOS ]PR#6 ...works... Quod erat liberandum. --------------------------------------- A 4am crack No. 266 ------------------EOF------------------