-------What Makes A Dinosaur Sore------ A 4am crack 2016-10-21 --------------------------------------- Name: What Makes A Dinosaur Sore Genre: educational Year: 1987 Credits: Rob Shaver, Peter Andrews, James Morrow, Angela Faeth Publisher: D.C. Heath and Company Media: two single-sided 5.25-inch disks OS: ProDOS 1.2 Previous cracks: none Similar cracks: #811 Rosie The Counting Rabbit #202 Squeegee Learns About Drugs (spoiler: they're bad, mmkay) Only disk 1 ("program") is bootable, so I'll start there. ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no read errors, but copy loads ProDOS then hangs with drive motor on 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 disk catalog Why didn't any of my copies work? probably a nibble check in the first SYSTEM file Next steps: 1. trace first .SYSTEM file 2. disable protection check 3. I don't know, go feed the ducks or something? ~ Chapter 1 In Which Things Are Not Always As They Appear [S7,D1=my ProDOS hard drive] [S6,D1=non-working copy] ]PR#7 ]CAT,S6,D1 /EXPLORE NAME TYPE BLOCKS MODIFIED DISK BIN 4 24-FEB-88 FLIPS DIR 1 3-AUG-87 ICONS DIR 1 9-JAN-87 AUXLOW BIN 8 24-FEB-88 AUX.48 BIN 33 24-FEB-88 AUX.LC BIN 25 24-FEB-88 SETUP BIN 1 24-FEB-88 STORY.SYSTEM SYS 3 24-FEB-88 *PRODOS SYS 32 6-SEP-86 TITLE.SCREEN BIN 12 2-SEP-86 MEMORY.CONFIG SYS 3 16-DEC-88 WORDS DIR 1 9-JAN-87 P.DINO.3 DIR 1 3-AUG-87 COLOR.DATA BIN 7 15-JUL-86 BLOCKS FREE: 83 BLOCKS USED: 197 ]PREFIX /EXPLORE ]-STORY.SYSTEM ...loads and runs(!)... Wait, what? It's looking more and more likely that the nibble check is inside the PRODOS file itself. Instead of tracing the entire PRODOS file, I turn to my trusty Disk Fixer sector editor and searched for the hex sequence "BD 89 C0". Although there are many variations of copy protection, a surprising number of disks use a nibble check that starts by loading the X register with the slot number (x16) and an "LDA $C089,X" instruction to turn on the drive motor. And I get lucky: four matches. - T00,S0E - part of the ProDOS bootloader (expected) - T11,S00 - Copy II Plus disk map says this is part of the PRODOS file, but I looked and it's part of the RWTS. So this is expected and legitimate, not the start of a nibble check. - T0A,S05 - two matches, both highly suspicious Copy II Plus disk map says T0A,S05 is part of the MEMORY.CONFIG file. It's a SYS file, which means it's probably loaded at $2000. ]PR#7 ... ]PREFIX /EXPLORE ]BLOAD MEMORY.CONFIG,A$2000,TSYS ]CALL -151 *2000L 2000- 20 D1 21 JSR $21D1 *21D1L ; set up an MLI call with the boot slot 21D1- AD 30 BF LDA $BF30 21D4- 8D DF 21 STA $21DF ; call ProDOS MLI with command #$80, ; which is a raw block read 21D7- 20 00 BF JSR $BF00 21DA- [80] 21DB- [DE 21] 21DD- 60 RTS Continuing from $2003... ; turn on slot motor manually (always ; suspicious) 2003- AE 30 BF LDX $BF30 2006- BD 8A C0 LDA $C08A,X 2009- BD 89 C0 LDA $C089,X 200C- BD 8E C0 LDA $C08E,X ; an address? ($2300) or two separate ; parameters 200F- A9 00 LDA #$00 2011- 85 00 STA $00 2013- A9 23 LDA #$23 2015- 85 01 STA $01 ; not shown, but the subroutine at ; $21E4 moves the drive head to the ; track given in zero page $01 2017- 20 E4 21 JSR $21E4 So we're on track $23, which is weird. But wait, it's about to get weirder. ~ Chapter 2 A Fish Out Of ProDOS Continuing from $201A... 201A- 20 36 20 JSR $2036 *2036L 2036- A9 00 LDA #$00 2038- 85 04 STA $04 ; turn on slot motor manually, again, ; because abstractions are difficult ; I guess 203A- AE 30 BF LDX $BF30 203D- BD 89 C0 LDA $C089,X 2040- BD 8E C0 LDA $C08E,X 2043- 20 74 21 JSR $2174 *2174L ; boot slot (x16) 2174- AE 30 BF LDX $BF30 ; this looks identical to the code in ; a standard DOS 3.3 RWTS (specifically ; at $B944) which finds the next ; available address field 2177- A0 FC LDY #$FC 2179- 84 26 STY $26 217B- C8 INY 217C- D0 04 BNE $2182 217E- E6 26 INC $26 2180- F0 4D BEQ $21CF ; match "D5 AA 96" nibble sequence 2182- BD 8C C0 LDA $C08C,X 2185- 10 FB BPL $2182 2187- C9 D5 CMP #$D5 2189- D0 F0 BNE $217B 218B- EA NOP 218C- BD 8C C0 LDA $C08C,X 218F- 10 FB BPL $218C 2191- C9 AA CMP #$AA 2193- D0 F2 BNE $2187 2195- A0 03 LDY #$03 2197- BD 8C C0 LDA $C08C,X 219A- 10 FB BPL $2197 219C- C9 96 CMP #$96 219E- D0 E7 BNE $2187 21A0- A9 00 LDA #$00 21A2- 85 27 STA $27 21A4- BD 8C C0 LDA $C08C,X 21A7- 10 FB BPL $21A4 21A9- 2A ROL 21AA- 85 26 STA $26 21AC- BD 8C C0 LDA $C08C,X 21AF- 10 FB BPL $21AC 21B1- 25 26 AND $26 ; it even parses the address field into ; the same zero page locations as DOS 21B3- 99 2C 00 STA $002C,Y 21B6- 45 27 EOR $27 21B8- 88 DEY 21B9- 10 E7 BPL $21A2 21BB- A8 TAY 21BC- D0 11 BNE $21CF ; match single #$DE nibble for epilogue 21BE- BD 8C C0 LDA $C08C,X 21C1- 10 FB BPL $21BE 21C3- C9 DE CMP #$DE 21C5- D0 08 BNE $21CF 21C7- EA NOP 21C8- BD 8C C0 LDA $C08C,X 21CB- 10 FB BPL $21C8 21CD- 18 CLC 21CE- 60 RTS 21CF- 38 SEC 21D0- 60 RTS Continuing from $2046... ; is this the sector we wanted? (the ; physical sector number is now in ; zero page $2D) 2046- A5 2D LDA $2D 2048- C5 04 CMP $04 ; nope, loop back until we find it 204A- D0 F7 BNE $2043 ; skip to sync byte (#$FF) 204C- BD 8E C0 LDA $C08E,X 204F- BD 8C C0 LDA $C08C,X 2052- 10 FB BPL $204F 2054- C9 FF CMP #$FF 2056- D0 F4 BNE $204C 2058- A0 00 LDY #$00 205A- C8 INY ; skip an exact number of nibbles and ; look for #$D5 205B- BD 8E C0 LDA $C08E,X 205E- BD 8C C0 LDA $C08C,X 2061- 10 FB BPL $205E 2063- C9 D5 CMP #$D5 ; if not found in correct location (Y ; register counts the nibbles before ; the #$D5), try again from the top 2065- D0 F3 BNE $205A 2067- C0 07 CPY #$07 2069- D0 D8 BNE $2043 ; do this for all sectors 206B- E6 04 INC $04 206D- A9 10 LDA #$10 206F- C5 04 CMP $04 2071- D0 D0 BNE $2043 ; start over on sector 0 2073- A9 00 LDA #$00 2075- 85 04 STA $04 2077- 20 74 21 JSR $2174 207A- A5 2D LDA $2D 207C- C5 04 CMP $04 207E- D0 F7 BNE $2077 ; skip to address epilogue 2080- BD 8C C0 LDA $C08C,X 2083- 10 FB BPL $2080 2085- C9 AA CMP #$AA 2087- D0 F7 BNE $2080 2089- BD 8C C0 LDA $C08C,X 208C- 10 FB BPL $2089 208E- C9 EB CMP #$EB 2090- D0 EE BNE $2080 ; skip to sync byte (#$FF) 2092- BD 8C C0 LDA $C08C,X 2095- 10 FB BPL $2092 2097- C9 FF CMP #$FF 2099- D0 F7 BNE $2092 ; skip an exact number of nibbles and ; look for #$D5 209B- A0 00 LDY #$00 209D- C8 INY 209E- BD 8E C0 LDA $C08E,X 20A1- BD 8C C0 LDA $C08C,X 20A4- 10 FB BPL $20A1 20A6- C9 D5 CMP #$D5 ; if not found in correct location, try ; again from the top 20A8- D0 F3 BNE $209D ; again, Y register counts the nibbles ; before the #$D5 20AA- C0 10 CPY #$10 20AC- D0 C5 BNE $2073 ; do this for several other sectors 20AE- E6 04 INC $04 20B0- A9 0A LDA #$0A 20B2- 20 68 21 JSR $2168 20B5- A9 04 LDA #$04 20B7- C5 04 CMP $04 20B9- D0 04 BNE $20BF 20BB- E6 04 INC $04 20BD- D0 B8 BNE $2077 20BF- A9 0F LDA #$0F 20C1- C5 04 CMP $04 20C3- D0 BB BNE $2080 20C5- 20 74 21 JSR $2174 20C8- A5 2D LDA $2D 20CA- C9 0F CMP #$0F 20CC- D0 F7 BNE $20C5 ; read data field (not shown) 20CE- 20 FB 20 JSR $20FB ; look for #$A5 nibble in a specific ; place 20D1- A0 00 LDY #$00 20D3- C8 INY 20D4- BD 8E C0 LDA $C08E,X 20D7- BD 8C C0 LDA $C08C,X 20DA- 10 FB BPL $20D7 20DC- C9 A5 CMP #$A5 20DE- D0 F3 BNE $20D3 ; Y register counts nibbles before #$A5 20E0- C0 2D CPY #$2D 20E2- D0 E1 BNE $20C5 ; look for #$D5 nibble in a specific ; place 20E4- A0 00 LDY #$00 20E6- C8 INY 20E7- BD 8E C0 LDA $C08E,X 20EA- BD 8C C0 LDA $C08C,X 20ED- 10 FB BPL $20EA 20EF- C9 D5 CMP #$D5 20F1- D0 F3 BNE $20E6 ; Y register counts nibbles before #$D5 20F3- C0 5D CPY #$5D 20F5- D0 CE BNE $20C5 ; success path falls through to here 20F7- A0 00 LDY #$00 20F9- EA NOP 20FA- 60 RTS My copy never makes it this far. It's stuck in an infinite loop, trying to find a precisely organized track $23 (and failing). Continuing from $201D... ; seek back to track $00 (from $23) 201D- A9 23 LDA #$23 201F- 85 00 STA $00 2021- A9 00 LDA #$00 2023- 85 01 STA $01 2025- 20 E4 21 JSR $21E4 ; copy some real code to lower memory 2028- A0 00 LDY #$00 202A- B9 42 22 LDA $2242,Y 202D- 99 00 10 STA $1000,Y 2030- C8 INY 2031- D0 F7 BNE $202A ; and jump there 2033- 4C 00 10 JMP $1000 It looks like I should be able to skip over the protection check by jumping straight to the success path at $2028. T18,S00,$00: 202021 -> 4C2820 ]PR#6 ...works... Disk 2 ("student disk") is unprotected. Quod erat liberandum. ~ Epilogue The program runs when I execute STORY.SYSTEM directly. So how does MEMORY.CONFIG get called? Disk Fixer --> [F]ind --> [A]SCII --> "CONFIG" --v-- -------------- DISK EDIT -------------- TRACK $0E/SECTOR $0D/VOLUME $FE/BYTE$E8 --------------------------------------- $80: CD A2 A0 C6 C9 CC C5 A0 M" FILE $88: A0 AA AA A0 AA AA A0 A0 ** ** $90: D3 D9 D3 D4 C5 CD A0 D0 SYSTEM P $98: D2 CF C7 D2 C1 CD A0 D4 ROGRAM T $A0: CF CF A0 CC C1 D2 C7 C5 OO LARGE $A8: A0 A0 AA AA AA AA A0 D5 **** U $B0: CE C1 C2 CC C5 A0 D4 CF NABLE TO $B8: A0 CC CF C1 C4 A0 D8 AE LOAD X. $C0: D3 D9 D3 D4 C5 CD A0 AA SYSTEM * $C8: AA AA AA AA AA AA AA AA ******** $D0: AA 00 03 80 02 00 14 01 *@C.B@TA $D8: 02 01 00 00 00 04 01 00 BA@@@DA@ $E0: 20 00 00 00 00 01 00 AE @@@@A@. $E8: C3 CF CE C6 C9 C7 8D 08 CONFIG.H ^^^^^^^^^^^^^^^^^ this should be "SYSTEM" $F0: C0 B5 42 8D 09 C0 95 42 @5B.I@.B $F8: CA 10 F3 A9 28 38 8D 08 JPs)(8.H --------------------------------------- BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/NORMAL ---------------------------------------- COMMAND : _ --^-- And there it is: a hacked version of PRODOS that, instead of looking for the first .SYSTEM file, looks for the first .CONFIG file. Of course there's only one of those, MEMORY.CONFIG, which silently performs its nibble check before manually reading STORY.SYSTEM and jumping to it. --------------------------------------- A 4am crack No. 884 ------------------EOF------------------