-------------Writer Rabbit------------- A 4am crack 2015-08-17 -------------------. updated 2015-09-02 |___________________ Name: Writer Rabbit Version: 1.2 Genre: educational Year: 1986 Author: Leslie Grimm Publisher: The Learning Company Media: double-sided 5.25-inch floppy OS: "RDOS.SYSTEM" (ProDOS-compatible) Previous cracks: none Similar cracks: Writer Rabbit 1.3 (crack no. 15) Only side A is bootable. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no errors, but the copy boots to the graphical title screen then says "Fatal Disk Error" and hangs Locksmith Fast Disk Backup ditto EDD 4 bit copy (no sync, no count) ditto Copy ][+ nibble editor nothing suspicious Disk Fixer T00 -> looks like ProDOS bootloader and ProDOS disk catalog Why didn't any of my copies work? Probably a nibble check in the startup program Next steps: 1. Search for error message, maybe we'll get lucky 2. Disable nibble check 3. There is no step 3 (I hope) ~ Chapter 1 In Which We Get Lucky Turning to my trusty Disk Fixer sector editor, I scanned for the ASCII string "Fatal"... [S6,D1=non-working copy] [Disk Fixer] ["F"ind] ["A"SCII] "Fatal" ...but found nothing. However, knowing that many Apple II programs use 7-bit ASCII, I scanned for the hex sequence "46 61 74 61 6C" ("Fatal" without the high bit set): [Disk Fixer] ["F"ind] ["H"ex] "46 61 74 61 6C" Behold! Matches on T03,S0E and T10,S08. T03,S0E is the second half of a ProDOS block; the first half is T03,S00. (See "Beneath Apple DOS", fig. 3-24, "Comparison of Sector Skewing". You can also set Disk Fixer to ProDOS ordering mode and sector $0E will appear as $01, but I find that confusing so I rarely use it.) Anyway, the nibble check is on T03,S00, as seen through Disk Fixer's built-in disassembly mode: --v-- T03,S00 ----------- DISASSEMBLY MODE ---------- ; turn on drive motor manually 008B:BD 89 C0 LDA $C089,X ; some sort of Death Counter 008E:A9 56 LDA #$56 0090:85 08 STA $08 0092:A9 08 LDA #$08 0094:C6 07 DEC $07 0096:D0 04 BNE $009C 0098:C6 08 DEC $08 ; If the Death Counter hits zero, that ; would be bad. Which part of "Death ; Counter" sounded good to you, anyway? 009A:F0 3C BEQ $00D8 ; look for an $FB nibble 009C:BC 8C C0 LDY $C08C,X 009F:10 FB BPL $009C 00A1:C0 FB CPY #$FB 00A3:D0 ED BNE $0092 00A5:F0 00 BEQ $00A7 ; kill a few cycles (not pointless, ; because the disk spins independently ; of the CPU, so all of these low-level ; disk reads are highly time-sensitive) 00A7:EA NOP 00A8:EA NOP ; read data latch (note: no BPL loop ; here, we're just reading it once) 00A9:BC 8C C0 LDY $C08C,X ; do a compare to set or clear the ; carry bit (among other things, but ; it's the carry bit we care about) 00AC:C0 08 CPY #$08 ; rotate the carry into the low bit of ; the accumulator 00AE:2A ROL ; if we just rolled a "1" bit out of ; the high bit of the accumulator, take ; this branch 00AF:B0 0B BCS $00BC ; next nibble needs to be $FF 00B1:BC 8C C0 LDY $C08C,X 00B4:10 FB BPL $00B1 ; ...otherwise we start over 00B6:C0 FF CPY #$FF 00B8:D0 D8 BNE $0092 ; loop back to get next nibble 00BA:F0 EB BEQ $00A7 ; execution continues here (from $00AF) ; get another nibble 00BC:BC 8C C0 LDY $C08C,X 00BF:10 FB BPL $00BC ; stash it in zero page 00C1:84 07 STY $07 ; if the accumulator is anything but ; %00001010, start over 00C3:C9 0A CMP #$0A 00C5:D0 CB BNE $0092 ; get a nibble 00C7:BD 8C C0 LDA $C08C,X 00CA:10 FB BPL $00C7 ; more bit twiddling 00CC:38 SEC 00CD:2A ROL ; AND it with the previously stashed ; nibble 00CE:25 07 AND $07 00D0:49 FF EOR #$FF ; branch on failure 00D2:F0 04 BEQ $00D8 --^-- I got lost several times trying to follow this routine. I think the easiest way to explain it is to show the difference between the original disk and my non-working copy. ~ Chapter 2 In Which We Get Visual Here is the original disk, as seen by the Copy II+ nibble editor. Nibbles with extra "0" bits (timing bits) after them are displayed in inverse on an original machine, marked here with a "+" after the nibble. --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 00 START: 1B1E LENGTH: 17C1 1C70: 9F EB E5 FC D7 D7 D7 EE VIEW 1C78: FA E6 E6 FF FE F2 ED FD 1C80: FF EF ED BA BB DD AF E6 1C88: B7 A7 CB B7 DE AA EB FF 1C90: FF FF FF FB+FF FF+FF FF+ 1C98: FD FF+FF+FF+FF+FF+FF+FF+ 1CA0: FF+FF+D5 AA 96 AA AB AA 1CA8: AA AA AB AA AA DE AA EB+ 1CB0: FF+FF+FF+FF+FF+FF D5 AA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- It's easy to understand why a simple sector copy failed. The sequence that this code is looking for starts at offset $1C93, which is between the end of one sector and the beginning of the next. (The data epilogue is at $1C8C; the next address prologue is at $1CA2.) Sector copiers discard everything between those delimiters and rebuild the track with a default pattern of sync bytes. That pattern doesn't include an $FB nibble, so the nibble check fails. But the EDD bit copy also failed. Here is the original disk's pattern at offset $1C93: - $FB + timing bit - $FF - $FF + timing bit - $FF - $FF + timing bit And here is what the same part of the track looks like on my failed EDD copy: --v-- COPY ][ PLUS BIT COPY PROGRAM 8.4 (C) 1982-9 CENTRAL POINT SOFTWARE, INC. --------------------------------------- TRACK: 00 START: 1B1E LENGTH: 17C1 1C70: 9F EB E5 FC D7 D7 D7 EE VIEW 1C78: FA E6 E6 FF FE F2 ED FD 1C80: FF EF ED BA BB DD AF E6 1C88: B7 A7 CB B7 DE AA EB FF 1C90: FF FF FF FB+FF FF FF+FF+ 1C98: FD FF+FF+FF+FF+FF+FF+FF+ 1CA0: FF+FF+D5 AA 96 AA AB AA 1CA8: AA AA AB AA AA DE AA EB+ 1CB0: FF+FF+FF+FF+FF+FF D5 AA --------------------------------------- A TO ANALYZE DATA ESC TO QUIT ? FOR HELP SCREEN / CHANGE PARMS Q FOR NEXT TRACK SPACE TO RE-READ --^-- A subtle difference! The sequence at offset $1C93 now looks like this: - $FB + timing bit - $FF - $FF - $FF + timing bit - $FF + timing bit This code is looking for $FF bytes with an alternating pattern of timing bit, no timing bit, timing bit, no timing bit. It doesn't find that on the bit copy, so it knows it's not running on an original disk. ~ Chapter 3 In Which We Wrap Up Continuing the code listing... ; success path falls through to here -- ; turn off the drive motor and return ; to the caller 00D4:DD 88 C0 CMP $C088,X 00D7:60 RTS ; failure path (a.k.a. "The Badlands", ; from which there is no return) 00D8:DD 88 C0 CMP $C088,X ; I'm pretty sure this is the routine ; that prints the error message on the ; screen. A/X is low/high address of ; the coordinates or some parameters, ; followed by the error message itself ; (see below) 00DB:A9 10 LDA #$10 00DD:A2 8F LDX #$8F 00DF:20 D4 8D JSR $8DD4 00E2:38 SEC 00E3:6E 69 56 ROR $5669 00E6:20 6E 56 JSR $566E 00E9:00 14 8F 00EC:A9 A2 LDA #$A2 00EE:8D 85 8E STA $8E85 00F1:A9 01 LDA #$01 00F3:8D 00 03 STA $0300 00F6:A9 7F LDA #$7F 00F8:8D 87 40 STA $4087 00FB:A9 00 LDA #$00 00FD:8D 88 40 STA $4088 T03,S0E ----------- DISASSEMBLY MODE ----------- 0000:A9 FF LDA #$FF 0002:8D 89 40 STA $4089 0005:A9 00 LDA #$00 0007:8D 8A 40 STA $408A 000A:20 8B 40 JSR $408B ; this jumps to a routine that wipes ; memory and hangs 000D:4C 7E 8E JMP $8E7E ; error message is here 0010:52 04 2E 20 0D 0012:"Fatal Disk Error" --^-- There don't appear to be any side effects. The routine either returns gracefully or prints an error and never returns at all. I should be able to put an "RTS" at the beginning of it to bypass it entirely. T03,S00,$8B change "BD" to "60" There is an identical nibble check on track $10. T10,S06,$E2 change "BD" to "60" ]PR#6 ...works... ~ Chapter 4 In Which It Doesn't Work ...That is, until I select "Silly Sentence Party", flip to side B, and select "Return to Main Menu". Then I get a "Fatal Disk Error" again. The menu program is duplicated on both sides, and each one contains the same nibble check! Luckily, the third nibble check (on side B) is identical to the ones on side A. I found it easily with a sector search for the same hex sequence (the error message with high bit off): [Disk Fixer] ["F"ind] ["H"ex] "46 61 74 61 6C" Side B,T08,S0C,$E2 change "BD" to "60" Quod erat liberandum. ~ Changelog 2015-09-02 - Vastly improved explanation of the actual protection routine. Thanks to qkumba for pointing out that my original explanation was inaccurate. 2015-08-17 - initial release --------------------------------------- A 4am crack No. 407 ------------------EOF------------------