-----------Addition Magician----------- A 4am crack 2016-01-28 --------------------------------------- Name: Addition Magician Genre: educational Year: 1984 Author: Dale Disharoon Publisher: The Learning Company Media: single-sided 5.25-inch floppy OS: custom Previous cracks: none Similar cracks: #476 Microzine 2 #464 Microzine 4 #409 Microzine 5 #332 Microzine 3 ~ 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) read errors on T11+ copy displays a graphical title page then hangs with the drive motor on Copy ][+ nibble editor T00 -> standard prologues, modified epilogues (FF FF FF) T01,02 -> corrupted address fields that claim to be track $00 T03,04 -> not full tracks? looks like they have some standard-ish sectors, but not 16 per track (also corrupted address fields) T05-T0C -> more corrupted address fields (like T01) T0D-T10 -> uncorrupted address fields but still non-standard epilogues T11+ unformatted When I say "corrupted address fields," this is what that looks like: --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 01 START: 21DC LENGTH: 189D ^^ 21B8: FF FF FF FF FF FF FF FF VIEW 21C0: FF FF FF FF FF FF FF FF 21C8: FF FF FF FF FF FF FF FF 21D0: FF FF FF FF FF FF FF FF 21D8: FF FF FF FF FF D5 AA 96 <-21DD ^^^^^^^^ address prologue 21E0: AA AA AA AA AA AA AA AA ^^^^^ ^^^^^ ^^^^^ ^^^^^ V000 T00 S00 chksm 21E8: FF FF FF FF FF CF F3 FC ^^^^^^^^ address epilogue 21F0: FF FF D5 AA AD 9B DB B9 ^^^^^^^^ data prologue 21F8: B9 DB F2 DE B9 AE B3 BA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- The disk is lying to me. The address field claims to be track $00, but it's really track $01. Bad disk! Stop lying! Disk Fixer ["O" -> "Input/Output Control"] set Address Epilogue to "FF FF FF" set Data Epilogue to "FF FF FF" T00 readable T01-T0C unreadable (no option to ignore the corrupted address field) T0D-T10 readable T11+ unreadable (unformatted) Copy ][+ sector editor ["P" -> "Sector Editor Patcher"] set type to "CUSTOM" set Address Epilogue to "FF FF" set Data Epilogue to "FF FF FF" T00 readable T0D-T10 readable ["P" -> "Sector Editor Patcher"] set CHECK TRACK to "NO" T01 readable! only parts of T02 and T03 readable: T02: S03,04,05,06,07,0A,0B,0C,0D,0E T03: S01,02,08,09,0F T04-T0C readable! Why didn't COPYA work? modified epilogue bytes on track $00 Why didn't Locksmith FDB work? ditto Why didn't my EDD copy work? I've seen similar disks, where the first N tracks have intentionally corrupted address fields. (N varies from disk to disk.) There's a custom loader that loads the data from those corrupted tracks, then transfers control to a standard RWTS for the rest of the program. Somewhere in the corrupted tracks, it will load data from consecutive half tracks. (These are devilishly difficult to copy, and I didn't even try.) That's just an educated guess; I could be surprised. Hey, I can actually validate that guess in the Copy ][+ nibble editor, which can read half tracks. --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 02.50 START: 3700 LENGTH: 198E ^^^^^ 3BD0: FF FF FF FF FF FF FF FF VIEW 3BD8: FF FF FF FF FF FF FF FF 3BE0: FF FF FF FF FF FF FF FF 3BE8: FF FF C9 FF FF FF FF FF 3BF0: FF FF FF FF FF D5 AA 96 <-3BF5 ^^^^^^^^ address prologue 3BF8: AA AA AA AA AF AB AF AB ^^^^^ ^^^^^ ^^^^^ ^^^^^ V000 T00 S0B chksm 3C00: FF FF FF 9F E7 F9 FE FF ^^^^^^^^ address eplogue 3C08: D5 AA AD A7 B4 BD CD ED ^^^^^^^^ data prologue 3C10: ED 9B ED F2 E9 DF B6 AB --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- Jackpot! (Note that it's still claiming to be track $00, though, just like the other whole tracks above and below it.) Next steps: 1. Trace the boot 2. ??? ~ Chapter 1 Boot Trace and Chill [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 reset vector 0801- 8A TXA 0802- 4A LSR 0803- 4A LSR 0804- 4A LSR 0805- 4A LSR 0806- 09 C0 ORA #$C0 0808- 85 3F STA $3F 080A- 8D F3 03 STA $03F3 080D- 49 A5 EOR #$A5 080F- 8D F4 03 STA $03F4 0812- A9 00 LDA #$00 0814- 8D F2 03 STA $03F2 ; hmm 0817- A9 04 LDA #$04 0819- 48 PHA ; machine initialization (memory banks, ; TEXT, IN#0, PR#0, &c.) 081A- 8D 81 C0 STA $C081 081D- 20 2F FB JSR $FB2F 0820- 8D 52 C0 STA $C052 0823- 20 89 FE JSR $FE89 0826- 20 93 FE JSR $FE93 ; clear hi-res screen 1 0829- A2 20 LDX #$20 082B- A0 00 LDY #$00 082D- 84 06 STY $06 082F- A9 20 LDA #$20 0831- 85 07 STA $07 0833- 98 TYA 0834- 91 06 STA ($06),Y 0836- C8 INY 0837- D0 FB BNE $0834 0839- E6 07 INC $07 083B- CA DEX 083C- D0 F6 BNE $0834 ; switch to hi-res screen 1 (blank) 083E- 8D 57 C0 STA $C057 0841- 8D 50 C0 STA $C050 0844- 8D 54 C0 STA $C054 0847- 8D 52 C0 STA $C052 ; set up ($3E) vector to point to the ; sector read routine in the disk ; controller ROM 084A- A9 5C LDA #$5C 084C- 85 3E STA $3E ; the disk controller ROM always exits ; via $0801, so set that to an RTS so ; we can JSR and not have to set up a ; loop 084E- A9 60 LDA #$60 0850- 8D 01 08 STA $0801 ; hmm 0853- A9 72 LDA #$72 0855- 48 PHA OK, we've now pushed $04/$72 on the stack. That's probably important. ; multi-sector read ; Y = first logical sector ($01) ; X = last logical sector ($0E) ; A = start address high byte ($09) 0856- A0 00 LDY #$00 0858- 84 FC STY $FC 085A- C8 INY 085B- A9 09 LDA #$09 085D- A2 0E LDX #$0E ; call multi-sector read routine 085F- 20 65 08 JSR $0865 ; another sector read, this time just ; one sector, into $0400 (X is already ; less than Y on entry, so loop will ; exit after one read) 0862- A9 04 LDA #$04 0864- AA TAX ; falls through to multi-sector read ; entry point (was also called earlier) 0865- 85 27 STA $27 0867- E8 INX 0868- 86 49 STX $49 086A- 84 F9 STY $F9 ; map logical into physical sector and ; store it in zero page where the disk ; controller ROM will look for it 086C- B9 83 08 LDA $0883,Y 086F- 85 3D STA $3D ; read sector via disk controller ROM 0871- 20 7E 08 JSR $087E ; loop until done 0874- A4 F9 LDY $F9 0876- C8 INY 0877- C4 49 CPY $49 0879- 90 EF BCC $086A 087B- A5 27 LDA $27 ; subroutine to read a sector via ($3E) ; which points to $Cx5C, which exits ; via $0801, which is now an "RTS" ; (HOW F---ING ELEGANT IS THAT, RIGHT?) 0885- A6 2B LDX $2B 0887- 6C 3E 00 JMP ($003E) ; physical to logical sector map 0883- 00 03 05 07 09 0888- 0B 0D 0F 02 04 06 08 0A 0890- 0C 0E 01 That's it. Flexible but compact. It's a weird combination of reads, though. It loads a bunch of sectors at $0900, then the last one at $0400. That's part of the text page, but it's hidden during boot because we cleared the entire hi-res graphics page and showed that instead. Of course, we manually pushed $04/$72 on the stack earlier, so once we fall through to the sector read routine, reads the last sector, and hits the RTS we put at $0801, it will "return" to $0472 + 1 = $0473. Let's interrupt the boot before it gets there. ~ Chapter 2 In Which Things Get Brilliantly Weird *9600physical sectors is at ; $0463) or a physical sector 241D- 24 4A BIT $4A 241F- 30 03 BMI $2424 2421- B9 63 04 LDA $0463,Y ; store physical sector in $3D (again, ; used by the disk controller ROM) 2424- 85 3D STA $3D ; read sector by jumping to ($003E), ; which points to $Cx5C (e.g. $C65C if ; booting from slot 6) and exit via ; $0801, which is an RTS by now, so ; this just continues to the next line 2426- 20 00 04 JSR $0400 ; increment sector index 2429- A4 F9 LDY $F9 242B- C8 INY ; are there more sectors to read? 242C- C4 49 CPY $49 ; yes, branch back and repeat 242E- 90 EA BCC $241A ; no, exit with last page (+1) in A ; (disk controller ROM increments this ; after storing sector data, so on exit ; this will be the first page that was ; NOT filled with data in this loop) 2430- A5 27 LDA $27 2432- 60 RTS And that's how we fill up $0800..$1FFF: $0900..$16FF were read from track $00 (at $0856), now $1700..$1FFF are read from track $01. ; now call the code we just loaded 247F- 20 00 09 JSR $0900 2482- 20 00 1F JSR $1F00 That's where I need to interrupt the boot. ~ Chapter 3 In Which Things Get Weirdly Brilliant *9600 *C0E8 *2800<800.1FFFM *C500G ... ]BSAVE BOOT2 0800-1FFF,A$2800,L$1800 After several more cycles of TRACE3, I have all of main memory spread across several files: ]CATALOG C1983 DSR^C#254 206 FREE A 019 HELLO B 005 AUTOTRACE B 065 SUPER DEMUFFIN B 003 BOOT0 B 003 TRACE B 003 BOOT1 0400-04FF B 003 TRACE2 B 026 BOOT1 0800-1FFF B 003 TRACE3 B 026 BOOT2 0800-1FFF B 034 BOOT2 4000-5FFF B 066 BOOT2 6000-9FFF B 034 BOOT2 A000-BFFF One more thing... ]BLOAD BOOT2 A000-BFFF,A$2000,L$2000 ]CALL -151 *3800L . . appears to be a DOS-shaped RWTS . 3898- A6 27 LDX $27 389A- 20 BB B8 JSR $B8BB 389D- A9 FF LDA #$FF 389F- 20 B8 B8 JSR $B8B8 38A2- A9 FF LDA #$FF 38A4- 20 B8 B8 JSR $B8B8 38A7- A9 EB LDA #$EB ... Confirmed: after the bootloader exits, we have a full DOS 3.3 RWTS in memory. Spot checking the RWTS, it's perfectly normal except it expects "FF FF FF" epilogue bytes. Which, by the way, is just the sort of RWTS that could read tracks $0D-$10. I'll need to patch it to read the standard epilogue instead. *389E:DE *38A3:AA *3935:DE *393F:AA *3991:DE *399B:AA *3CAE:DE *3CB3:AA *BSAVE RWTS FIXED,A$3800,L$800 ~ Chapter 6 In Which Everything Is Simple If You Look At It The Right Way Using Super Demuffin (with epilogues "FF FF FF"), I "copied" the original disk to a freshly formatted blank disk. Of course, this only got track $00 and tracks $0D-$10, but I'll take it. --v-- LOCKSMITH 7.0 FAST DISK BACKUP R.************....****************** W*********************************** HEX 00000000000000001111111111111111222 TRK 0123456789ABCDEF0123456789ABCDEF012 0.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 1.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 2.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 3.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 4.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 5.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 6.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 7.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 8.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 9.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA A.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA B.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA C.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA D.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA 12 E.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA F.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA [ ] PRESS [RESET] TO EXIT --^-- Now I need to write everything that I captured from the corrupted tracks back to tracks $01-$0C Disk layout comparison: track | old address | new address | sec ------+-------------+-------------+---- $01 | $1700-$1FFF | 0-8 $02 | $0800-$0CFF | $0800-$16FF | 0-E $02.5 | $0D00-$11FF | | $03 | $1200-$16FF | | $04 | $1700-$1FFF | 0-8 $05 | $4000-$4FFF | 0-F $06 | $5000-$5FFF | 0-F $07 | $6000-$6FFF | 0-F $08 | $7000-$7FFF | 0-F $09 | $8000-$8FFF | 0-F $0A | $9000-$9FFF | 0-F $0B | $A000-$AFFF | 0-F $0C | $B000-$BFFF | 0-F Of course, all the tracks will now have normal address fields (no more lying about the track numbers). Also no half tracks and no spirals. Just, you know, sectors on a disk. All the spiral track stuff collapses into track $02, then track $03 is completely unused. [S6,D1=demuffin'd copy (T00, T0D-T10)] [S5,D1=my work disk] ]PR#5 ... ]CALL -151 *300L ; page count (decremented) 0300- A9 30 LDA #$09 0302- 85 FF STA $FF ; logical sector (incremented) 0304- A9 00 LDA #$00 0306- 85 FE STA $FE ; call RWTS to write sector 0308- A9 03 LDA #$03 030A- A0 88 LDY #$88 030C- 20 D9 03 JSR $03D9 ; increment logical sector, wrap around ; from $0F to $00 and increment track 030F- E6 FE INC $FE 0311- A4 FE LDY $FE 0313- C0 10 CPY #$10 0315- D0 07 BNE $031E 0317- A0 00 LDY #$00 0319- 84 FE STY $FE 031B- EE 8C 03 INC $038C ; Convert to the interleave order that ; this disk expects 031E- B9 40 03 LDA $0340,Y 0321- 8D 8D 03 STA $038D ; increment page to write 0324- EE 91 03 INC $0391 0327- C6 FF DEC $FF ; loop until done with all pages 0329- D0 DD BNE $0308 032B- 60 RTS ; sector interleave table *340.34F 0340- 00 06 05 04 03 02 01 0F 0348- 0E 0D 0C 0B 0A 09 08 07 ; RWTS parameter table, pre-initialized ; with slot 6, drive 1, track $01, ; sector $00, address $1700, and RWTS ; write command ($02) *388.397 0388- 01 60 01 00 01 00 FB F7 0390- 00 17 00 00 02 00 00 60 *BSAVE WRITE T01,A$300,L$98 *BLOAD BOOT1 0800-1FFF,A$800 *300G ...write write write... Track 1 complete. *301:0F ; sector count *38C:02 ; track *391:08 ; first memory page *BSAVE WRITE T02,A$300,L$98 *BLOAD BOOT2 0800-1FFF,A$800 *300G ...write write write... Track 2 complete. *301:09 ; sector count *38C:04 ; track *391:17 ; first memory page *BSAVE WRITE T04,A$300,L$98 *300G ...write write write... Track 4 complete. *301:80 ; sector count *38C:05 ; first track *391:10 ; first memory page *BSAVE WRITE T05+,A$300,L$98 *BLOAD BOOT2 4000-5FFF,A$1000 *BLOAD BOOT2 6000-9FFF,A$3000 *BLOAD BOOT2 A000-BFFF,A$7000 *BLOAD RWTS FIXED,A$8800 *300G ...write write write... Tracks $05-$0C complete. Now I need to modify the bootloader at $0473 slightly. 1. Modify the routine at $04CA to read 15 ($0E) sectors from track $02 instead of the spiral tracks, then skip track $03 altogether. 2. Modify the routine at $0433 (that advances the drive head) so it updates zero page $41 with the current track. The sector read routine at $C65C compares the track listed in the address field to zero page $41 and loops forever until it matches. $C600 initializes $41 to 0, and the original disk never updates $41, but everything works because the address fields are corrupted and all claim to be track 0. So part of it will be simpler, because we'll no longer be spiraling between tracks. But part of it will actually be more complicated because the address fields are no longer corrupted and we need to track the track number. First, the patch at $04CA to load 15 ($0E) sectors from track $02, then skip over track $03. T00,S07,$CA change to 20 33 04 A9 08 A2 0E 20 13 04 4C 33 04 which looks like this (using Disk Fixer's built-in disassembler): --v-- 00CA:20 33 04 JSR $0433 00CD:A9 08 LDA #$08 00CF:A2 0E LDX #$0E 00D1:20 13 04 JSR $0413 00D4:4C 33 04 JMP $0433 --^-- Second, a new routine at $04D7 (now unused space) to increment the track number in zero page. T00,S07,$D7 change to "E6 41 4C 36 04" --v-- 00D7:E6 41 INC $41 00D9:4C 36 04 JMP $0436 --^-- Third, the patch at $0433 to call the new routine at $04D7 so we increment the track number in zero page before advancing the drive arm. T00,S07,$34 change "36" to "D7" --v-- 0033:20 D7 04 JSR $04D7 --^-- ]PR#6 ...works... Quod erat liberandum. --------------------------------------- A 4am crack No. 595 ------------------EOF------------------