------------Spelling Mastery----------- A 4am crack 2017-10-20 --------------------------------------- Name: Spelling Mastery Genre: educational Year: 1988 Credits: Ahead Designs Publisher: Developmental Learning Materials, Inc. Platform: Apple ][+ or later Media: single-sided 5.25-inch floppy OS: Pronto-DOS Previous cracks: none Similar cracks: #460 Curious George Visits The Library #185 Curious George in Outer Space #008 Curious George Goes Shopping ~ COPYA no errors, but copy displays a graphical error message "File not found, press C when you have corrected the problem" Locksmith Fast Disk Backup ditto EDD 4 bit copy (no sync, no count) ditto Copy ][+ nibble editor nothing suspicious Disk Fixer standard DOS 3.3-shaped bootloader (Pronto-DOS) disk catalog on track $11 T01,S07 -> startup program is "HELLO" Why didn't any of my copies work? Probably a sneaky runtime protection check somewhere that flips a bit and triggers a spurious "file not found" message to confuse me. Next steps: 1. Search for common signs of a runtime protection check 2. If that fails, trace the startup program 3. If that fails, I dunno, go feed the ducks or something? ~ Turning to my Disk Fixer sector editor, I search the disk for the most common indicator of a protection check: the soft switch that turns on the drive motor. [Disk Fixer] ["F"ind] ["H"ex] "BD 89 C0" --v-- ------------- DISK SEARCH ------------- $00/$07-$4F $14/$0E-$C3 PRESS [RETURN] --^-- The match on track $00 is part of the RWTS, i.e. legitimate. The match on track $14 immediately suspicious. Copy II Plus "disk map" tells me this sector is part of the "START" file, so let's look there. [S6,D1=non-working copy] ]PR#6 ...... ]LIST 10 ONERR GOTO 100 20 POKE 1012,0 30 HGR2 35 PRINT "MAXFILES 1" 40 PRINT "BLOAD START" 50 PRINT "BRUN MENU" 100 CALL - 1438 ]BLOAD START ]CALL -151 *AA72.AA73 AA72- 00 60 Scanning memory, I find the suspicious command at $61BF, in a routine that appears to start at $61AF. *61AFL 61AF- A9 60 LDA #$60 61B1- 8D 88 62 STA $6288 61B4- A9 05 LDA #$05 61B6- 8D 89 62 STA $6289 ; turn on drive motor manually 61B9- AE 88 62 LDX $6288 61BC- BD 8E C0 LDA $C08E,X 61BF- BD 89 C0 LDA $C089,X ; wait for drive to spin up 61C2- A9 00 LDA #$00 61C4- 8D 8A 62 STA $628A 61C7- A0 00 LDY #$00 61C9- C8 INY 61CA- D0 FD BNE $61C9 61CC- EE 8A 62 INC $628A 61CF- D0 F6 BNE $61C7 61D1- A9 00 LDA #$00 61D3- 8C 8A 62 STY $628A 61D6- 20 7C 62 JSR $627C *627CL ; get a disk nibble 627C- BD 8C C0 LDA $C08C,X 627F- 10 FB BPL $627C 6281- 60 RTS ; Y and $628A both start at 0, so this ; will look a loooong time for the ; expected nibbles, but not forever 61D9- C8 INY 61DA- D0 08 BNE $61E4 61DC- EE 8A 62 INC $628A 61DF- D0 03 BNE $61E4 61E1- 4C 77 62 JMP $6277 ; execution continues here (from $61DA ; or $61DF) ; find a nibble sequence, $D5 $AA $BB 61E4- C9 D5 CMP #$D5 61E6- D0 EE BNE $61D6 61E8- 20 7C 62 JSR $627C 61EB- C9 AA CMP #$AA 61ED- D0 F5 BNE $61E4 61EF- 20 7C 62 JSR $627C 61F2- C9 BB CMP #$BB 61F4- D0 EE BNE $61E4 ; capture several 4-4 encoded values ; (like an address field?) 61F6- A0 00 LDY #$00 61F8- 20 7C 62 JSR $627C 61FB- 38 SEC 61FC- 2A ROL 61FD- 8D 8A 62 STA $628A 6200- 20 7C 62 JSR $627C 6203- 2D 8A 62 AND $628A 6206- 99 8B 62 STA $628B,Y 6209- C8 INY 620A- C0 02 CPY #$02 620C- D0 EA BNE $61F8 ; skip over 4 nibbles 620E- A0 00 LDY #$00 6210- 20 7C 62 JSR $627C 6213- C8 INY 6214- C0 04 CPY #$04 6216- D0 F8 BNE $6210 ; skip over sync nibbles ($FF) 6218- BD 8C C0 LDA $C08C,X 621B- 10 FB BPL $6218 621D- C9 FF CMP #$FF 621F- D0 4E BNE $626F ; reset data latch 6221- BD 8D C0 LDA $C08D,X ; kill some time to get out of sync ; with the "proper" start of nibbles) 6224- A0 10 LDY #$10 6226- A5 09 LDA $09 ; now start looking for nibbles that ; don't really exist (except they do, ; because we're out of sync and reading ; timing bits as data) 6228- BD 8C C0 LDA $C08C,X 622B- 10 FB BPL $6228 622D- 88 DEY 622E- F0 3F BEQ $626F ; find a desynchronized $EE nibble 6230- C9 EE CMP #$EE 6232- D0 F4 BNE $6228 ; store next 4 desynchronized nibbles 6234- A0 00 LDY #$00 6236- BD 8C C0 LDA $C08C,X 6239- 10 FB BPL $6236 623B- 99 8D 62 STA $628D,Y 623E- C8 INY 623F- C0 04 CPY #$04 6241- D0 F3 BNE $6236 ; check 4-and-4 encoded values that we ; captured earlier 6243- AD 8B 62 LDA $628B 6246- CD 82 62 CMP $6282 6249- D0 24 BNE $626F 624B- AD 8C 62 LDA $628C 624E- CD 83 62 CMP $6283 6251- D0 1C BNE $626F ; check desynchronized nibbles that we ; captured earlier against an encrypted ; array at $6284 6253- A0 00 LDY #$00 6255- B9 8D 62 LDA $628D,Y 6258- 49 87 EOR #$87 625A- 38 SEC 625B- E9 01 SBC #$01 625D- D9 84 62 CMP $6284,Y 6260- D0 0D BNE $626F 6262- 99 8D 62 STA $628D,Y 6265- C8 INY 6266- C0 04 CPY #$04 6268- D0 EB BNE $6255 ; if everything checks out, execution ; falls through to here -- turn off the ; drive motor, clear the carry bit, and ; exit gracefully 626A- BD 88 C0 LDA $C088,X 626D- 18 CLC 626E- 60 RTS ; any failures end up here -- decrement ; the death counter and eventually give ; up 626F- CE 89 62 DEC $6289 6272- F0 03 BEQ $6277 6274- 4C D1 61 JMP $61D1 ; turn off drive, set carry, and exit 6277- BD 88 C0 LDA $C088,X 627A- 38 SEC 627B- 60 RTS ~ Interesting to note: there is no track seek at the beginning of this routine. It just assumes it's on the right track to find the magic protection bitstream. Turning back to the Copy II Plus nibble editor, I can see the $D5 $AA $BB nibble sequence on every single track, followed by the magic bitstream and desynchronized values. So this disk is always ready to verify its originality, regardless of which track it's on. The caller only cares about the carry bit, so let's just clear the carry bit at $61AF and exit unconditionally. T14,S0E,$B3: A9 -> 18 Quod erat liberandum. --------------------------------------- A 4am crack No. 1481 ------------------EOF------------------