-------------Memory Minder------------- A 4am crack 2015-11-22 --------------------------------------- Name: Memory Minder Version: A-44 Genre: productivity Year: 1984 Publisher: Computer Headware Media: double-sided 5.25-inch floppy OS: DOS 3.3 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 What does the boot look and sound like? 1. immediate blank screen 2. several sequential track reads 3. DOS prompt 4. track seek (maybe to T11?) 5. more disk activity (back and forth like file access) 6. title screen Does it access the disk after boot? Yes, repeatedly. Does it have an option to read, write, or format user-supplied data disks? Yes. 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 hangs after reading one track Copy ][+ nibble editor T00 -> standard prologues, modified epilogues (FF FF EB) T01-T02 -> corrupted address fields that claim to be track $00 T03-T04 -> not full tracks? looks like they have some standard-ish sectors, but not 16 per track (also corrupted address fields) T05..T11 -> standard prologues, modified epilogues (FF FF FF), standard address fields T12+ unformatted --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 01 START: 2735 LENGTH: 185A ^^ 2710: FF FF FF FF FF FF FF FF VIEW 2718: FF FF FF FF FF FF FF FF 2720: FF FF FF FF FF FF FF FF 2728: FF FF FF FF FF FF FF FF 2730: FF FF FF FF FF D5 AA 96 <-2735 ^^^^^^^^ address prologue 2738: AA AA AA AA AA AA AA AA ^^^^^ ^^^^^ ^^^^^ ^^^^^ V000 T00 S00 chksm 2740: FF FF FF FF FC FF FF FF ^^^^^^^^ address epilogue 2748: FF D5 AA AD F2 FA D7 D7 ^^^^^^^^ data prologue 2750: A6 BE FE F7 FB EC 97 B9 --------------------------------------- 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 EB" set Data Epilogue to "FF FF EB" T00 readable T01..T04 unreadable (no option to ignore the corrupted address field) T05..T11 readable T11 looks like DOS 3.3 catalog Copy ][+ sector editor ["P" -> "Sector Editor Patcher"] set type to "CUSTOM" set Address Epilogue to "FF FF" set Data Epilogue to "FF FF EB" T00, T05..T22 readable ["P" -> "Sector Editor Patcher"] set CHECK TRACK to "NO" T01 readable! only parts of T03 and T04 readable: T03: S03,04,05,06,07,0A,0B,0C,0D,0E T04: S01,02,04,08,09,0C,0F Why didn't COPYA work? modified epilogue bytes (every track) Why didn't Locksmith FDB work? modified epilogue bytes (every track) Why didn't my EDD copy work? I don't know. Maybe a nibble check during boot? Next steps: 1. Super Demuffin to convert the tracks that have modified epilogue bytes but are otherwise normal, complete, and uncorrupted 2. Trace the boot 3. See what happens ~ Chapter 1 In Which Everything Is Awesome When you first run Super Demuffin, it asks for the parameters of the original disk. In this case, the prologue bytes are the same, but the epilogues are "FF FF EB" instead of "DE AA EB". --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 change (was DE AA EB) Data prologue: D5 AA AD Data epilogue: FF FF EB ^^^^^^^^ change (was DE AA EB) 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. It assumes that both disks are in slot 6, and that drive 1 is the original and drive 2 is the copy. [S6,D1=original disk] [S6,D2=blank disk] --v-- LOCKSMITH 7.0 FAST DISK BACKUP R.****.............***************** W*********************************** HEX 00000000000000001111111111111111222 TRK 0123456789ABCDEF0123456789ABCDEF012 0.AAAA.............***************** 1.AAAA.............***************** 2.AAAA.............***************** 3.AAAA.............***************** 4.AAAA.............***************** 5.AAAA.............***************** 6.AAAA.............***************** 7.AAAA.............***************** 8.AAAA.............***************** 9.AAAA.............***************** A.AAAA.............***************** B.AAAA.............***************** C.AAAA.............***************** D.AAAA.............***************** 12 E.AAAA.............***************** F.AAAA.............***************** [ ] PRESS [RESET] TO EXIT --^-- That's about what I expected. It can't read tracks $01-$04 because the address field is intentionally corrupted. And it can't read tracks $12+ because they are unformatted. Other than that, it worked great. Let's go see what's on those unreadable tracks. [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 02 LDA #$02 0819- 48 PHA ; machine initialization (memory banks, ; TEXT, IN#0, PR#0, HOME, &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 0829- 20 58 FC JSR $FC58 082C- 8D 51 C0 STA $C051 082F- 8D 54 C0 STA $C054 0832- 8D 52 C0 STA $C052 ; set up ($3E) vector to point to the ; sector read routine in the disk ; controller ROM 0835- A9 5C LDA #$5C 0837- 85 3E STA $3E ; The disk controller ROM always exits ; via $0801, so set that to an "RTS". ; Then we can treat it like any other ; subroutine: JSR to it and continue. 0839- A9 60 LDA #$60 083B- 8D 01 08 STA $0801 ; double hmm 083E- A9 72 LDA #$72 0840- 48 PHA OK, we've now pushed $02/$72 on the stack. That's probably important. ; multi-sector read ; Y = start logical sector ($01) ; X = end logical sector ($03) ; A = start address high byte ($9D) 0841- A0 00 LDY #$00 0843- 84 FC STY $FC 0845- C8 INY 0846- A9 9D LDA #$9D 0848- A2 03 LDX #$03 084A- 20 50 08 JSR $0850 ; another sector read, this time just ; one sector, into $0200 (X is already ; less than Y on entry, so loop will ; exit after one read) 084D- A9 02 LDA #$02 084F- AA TAX ; falls through to multi-sector read ; entry point (was also called earlier ; from $084A) 0850- 85 27 STA $27 0852- E8 INX 0853- 86 49 STX $49 0855- 84 F9 STY $F9 ; map logical into physical sector and ; store it in zero page where the disk ; controller ROM will look for it 0857- B9 6E 08 LDA $086E,Y 085A- 85 3D STA $3D ; read sector via disk controller ROM 085C- 20 69 08 JSR $0869 ; loop until done 085F- A4 F9 LDY $F9 0861- C8 INY 0862- C4 49 CPY $49 0864- 90 EF BCC $0855 0866- A5 27 LDA $27 0868- 60 RTS ; 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?) 0869- A6 2B LDX $2B 086B- 6C 3E 00 JMP ($003E) ; logical to physical sector mapping 086E- 00 03 0870- 05 07 09 0B 0D 0F 02 04 0872- 06 08 0A 0C 0E 01 That's it. Flexible but compact. So where does this routine go next? Ah! We manually pushed $02/$72 to the stack earlier, so once we fall through to the multi-sector read routine (at $0862) and hit the RTS (at $087A), it will "return" to $0272 + 1 = $0273. Let's interrupt the boot before it gets there. ~ Chapter 2 In Which Things Get Brilliantly Weird *9600physical sectors is at ; $0263) or a physical sector 021D- 24 4A BIT $4A 021F- 30 03 BMI $0224 ; store physical sector in $3D (again, ; used by the disk controller ROM) 0221- B9 63 02 LDA $0263,Y 0224- 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 ; after reading a sector this just ; continues to the next line 0226- 20 00 02 JSR $0200 ; increment sector index 0229- A4 F9 LDY $F9 022B- C8 INY ; are there more sectors to read? 022C- C4 49 CPY $49 ; yes, branch back and repeat 022E- 90 EA BCC $021A ; 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) 0230- A5 27 LDA $27 0232- 60 RTS To sum up: These two lines of code... || 02BE- A9 A0 LDA #$A0 || || 02C0- 4C 0B 02 JMP $020B || advanced the drive head from track $00 to track $01, read the entire track into $A000..$AFFF (despite the fact that every sector's address field was corrupted and claimed to be track $00), then fall through from $020B to $020E and do it all over again, but moving to track $02 and reading into $B000..$BFFF instead. Beautiful. ~ Chapter 3 Every Byte Is Sacred, Every Byte Is Great, If A Byte Gets Wasted, Woz Gets Quite Irate Continuing from $0278... 0278- 20 98 02 JSR $0298 *298L ; advance the drive head a whole track 0298- 20 33 02 JSR $0233 [now on track 3] ; zero page fiddling (see below) 029B- A9 00 LDA #$00 029D- 85 41 STA $41 029F- 38 SEC 02A0- 66 4A ROR $4A ; Read several sectors (but not the ; entire track) ; A = start address high byte ($10) ; Y = start sector ($01) ; X = end sector ($05) 02A2- A9 10 LDA #$10 02A4- A0 01 LDY #$01 02A6- A2 05 LDX #$05 02A8- 20 15 02 JSR $0215 ; move the drive head one phase only, ; to the next HALF track 02AB- 20 36 02 JSR $0236 [now on track 3.5] ; read more sectors ($06..$0A) 02AE- A2 0A LDX #$0A 02B0- 20 15 02 JSR $0215 ; advance another half track 02B3- 20 36 02 JSR $0236 [now on track 4] ; read more sectors ($0B..$0F) 02B6- A2 0F LDX #$0F 02B8- 20 15 02 JSR $0215 ; fiddle with $4A again 02BB- 46 4A LSR $4A 02BD- 60 RTS So here's the deal with $4A: we initialized it at $0273 by a blind LSR, which clears the high bit. This tells the multi-sector read routine at $0215 to use logical sectors. Then we set the high bit at $029F with SEC + ROR, indicating we want $0215 to read physical sectors. Then we read a few sectors from track 3, a few from track 3.5, and a few from track 4. Then we reset $4A with another LSR, and we're back to using logical sectors. This explains why my EDD bit copy failed. This disk is storing data on half tracks. Worse, it's storing data on *adjacent* half tracks -- a few from track 3, a few from track 3.5, and a few from track 4. Due to limitations of the Disk II drive mechanism, that would be virtually impossible for a generic bit copier to reproduce on a blank floppy disk. Every part of this code is brilliant. AND it fits in a single sector in low memory. AND it's flexible enough to read from virtually uncopyable disks. Continuing from $027B... ; now put slot number (x16) into... ; an RWTS parameter table?!? 027B- A6 2B LDX $2B 027D- 8E E9 B7 STX $B7E9 ; turn off drive motor 0280- BD 88 C0 LDA $C088,X ; set up DOS globals (tracking where ; the drive head is) 0283- 20 8E BE JSR $BE8E 0286- A5 FC LDA $FC 0288- 99 78 04 STA $0478,Y 028B- 4A LSR 028C- 8D 78 04 STA $0478 ; push $B7/$01 on the stack 028F- A9 B7 LDA #$B7 0291- 48 PHA 0292- A9 01 LDA #$01 0294- 48 PHA ; and exit via HOME 0295- 4C 58 FC JMP $FC58 Execution continues at $B702 (because we just pushed $B7/$01 on the stack). ~ Chapter 4 In Which Everything Is Terribly Awesome I can interrupt the boot to capture the code loaded at $A000..$BFFF and $1000.. $1EFF. For reasons I forget, I did this in two separate traces. *9600