----------Language Carnival 1---------- A 4am crack 2016-10-23 --------------------------------------- Name: Language Carnival 1 Genre: educational Year: 1988 Publisher: Developmental Learning Materials Platform: Apple ][+ or later (64K) Media: single-sided 5.25-inch floppy OS: ProDOS 1.4 Previous cracks: none ~ Chapter 0 In Which Various Automated Tools Fail In Interesting Ways COPYA no errors, but copy boots ProDOS, displays BASIC prompt, then exits to BASIC with no OS in memory Locksmith Fast Disk Backup ditto EDD 4 bit copy (no sync, no count) ditto Copy ][+ nibble editor nothing suspicious Disk Fixer T00 -> standard ProDOS bootloader and disk catalog Why didn't any of my copies work? probably a nibble check in the startup program Next steps: 1. Trace the startup program 2. Disable the nibble check 3. Declare victory(*) (*) go to the gym ~ Chapter 1 In Which Things Go Better Than Expected [S6,D1=non-working copy] [S7,D1=my ProDOS hard drive /A4AMCRACK] ]PR#7 ... ]CAT,S6,D1 /CARNIVAL1 NAME TYPE BLOCKS MODIFIED *BASIC.SYSTEM SYS 21 15-NOV-83 *CS BIN 5 22-SEP-87 DARTS BAS 13 5-NOV-87 GALLERY BAS 16 5-NOV-87 MM.WORDS TXT 9 15-OCT-87 PRODOS SYS 32 17-APR-87 PSET.0B BIN 6 15-OCT-87 PSET.0D BIN 9 15-OCT-87 PSET.CC BIN 9 15-OCT-87 PSET.DT BIN 6 15-OCT-87 RR.WORDS TXT 5 15-OCT-87 SP.WORDS TXT 6 15-OCT-87 START.2 BAS 15 2-NOV-87 STARTUP BAS 3 29-OCT-87 STRENGTH BAS 16 5-NOV-87 THROW BAS 15 5-NOV-87 LS BIN 17 15-OCT-87 SETUP BIN 1 2-DEC-87 SETUP2 BIN 1 2-DEC-87 BLOCKS FREE: 68 BLOCKS USED: 212 ]PREFIX /CARNIVAL1 ]LOAD STARTUP ]LIST 1 POKE 214,255: POKE 1012,0 4 PRINT CHR$ (4);"BLOAD SETUP" 5 PRINT CHR$ (4);"BLOAD SETUP2 ": CALL 12288 11 POKE 1012,0 15 LOMEM: 24576 20 D$ = CHR$ (4) 50 HOME : TEXT 55 PRINT : PRINT D$;"BLOAD CS,A $2000": POKE 232,0: POKE 233 ,32 60 PRINT D$;"BLOADLS,A$4000" 65 POKE 230,64:AA = PEEK (4923 2) + PEEK (49239) + PEEK ( 49237) + PEEK (49234) BREAK ] ]BLOAD SETUP ; loads at $3000 ]BLOAD SETUP2 ; loads at $2000 ]CALL -151 12288 is $3000, so let's start there. ~ Chapter 2 In Which It All Comes Down To One Bit *3000L ; a simple XOR decryption loop 3000- A2 E2 LDX #$E2 3002- BD 00 20 LDA $2000,X 3005- 49 FF EOR #$FF 3007- 9D 00 20 STA $2000,X 300A- CA DEX 300B- D0 F5 BNE $3002 ; call the decrypted code 300D- 20 00 20 JSR $2000 ; branch if carry is clear 3010- 90 04 BCC $3016 ; jump to BASIC cold start (never ; returns) 3012- 20 B0 FE JSR $FEB0 3015- 60 RTS ; successful execution continues here ; (from $3010) -- set some zero page ; value and exit 3016- A9 02 LDA #$02 3018- 85 FE STA $FE 301A- 60 RTS Well it's pretty clear that the code at $2000 is important (it's encrypted, after all), and that it is vitally important that it clear the carry flag on exit. ; stop after the decryption loop *300D:60 ; decrypt the mysterious code at $2000 *3000G *2000L ; hard-code slot 6 2000- A9 60 LDA #$60 2002- 8D D9 20 STA $20D9 2005- A9 05 LDA #$05 2007- 8D DA 20 STA $20DA 200A- AE D9 20 LDX $20D9 ; turn on slot 6 drive motor manually 200D- BD 8E C0 LDA $C08E,X 2010- BD 89 C0 LDA $C089,X 2013- A9 00 LDA #$00 2015- 8D DB 20 STA $20DB ; wait for drive to spin up 2018- A0 00 LDY #$00 201A- C8 INY 201B- D0 FD BNE $201A 201D- EE DB 20 INC $20DB 2020- D0 F6 BNE $2018 2022- A9 00 LDA #$00 2024- 8C DB 20 STY $20DB ; get a nibble from disk (not shown) 2027- 20 CD 20 JSR $20CD 202A- C8 INY 202B- D0 08 BNE $2035 202D- EE DB 20 INC $20DB 2030- D0 03 BNE $2035 2032- 4C C8 20 JMP $20C8 ; match "D5 AA BB" nibble sequence 2035- C9 D5 CMP #$D5 2037- D0 EE BNE $2027 2039- 20 CD 20 JSR $20CD 203C- C9 AA CMP #$AA 203E- D0 F5 BNE $2035 2040- 20 CD 20 JSR $20CD 2043- C9 BB CMP #$BB 2045- D0 EE BNE $2035 ; get some 4-4-encoded values and ; store them locally 2047- A0 00 LDY #$00 2049- 20 CD 20 JSR $20CD 204C- 38 SEC 204D- 2A ROL 204E- 8D DB 20 STA $20DB 2051- 20 CD 20 JSR $20CD 2054- 2D DB 20 AND $20DB 2057- 99 DC 20 STA $20DC,Y 205A- C8 INY 205B- C0 02 CPY #$02 205D- D0 EA BNE $2049 205F- A0 00 LDY #$00 2061- 20 CD 20 JSR $20CD 2064- C8 INY 2065- C0 04 CPY #$04 2067- D0 F8 BNE $2061 ; skip self-sync nibble (#$FF) 2069- BD 8C C0 LDA $C08C,X 206C- 10 FB BPL $2069 206E- C9 FF CMP #$FF 2070- D0 4E BNE $20C0 ; reset data latch 2072- BD 8D C0 LDA $C08D,X ; burn some CPU cycles (now we're out ; of phase with the "proper" start of ; nibbles) 2075- A0 10 LDY #$10 2077- A5 09 LDA $09 ; find #$EE in the "out of phase" ; nibbles 2079- BD 8C C0 LDA $C08C,X 207C- 10 FB BPL $2079 207E- 88 DEY 207F- F0 3F BEQ $20C0 2081- C9 EE CMP #$EE 2083- D0 F4 BNE $2079 ; store the next 4 "out of phase" ; nibbles locally 2085- A0 00 LDY #$00 2087- BD 8C C0 LDA $C08C,X 208A- 10 FB BPL $2087 208C- 99 DE 20 STA $20DE,Y 208F- C8 INY 2090- C0 04 CPY #$04 2092- D0 F3 BNE $2087 ; check the 4-4-encoded values we read ; earlier 2094- AD DC 20 LDA $20DC 2097- CD D3 20 CMP $20D3 209A- D0 24 BNE $20C0 209C- AD DD 20 LDA $20DD 209F- CD D4 20 CMP $20D4 20A2- D0 1C BNE $20C0 ; verify the "out of phase" nibbles ; against an encrypted array 20A4- A0 00 LDY #$00 20A6- B9 DE 20 LDA $20DE,Y 20A9- 49 87 EOR #$87 20AB- 38 SEC 20AC- E9 01 SBC #$01 20AE- D9 D5 20 CMP $20D5,Y 20B1- D0 0D BNE $20C0 20B3- 99 DE 20 STA $20DE,Y 20B6- C8 INY 20B7- C0 04 CPY #$04 20B9- D0 EB BNE $20A6 ; turn off drive motor 20BB- BD 88 C0 LDA $C088,X ; clear carry and return to caller 20BE- 18 CLC 20BF- 60 RTS ; failures end up here (from $20B1, ; $20A2, $209A, $207F, or $2070) -- ; decrement death counter and try again ; but eventually give up 20C0- CE DA 20 DEC $20DA 20C3- F0 03 BEQ $20C8 20C5- 4C 22 20 JMP $2022 ; ultimate failure path is here -- turn ; off drive motor, set carry, and ; return to caller 20C8- BD 88 C0 LDA $C088,X 20CB- 38 SEC 20CC- 60 RTS Despite appearances, there are no long- term side effects here. We're reading "out of phase" nibbles (like an E7 bitstream check, but different values) and storing them, then comparing them, but we don't actually *need* them in the long run. The caller simply checks the carry flag and sets a zero page value (at $3018). The ultimate caller, the BASIC startup program, immediately loads another file at $2000 ("CS", on line 55), which will wipe out all of this code and the nibble values we stored. So it's safe to simply change the code at $3000 to ignore the encrypted copy protection code at $2000 and branch to the success path at $3016. Turning to my Disk Fixer sector editor, I can set the DOS type to "PRODOS" and press "D" to get a directory listing, then follow the "SETUP" file and find the $3000 calling code on track $1A. T1A,S04,$0E: 00 -> BE (Change the JSR $2000 to JSR $20BE, which unconditionally clears the carry, then let the rest of the code think the check succeeded.) ]PR#6 ...works... Quod erat liberandum. --------------------------------------- A 4am crack No. 886 ------------------EOF------------------