-----------1 2 3 Sequence Me----------- A 4am crack 2014-08-18 --------------------------------------- "1-2-3 Sequence Me" is a 1991 educational game by Infotech Manitoba Educational Technology Program and distributed by Sunburst. COPYA copies the disk without any read errors, but the copy does not work. It boots ProDOS, displays a graphical Sunburst logo, then displays the error message: "Unable to load. Press RETURN to quit." Booting from my ProDOS hard drive and running BASIC.SYSTEM, I can see the directory structure on the non-working copy. ]CAT,S6,D1 /SEQUENCE.ME5 NAME TYPE BLOCKS MODIFIED PRODOS SYS 32 18-AUG-89 ONE.SYSTEM SYS 13 26-OCT-90 LIBRARY BIN 38 26-OCT-90 MENUPICS BIN 8 26-OCT-90 SEQPICS BIN 106 9-OCT-90 MENU BAS 9 26-OCT-90 GAME BAS 11 22-OCT-90 BLOCKS FREE: 56 BLOCKS USED: 224 ProDOS loads the first .SYSTEM file at $2000 and jumps to it. ]PREFIX /SEQUENCE.ME5 ]BLOAD ONE.SYSTEM,A$2000,TSYS ]CALL -151 *2000L 2000- 58 CLI 2001- A2 FF LDX #$FF 2003- 9A TXS 2004- A9 00 LDA #$00 2006- 8D F3 03 STA $03F3 2009- 8D F4 03 STA $03F4 ; hook the input and output vectors (at ; zero page $36 and $38), then jump to ; BASIC coldstart routine (at $E000) 200C- A9 20 LDA #$20 200E- 85 38 STA $38 2010- A9 20 LDA #$20 2012- 85 39 STA $39 2014- A9 1F LDA #$1F 2016- 85 36 STA $36 2018- A9 20 LDA #$20 201A- 85 37 STA $37 201C- 4C 00 E0 JMP $E000 201F- 60 RTS Execution continues at $2020 when the ROM attempts to print a BASIC prompt and jumps to the hooked output vector. *2020L ; clear the stack 2020- A2 FF LDX #$FF 2022- 9A TXS ; initialize text/video/keyboard/screen 2023- 20 89 FE JSR $FE89 2026- 20 93 FE JSR $FE93 2029- 20 84 FE JSR $FE84 202C- 20 39 FB JSR $FB39 202F- 20 58 FC JSR $FC58 ; don't know what these do yet 2032- 20 3B 21 JSR $213B *213BG Ah, this is what displays the graphical Sunburst logo screen and returns. Even though I can't see the text screen, I can type *C051 C054 and get back to the monitor prompt. Harmless (as far as copy protection). Continuing with disassembly... 2035- 20 F6 20 JSR $20F6 *20F6G Returns immediately. (Listing it shows that it just modifies the ProDOS memory protection map at $BF58..$BF6F.) Moving on... 2038- 20 85 21 JSR $2185 203B- A9 81 LDA #$81 203D- B0 0B BCS $204A Hmm, a JSR followed by a branch on carry. Mildly suspicious. *2185G Loads something from disk. Promising... *2185L ; Under ProDOS, $BF30 holds the current ; slot number (x16) 2185- AD 30 BF LDA $BF30 2188- 20 EB 21 JSR $21EB 218B- 90 22 BCC $21AF *21EBL ; munge the slot number (x16) into the ; high byte of the disk controller ROM ; routine (e.g. $60 becomes $C6) 21EB- AA TAX 21EC- 29 70 AND #$70 21EE- 4A LSR 21EF- 4A LSR 21F0- 4A LSR 21F1- 4A LSR 21F2- 18 CLC 21F3- 69 C0 ADC #$C0 21F5- 8D 23 22 STA $2223 ; check for a few magic bytes to ; identify the disk controller ROM 21F8- A0 01 LDY #$01 21FA- A9 20 LDA #$20 21FC- 20 21 22 JSR $2221 ; and, apparently, fail if the ROM is ; not recognized 21FF- D0 1D BNE $221E 2201- A0 03 LDY #$03 2203- A9 00 LDA #$00 2205- 20 21 22 JSR $2221 2208- D0 14 BNE $221E 220A- A0 05 LDY #$05 220C- A9 03 LDA #$03 220E- 20 21 22 JSR $2221 2211- D0 0B BNE $221E 2213- A0 FF LDY #$FF 2215- A9 00 LDA #$00 2217- 20 21 22 JSR $2221 221A- D0 02 BNE $221E 221C- 18 CLC 221D- 60 RTS 221E- 8A TXA 221F- 38 SEC 2220- 60 RTS 2221- D9 00 C6 CMP $C600,Y 2224- 60 RTS 2225- 38 SEC 2226- 60 RTS So the subroutine at $21EB will set the carry if the disk controller ROM is not recognized. If the carry is clear, then execution continues at $21AF. (There is a BCC at $218B, immediately after the subroutine returns.) *21AFL 21AF- 4C B7 24 JMP $24B7 *24B7L ; save zero page $00 24B7- A5 00 LDA $00 24B9- 48 PHA ; munge slot number again 24BA- AD 30 BF LDA $BF30 24BD- 29 70 AND #$70 24BF- 85 00 STA $00 ; don't know what this does yet 24C1- 20 DB 24 JSR $24DB ; but it looks important 24C4- B0 0F BCS $24D5 ; try something 3 times 24C6- A9 03 LDA #$03 24C8- 8D DA 24 STA $24DA 24CB- 20 0A 25 JSR $250A ; one success is enough to clear the ; carry and exit gracefully 24CE- 90 06 BCC $24D6 24D0- CE DA 24 DEC $24DA 24D3- D0 F6 BNE $24CB 24D5- 38 SEC ; restore zero page $00 24D6- 68 PLA 24D7- 85 00 STA $00 24D9- 60 RTS 24DA- 00 BRK I'm closing in on it. Can you feel it? All the checks; all the indirection; all the "if this doesn't work perfectly the first time then it's game over" branches. This is not code that has my best interests at heart. Let's see what's at $250A. *250AL 250A- AD 30 BF LDA $BF30 250D- 8D 29 25 STA $2529 ; ProDOS MLI call 2510- 20 00 BF JSR $BF00 ; data for the MLI call 2513- C5 28 25 ; looks like an RWTS call (I realize ; this program is ProDOS-based, but ; this looks *exactly* like the RWTS ; call on DOS 3.3 disks at $B7B5) 2516- 08 PHP 2517- 78 SEI 2518- 20 41 25 JSR $2541 251B- 90 08 BCC $2525 251D- 20 3D 25 JSR $253D 2520- 90 03 BCC $2525 2522- 28 PLP 2523- 38 SEC 2524- 60 RTS 2525- 28 PLP 2526- 18 CLC 2527- 60 RTS *2541L ; gotcha 2541- A9 16 LDA #$16 2543- 8D A6 25 STA $25A6 2546- A6 00 LDX $00 ; turn on drive motor 2548- BD 89 C0 LDA $C089,X 254B- BD 8E C0 LDA $C08E,X 254E- 18 CLC 254F- A5 00 LDA $00 2551- 69 8C ADC #$8C 2553- 8D 67 25 STA $2567 2556- 8D E5 25 STA $25E5 2559- A0 E0 LDY #$E0 255B- 8C EA 25 STY $25EA 255E- C8 INY 255F- D0 05 BNE $2566 2561- EE EA 25 INC $25EA ; too many tries, give up 2564- F0 77 BEQ $25DD ; find address prologue ("D5 AA 96") 2566- AD EC C0 LDA $C0EC 2569- 10 FB BPL $2566 256B- C9 D5 CMP #$D5 256D- D0 EF BNE $255E 256F- 20 E4 25 JSR $25E4 2572- C9 AA CMP #$AA 2574- D0 F5 BNE $256B 2576- 20 E4 25 JSR $25E4 2579- C9 96 CMP #$96 257B- D0 EE BNE $256B ; skip actual address field 257D- 20 E4 25 JSR $25E4 2580- 20 E4 25 JSR $25E4 2583- A2 03 LDX #$03 2585- 20 E4 25 JSR $25E4 2588- C9 AA CMP #$AA 258A- D0 D2 BNE $255E 258C- CA DEX 258D- 10 F6 BPL $2585 258F- 20 E4 25 JSR $25E4 2592- 20 E4 25 JSR $25E4 2595- 20 E4 25 JSR $25E4 ; skip address epilogue 2598- C9 DE CMP #$DE 259A- D0 C2 BNE $255E 259C- A6 00 LDX $00 259E- BD 8C C0 LDA $C08C,X 25A1- 10 FB BPL $259E 25A3- C9 AA CMP #$AA 25A5- F0 02 BEQ $25A9 25A7- D0 B5 BNE $255E 25A9- A0 02 LDY #$02 ; kill some time to get out of sync ; with the "proper" start of nibbles) 25AB- BD 8D C0 LDA $C08D,X ; 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) 25AE- BD 8C C0 LDA $C08C,X 25B1- 10 FB BPL $25AE 25B3- C9 BB CMP #$BB 25B5- F0 1B BEQ $25D2 25B7- 88 DEY 25B8- 10 F4 BPL $25AE 25BA- 4C 61 25 JMP $2561 25BD- A0 02 LDY #$02 25BF- BD 8D C0 LDA $C08D,X 25C2- 48 PHA 25C3- 68 PLA 25C4- BD 8C C0 LDA $C08C,X 25C7- 10 FB BPL $25C4 25C9- C9 BB CMP #$BB 25CB- F0 05 BEQ $25D2 25CD- 88 DEY 25CE- 10 F4 BPL $25C4 25D0- 30 E8 BMI $25BA 25D2- BD 8C C0 LDA $C08C,X 25D5- 10 FB BPL $25D2 25D7- C9 F9 CMP #$F9 25D9- D0 DF BNE $25BA ; nice little pattern here to save one ; byte and slightly obfuscate the code: ; success path is at $25DB and clears ; the carry, while the failure path is ; at $25DD (in the middle of a listed ; instruction) and sets the carry 25DB- 18 CLC 25DC- 24 38 BIT $38 ; turn off the drive motor and quit 25DE- A6 00 LDX $00 25E0- BD 88 C0 LDA $C088,X 25E3- 60 RTS 25E4- AD EC C0 LDA $C0EC 25E7- 10 FB BPL $25E4 25E9- 60 RTS The good news is that there are no side effects to this nibble check, other than setting the carry flag. It doesn't use the nibbles it finds as some sort of decryption key for the next phase. At every step of the way, it clears the carry if all is well and sets the carry on "error" (in the sense that a non- original disk is an "error"). It's even nice enough to restore the zero page locations that it uses. Backing all the way up, I should be able to put a "CLC" and "RTS" at $2185 to claim unconditional success. A quick sector editor search finds this code on track $05. T05,S0E,$85 change "AD 30" to "18 60" Quod erat liberandum. --------------------------------------- A 4am crack No. 113 ------------------EOF------------------