💾 Archived View for mirrors.apple2.org.za › active › 4am › images › games › action › Lock%20N%20Chas… captured on 2023-05-24 at 23:03:25.
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
-------------Lock 'N' Chase------------ A 4am crack 2014-05-03 --------------------------------------- Lock 'N' Chase is a 1982 arcade game distributed by Data East USA, Inc. and Mattel Electronics. COPYA gives no read errors, but the copy boots to an "UNABLE TO LOAD GAME" message and hangs. There is no VTOC on track $11 and no other clues to go on. Time for boot tracing! [S6D1=original disk] [S5D1=my work disk] ]PR#5 ... CAPTURING BOOT0 ...reboots slot 6... ...reboots slot 5... SAVING BOOT0 ]CALL-151 *800<2800.28FFM *801L ; relatively normal boot0 loop to load ; more sectors from track $00 0801- A5 27 LDA $27 0803- C9 09 CMP #$09 0805- D0 3D BNE $0844 0807- A5 2B LDA $2B 0809- 8D F4 03 STA $03F4 ; figure out what slot we're booting in 080C- 4A LSR 080D- 4A LSR 080E- 4A LSR 080F- 4A LSR 0810- 09 C0 ORA #$C0 0812- 85 3F STA $3F 0814- A9 5C LDA #$5C 0816- 85 3E STA $3E 0818- 18 CLC ; $08F9 contains high byte of address ; to load boot1 code (-1, due to how ; the math works out -- regular DOS 3.3 ; does this too, except at $08FE and ; $08FF) 0819- AD F9 08 LDA $08F9 ; $08FA contains number of sectors to ; read 081C- 6D FA 08 ADC $08FA 081F- 8D F9 08 STA $08F9 ; clear hi-res screen 2 and display it 0822- A0 40 LDY #$40 0824- 84 01 STY $01 0826- A9 00 LDA #$00 0828- 85 00 STA $00 082A- A8 TAY 082B- 91 00 STA ($00),Y 082D- C8 INY 082E- D0 FB BNE $082B 0830- E6 01 INC $01 0832- A6 01 LDX $01 0834- E0 60 CPX #$60 0836- D0 F3 BNE $082B 0838- 2C 52 C0 BIT $C052 083B- 2C 55 C0 BIT $C055 083E- 2C 57 C0 BIT $C057 0841- 2C 50 C0 BIT $C050 ; translate physical sector numbers to ; logical sector numbers 0844- AE FA 08 LDX $08FA ; when out of sectors to read, ; execution continues at $085E 0847- F0 15 BEQ $085E 0849- BD FB 08 LDA $08FB,X 084C- 85 3D STA $3D 084E- CE FA 08 DEC $08FA 0851- AD F9 08 LDA $08F9 0854- 85 27 STA $27 0856- CE F9 08 DEC $08F9 0859- A6 2B LDX $2B ; jump back to disk controller routine ; at $Cx5C (will be $C65C if we're ; booting from slot 6) 085B- 6C 3E 00 JMP ($003E) ; done reading sectors, execution continues 085E- A9 00 LDA #$00 0860- 85 06 STA $06 0862- 85 83 STA $83 0864- 85 00 STA $00 0866- 8D 78 02 STA $0278 0869- A9 09 LDA #$09 086B- 85 07 STA $07 086D- 85 01 STA $01 ; don't know what this does yet 086F- 20 00 04 JSR $0400 So we're loading track $00, sectors $01..$04 into $400..$7FF, then calling $0400. Let's interrupt the boot there and see evil lurks in the hearts of men who write copy protection routines. *9600<C600.C6FFM ; interrupt boot at $086F and jump to a ; routine under my control instead ; (at $970A) 96F8- A9 4C LDA #$4C 96FA- 8D 6F 08 STA $086F 96FD- A9 0A LDA #$0A 96FF- 8D 70 08 STA $0870 9702- A9 97 LDA #$97 9704- 8D 71 08 STA $0871 ; start boot 9707- 4C 01 08 JMP $0801 ; execution redirected here after ; loading 4 sectors into $0400..$07FF 970A- AD E8 C0 LDA $C0E8 ; capture that code before rebooting ; wipes out the text page 970D- A2 04 LDX #$04 970F- B9 00 04 LDA $0400,Y 9712- 99 00 24 STA $2400,Y 9715- C8 INY 9716- D0 F7 BNE $970F 9718- EE 11 97 INC $9711 971B- EE 14 97 INC $9714 971E- CA DEX 971F- D0 EE BNE $970F ; reboot to my work disk 9721- 4C 00 C5 JMP $C500 *BSAVE TRACE1,A$9600,L$124 *9600G ...reboots slot 6... ...reboots slot 5... ]BSAVE BOOT1,A$2400,L$400 ]CALL -151 (For the purposes of this write-up, let's assume that the code is really in its original location at $0400..$07FF instead of $2400..$27FF.) *400L ; just some initialization 0400- A6 2B LDX $2B ; $04AA is uninteresting (I checked) 0402- 20 AA 04 JSR $04AA 0405- A9 00 LDA #$00 0407- 99 78 02 STA $0278,Y 040A- 99 88 02 STA $0288,Y 040D- 8D 78 02 STA $0278 0410- A9 83 LDA #$83 0412- 85 76 STA $76 0414- A9 11 LDA #$11 0416- 85 80 STA $80 0418- A9 07 LDA #$07 041A- 85 81 STA $81 041C- 85 82 STA $82 ; don't know what this does yet 041E- 20 FE 05 JSR $05FE *5FEL ; $0446 is uninteresting (I checked) 05FE- 20 46 04 JSR $0446 0601- A6 2B LDX $2B 0603- 20 3B 06 JSR $063B 0606- C9 00 CMP #$00 ; hmm, a branch 0608- F0 2F BEQ $0639 ; The Badlands (code from which there ; is no return) 060A- A4 2B LDY $2B 060C- B9 88 C0 LDA $C088,Y 060F- A9 A0 LDA #$A0 0611- A2 00 LDX #$00 0613- 9D 00 08 STA $0800,X 0616- E8 INX 0617- D0 FA BNE $0613 0619- EE 15 06 INC $0615 061C- AC 15 06 LDY $0615 061F- C0 0C CPY #$0C 0621- D0 F0 BNE $0613 ; copy message to text page 2 0623- A0 00 LDY #$00 0625- B9 CA 06 LDA $06CA,Y 0628- 99 00 09 STA $0900,Y 062B- C8 INY 062C- C0 28 CPY #$28 062E- D0 F5 BNE $0625 ; show text page 2 0630- AD 51 C0 LDA $C051 0633- AD 55 C0 LDA $C055 ; infinite loop 0636- 4C 36 06 JMP $0636 OK, we definitely want to avoid THAT code. That means that we definitely DO want to take that BEQ branch from $0608 to $0639 (past The Badlands). And that means that the routine at $063B (called from $0603) is the copy protection. *63BL ; turning on the disk motor by hand -- ; always suspicious 063B- BD 89 C0 LDA $C089,X 063E- A9 56 LDA #$56 0640- 85 11 STA $11 0642- D0 01 BNE $0645 0644- D0 C6 BNE $060C ; um, what? 0646- 12 ??? 0647- F0 03 BEQ $064C 0649- D0 0A BNE $0655 064B- D0 C6 BNE $0613 064D- 11 D0 ORA ($D0),Y 064F- 05 A9 ORA $A9 0651- FF ??? 0652- D0 74 BNE $06C8 0654- D0 BD BNE $0613 0656- 8C C0 10 STY $10C0 0659- FB ??? 065A- D0 01 BNE $065D 065C- D0 C9 BNE $0627 065E- D5 F0 CMP $F0,X 0660- 03 ??? Oh, I see what's going on. Fake instructions and sneaky branches designed to confuse, well, people like me from doing, well, the exact thing I'm doing now -- deciphering this code and bypassing it. Take another look at the branch instruction at $0642. It goes to $0645, which is "in the middle" of the next instruction in the disassembly listing. That "BNE $060C" at $0644? Never happens. Execution never gets to $0644; it always goes from $0642 to $0645. Changing the byte at $0644 from "D0" to "EA" (NOP) will clean up the listing. (I had to do this several times at different locations.) The final result looks like this: 063B- BD 89 C0 LDA $C089,X 063E- A9 56 LDA #$56 0640- 85 11 STA $11 0642- D0 01 BNE $0645 0644- EA NOP 0645- C6 12 DEC $12 0647- F0 03 BEQ $064C 0649- D0 0A BNE $0655 064B- EA NOP 064C- C6 11 DEC $11 064E- D0 05 BNE $0655 0650- A9 FF LDA #$FF 0652- D0 74 BNE $06C8 0654- EA NOP 0655- BD 8C C0 LDA $C08C,X 0658- 10 FB BPL $0655 065A- D0 01 BNE $065D 065C- EA NOP 065D- C9 D5 CMP #$D5 065F- F0 03 BEQ $0664 0661- D0 E2 BNE $0645 0663- EA NOP 0664- BD 8C C0 LDA $C08C,X 0667- 10 FB BPL $0664 0669- D0 01 BNE $066C 066B- EA NOP 066C- C9 AA CMP #$AA 066E- F0 03 BEQ $0673 0670- D0 D3 BNE $0645 0672- EA NOP 0673- BD 8C C0 LDA $C08C,X 0676- 10 FB BPL $0673 0678- D0 01 BNE $067B 067A- EA NOP 067B- C9 96 CMP #$96 067D- F0 03 BEQ $0682 067F- D0 C4 BNE $0645 0681- EA NOP 0682- A0 0A LDY #$0A 0684- BD 8C C0 LDA $C08C,X 0687- 10 FB BPL $0684 0689- D0 01 BNE $068C 068B- EA NOP 068C- C9 FF CMP #$FF 068E- F0 03 BEQ $0693 0690- D0 B3 BNE $0645 0692- EA NOP 0693- F0 01 BEQ $0696 0695- EA NOP 0696- BD 8C C0 LDA $C08C,X 0699- C9 08 CMP #$08 069B- B0 A8 BCS $0645 069D- D0 01 BNE $06A0 069F- EA NOP 06A0- BD 8C C0 LDA $C08C,X 06A3- 10 FB BPL $06A0 06A5- D0 01 BNE $06A8 06A7- EA NOP 06A8- 85 10 STA $10 06AA- 88 DEY 06AB- D0 03 BNE $06B0 06AD- F0 10 BEQ $06BF 06AF- EA NOP 06B0- BD 8C C0 LDA $C08C,X 06B3- 10 FB BPL $06B0 06B5- D0 01 BNE $06B8 06B7- EA NOP 06B8- 45 10 EOR $10 06BA- D0 EC BNE $06A8 06BC- F0 EA BEQ $06A8 06BE- EA NOP 06BF- A5 10 LDA $10 06C1- 49 60 EOR #$60 06C3- D0 80 BNE $0645 06C5- F0 01 BEQ $06C8 06C7- EA NOP 06C8- 60 RTS Look ma, a nibble check. I'm shocked. (Not really.) More importantly, though, is what happens if the nibble check succeeds: nothing. Well, there's a zero in the accumulator, which is checked at $0606. But nothing else. No decryption loop based on raw nibbles, no storing secret values in zero page. Just enough for the BEQ check at $0606. I should be able to put an RTS at $0603 and bypass the entire copy protection. T00,S03,$03 change "20" to "60" Quod erat liberandum. --------------------------------------- A 4am crack No. 27 ------------------EOF------------------