ISSUE 66 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This month sees the first of a few "one-off" protection systems, which are those you'll only find on one particular game. The particular game needed for this month's HTH is MoonStrike by Mirrorsoft, which was protected by MovieLoad - perhaps the hardest protection system yet covered in this column. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The First Basic Bit Follow the usual procedure of *Loading and *Listing. MOONSTRIKE LINE 0 LEN 395 0 REM 1 PAPER 0: INK 0: POKE 23624,70: CLEAR 27013: PRINT #0;" PLEASE DO NOT BE ALARM ED BY "''"ANYTHING STRANGE THAT MAY OR MAY"''" NOT HAPPEN. THIS IS A PRODUCT "' '" OF A DERANGED IMAGINATION."'" ";#2;AT 8,0;: RANDOMIZE USR 23760: LOAD "" That USR 23760 loads the headerless block that follows and does the bit of funky animation (pretty, isn't it?). The only thing you need to worry about in all the code loaded so far is the LOAD "" at the end, which loads the second bit of basic. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Loading The Second Bit First of all, try doing a standard *Load. It'll load the header, then return back to basic with an error. The reason for this is that the filename is taken up by strange control characters, which stop anything being printed after them (like the LINE and LEN messages). To overcome this, take a look in the *Load code for a 215 (there's only one), and replace it with a 0. This stops the routine printing the filename, so it only prints the start line and length of the basic block. Now try it again. LINE 0 LEN 2410 You can now *List in the usual way. 0 ,X POKE 23614.081,PEEK 23627.319: POKE 23613.433,PEEK 23627.679: POKE 23624 .2,PEEK 23605.71: POKE 23692.669,PEEK 23624.011: PRINT "NASTYLOAD": RANDOMIZE US R 2.8881517E+34^ IF YOU ENJOY DIFFICULT TASKS, ATTEMPTING TO HACK THIS PROGRAM WILL ELECTROCUTE YOUR PLEASURE CENTRES-1.3412728E+30R"AT ASCREEN$ CLEAR -1.0578 132E-19<; OR CHR$ lATN FOR SCR..... |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Don't be put out by that weird code at the start, it doesn't actually do anything. This basic starts the machine code in a similar way to Speedlock 1 - it sets a specific value for ERRSP (with the POKE 23613 and 23614's) then creates an error with that dodgy USR call. But what has ERRSP been set to? Try PRINT PEEK 23627. Now try it again. Spot the difference? That's because Basic has been told, by a dodgy header, that the program is longer than it actually is, with the result being that trying to find out values to do with the basic program are impossible. Hmmmmm. The way to overcome this is to type directly, RANDOMIZE USR 3E4: RANDOMIZE USR DIS where "dis" is replaced by the address of your disassembler. When you enter the disassembler, you are no longer affecting Basic, so you can find the values of 23627 and 23628 (5C4B and 5C4C hex). Bear in mind that you want the value of PEEK 23628+256*PEEK 23627 (ie the MSB becomes the LSB and vice versa) because of the POKEs in the Basic program. PEEK 23627 is 5D and PEEK 23628 is E5, so ERRSP is set to 5DE5. PEEK 5DE5 is 73 and PEEK 5DE6 is 5D, so the return address is 5D73. Now, in a similar way to cracking the basic in Speedlock 1, you need to put a breakpoint in at 5D73, then GOTO 0 so that the registers have their correct values. Unfortunately, you can't. Not directly, anyway, because as soon as you type something in in Basic, all the values of the all-important system variables (particularly VARS at 23627 and 23628) go crazy. What you need to do is load the basic as a headerless file to 8CCB (ie LD IX with #8CCB and DE with 2410), then return to your disassembler and put a breakpoint at 8D73. Now resave this new block of basic as a headerless file (use the same routine as a headerless load but the call is to #04C2, not #0556). Now load the header from the original basic, then, when it's loaded ("Program:" on the screen), stop the tape and load in your new basic. It will load and control will pass to the disassembler. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Making A Start Now that the basic's been cracked, we can start on the machine code. The all-important register values you should have at this point are: A'=7E BC'=0008 DE'=5D49 HL'=663B A=D1 BC=0D4E DE=4EF4 HL=663B IX=6635 IY=5C3A SP=5DE9 A lot of the ideas in this protection system were nicked from Speedlock 1 (as you may have noticed by now). 5D73, where the machine code starts, is the middle of a message. There is a lot of useless crap in this loader, but it is all executed, and you need to know the register values at the end of it because they're decrypted with. 5D73 DEFM "ICULT.TASKS,.ATTEMPTING.TO.HACK.THIS.PROGRAM.WILL.ELECTROCUTE.YOUR.PL EASURE.CENTRES" 5DC6 LD L,80 5DC8 ADC A,A 5DC9 LD SP,#1F40 5DCC LD E,L 5DCD LD IXL,#41 5DD0 DI 5DD1 LD R,A 5DD3 DEFB #FD 5DD4 LD B,#8D 5DD6 LD E,#40 5DD8 LD IYL,#22 5DDB LD HL,#F81D 5DDE LD IXH,#16 5DE1 JR NZ,#5DE7 5DE7 DJNZ #5DE7 5DE9 LD BC,#07C4 5DEC LD D,#F9 5DEE DEC IXH 5DF0 LD A,B 5DF1 EXX 5DF2 LD B,A 5DF3 LD H,#5E 5DF5 LD E,A 5DF6 LD C,#E5 5DF8 ADD A,A 5DF9 LD L,A 5DFA LD D,#F8 5DFC LD D,D So far, all the code has been crap. But it's been crap which has altered the registers. The decrypter which follows uses the new values for HL, DE and BC, which are 5E0E, F807 and 07E5 respectively. Your value for R (which you have to keep track of) should be 82. 5DFD LD A,(HL) 5DFE XOR H 5DFF SUB B 5E00 RLCA 5E01 XOR D 5E02 ADC A,C 5E03 LD IYL,#22 5E06 LD (HL),A 5E07 LDI 5E09 LD IYH,#23 5E0C CALL PE,#5DFD Note that this decrypter changes it's last byte, and note also that, at the end of it, the stack is in the ROM. The easy way out is to move it somewhere and, after the necessary code to keep track of R, do something along the lines of LD (#6000),SP: LD SP,7000: 5E0F EXX 5E10 CALL NZ,#F815 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
For this decrypter, HL should be F81D and BC should be 07C4. These are the only two values obviously necessary at this stage, but afterwards, SP should be FFF0 and R should be DF. F815 LD A,#1F F817 RRD F819 CPI F81B CALL PE,#F817 F81E DEC E F81F JR NZ,#F829 F829 EXX F82A LD HL,#5900 F82D LD DE,#5901 F830 LD BC,#9F26 F833 LD (HL),L F834 LDIR Rip this LDIR out by POKEing F82E with 0 (so that HL=DE). Afterwards, simply add one to the value in DE. F836 EX DE,HL F837 LD D,(HL) F838 DEC D F839 INC HL F83A LD E,(HL) F83B RRC HL F83D EX DE,HL F83E LD C,#19 F840 LDIR F842 EXX F843 DEFM "#25-.IF.YOU.DON'T.STOP.HACKING.INTO.MY.SACRED.PROTECTION.SYSTEM,.I.WI LL.GET.A.LARGE.AXE.AND.GIVE.YOU.A.HACKING.YOU.WILL.NEVER.FORGET.!.." F8CB DEC B F8CC RLC B F8CE DEC B F8CF LD A,E F8D0 LD E,B F8D1 AND #36 F8D3 LD B,A F8D4 LD A,H F8D5 SUB B F8D6 LD D,A F8D7 LD A,L F8D8 SUB B F8D9 LD H,D F8DA DEC A F8DB LD C,A F8DC LD L,B F8DD DEC L Now there follows the third decrypter. The values needed are HL=F905 DE=F93F BC=06DC R=85 F8DE RLC (HL) F8E0 RLC (HL) F8E2 RLC (HL) F8E4 RLC (HL) F8E6 RLC (HL) F8E8 LD A,C F8E9 ADD A,(HL) F8EA XOR L F8EB LD (HL),A F8EC LD A,R F8EE ADD A,(HL) F8EF RLCA F8F0 XOR B F8F1 LD (HL),A F8F2 RRD F8F4 LD A,(HL) F8F5 RRA F8F6 JR C,#F8F5 F8F8 AND #07 F8FA INC A F8FB DEC A F8FC INC A F8FD DEC A F8FE JR NZ,#F8FB F900 LD A,B F901 CPI F903 OR C F904 JR NZ,#F8E4 F906 LD A,(DE) F907 EX (SP),HL F908 LD H,A F909 RRCA F90A INC DE F90B LD L,A F90C LD A,(DE) F90D EXX F90E ADD A,(HL) F90F EXX F910 SUB L F911 LD L,A F912 EX (SP),HL F913 INC SP F914 INC SP F915 INC DE F916 EX (SP),HL F917 EX DE,HL F918 XOR (HL) F919 RLCA F91A INC HL F91B SUB (HL) F91C LD D,A F91D INC HL F91E RLCA F91F XOR (HL) F920 LD E,A F921 INC HL F922 EX DE,HL F923 EX (SP),HL F924 EX DE,HL F925 ADD A,(HL) F926 LD B,A F927 INC HL F928 RRCA F929 SUB (HL) F92A RRCA F92B LD L,A F92C LD H,B F92D RLCA F92E DJNZ #F92D F930 EX DE,HL F931 EXX F932 DEC (HL) F933 INC HL F934 RLC (HL) F936 INC HL F937 RRC (HL) F939 INC HL F93A DEC (HL) F93B EXX F93C JP #FF50 FF50 INC B FF51 RL H FF53 ADD HL,DE FF54 LD A,(DE) FF55 XOR (HL) FF56 ADD A,B FF57 DEFM "#24-.GO.AWAY.BEFORE.I.GET.REALLY.NASTY.!" FF7D LD D,#21 FF7F DEC B FF80 RRCA FF81 LD C,A FF82 LD A,D FF83 ADC A,H FF84 RR B FF86 LD E,B FF87 LD H,A FF88 SBC L FF89 RRA FF8A LD L,A FF8B AND #8F FF8D LD B,A FF8E SBC H FF8F NEG FF91 LD C,A FF92 CCF FF93 RRA FF94 ADC A,D FF95 LD D,C FF96 INC D FF97 LD C,A For this next decrypter, HL=F946 DE=F47F BC=69B R=8F The address at (SP) is FA51 and that at (SP-2) is FF98. To crack it, simply change the address at (SP), ie (FFF2) and (FFF3) to something convenient. This is the RET PO address, which is RETed to on completion of the decrypter. Otherwise, FF98 (from SP-2) is RETed to and another byte is decrypted. This is similar in principle to the recent Speedlock decrypter, which had a RET PO to jump out. FF98 LD A,(HL) FF99 EX DE,HL FF9A LD (HL),A FF9B RLC (HL) FF9D DEC (HL) FF9E RLC (HL) FFA0 RLC (HL) FFA2 LD A,R FFA4 SUB (HL) FFA5 LD (HL),A FFA6 RRD FFA8 AND B FFA9 RRA FFAA JR C,#FFA9 FFAC AND #0E FFAE DEC A FFAF DEC A FFB0 JR NZ,#FFAE FFB2 CPI FFB4 INC DE FFB5 EX DE,HL FFB6 RET PO FFB7 DEC SP FFB8 DEC SP FFB9 RET PE FA51 EXX FA52 LD DE,#0000 FA55 LD HL,#FA84 FA58 LD BC,#0589 FA5B LDDR FABD LDD FABF RET PO FAC0 LD H,#18 FAC2 LD DE,#FFF2 FAC5 LD B,#00 FAC7 LDDR FAC9 POP HL FACA POP DE FACB LD BC,#001E FACE LDIR FAD0 LDD FAD2 EXX FAD3 RET PE F9D9 LD A,(BC) F9DA LD B,A F9DB RLCA F9DC SBC HL,BC F9DE NEG F9E0 INC A F9E1 RRA F9E2 ADD A,B F9E3 DEFM "#23-.GO.AHEAD,.MAKE.MY.DAY" F9FD JR NZ,#FA00 FA00 RRCA FA01 DEC A FA02 LD C,A FA03 LD A,B FA04 RRA FA05 ADC A,H FA06 INC A FA07 INC A FA08 LD L,A FA09 AND #83 FA0B INC SP FA0C ADC A,L FA0D LD E,A FA0E LD A,D FA0F SBC #08 FA11 LD D,A FA12 INC A FA13 LD H,A FA14 CPL FA15 RRA FA16 LD B,A FA17 INC SP This decrypter uses values HL=F47F, DE=F382, BC=055A, R=8C. The RET PO should be to FA34 (which you should change to retain control) and the RET PE should be to FA18 (to loop back and do the next byte). FA18 LD A,R FA1A RRC (HL) FA1C INC (HL) FA1D RRC (HL) FA1F INC A FA20 SUB (HL) FA21 LD (HL),A FA22 AND A FA23 RLA FA24 JR C,#FA23 FA26 OR #E0 FA28 INC A FA29 JR NZ,#FA28 FA2B LDI FA2D RET PO FA2E DEC SP FA2F DEC SP FA30 RET PE FA34 DEC E FA35 JR NC,#FA39 FA39 LD A,D FA3A JR NZ,#FA3E FA3E RRA FA3F JR #FA43 FA43 LD D,E FA44 JR NC,#FA48 FA48 LD E,A FA49 JR NZ,#FA4C FA4C DEC E FA4D DEC H FA4E RET NZ F382 SBC HL,DE F384 LD A,#01 F386 RLCA F387 RRA F388 DEFM "#22-.I'M.NOT.GETTING.YOU.DOWN,.AM.I?.I.WOULD.HATE.TO.THINK.I.WAS.GETT ING.YOU.DOWN..." F3DC RL H F3DE RL H F3E0 RL H F3E2 RR B F3E4 DEC B F3E5 DEC B F3E6 LD A,H F3E7 ADC A,B F3E8 LD H,A F3E9 DEC H F3EA CPL F3EB INC A F3EC LD L,A F3ED LD D,H F3EE LD E,#08 F3F0 LD A,#D1 F3F2 LD C,A F3F3 XOR #BF F3F5 AND #95 F3F7 LD B,A F3F8 PUSH DE You're now dangerously close to cracking MovieLoad! HL=F40B DE=F408 BC=04D1 R=D3 The RET PO is to F408. F3F9 LD A,R F3FB RLC (HL) F3FD ADD A,(HL) F3FE LD (HL),A F3FF AND A F400 RRA F401 JR C,#F400 F403 LDI F405 RET PO F406 JR #F3F9 F408 EXX F409 IN A,(#1F) F40B LD L,A F40C DEC SP F40D DEC SP F40E POP DE F40F IN A,(#FB) F411 LD H,A F412 DEC E F413 JR NZ,#F40F F415 INC E F416 IN A,(#EF) F418 INC D F419 JR NZ,#F40F F41B LD E,A F41C IN A,(#F7) F41E LD D,A F41F LD A,I F421 LD C,A F422 EXX F423 LD HL,#F8AD F426 PUSH HL F427 LD HL,#C8CA F42A LD DE,#C8CB F42D LD BC,#2B67 F430 LDIR F432 RET F8AD CALL #F694 F8B0 PUSH IX F8B2 POP HL F8B3 LD A,(HL) F8B4 INC HL F8B5 XOR (HL) F8B6 INC HL F8B7 LD E,A F8B8 RLCA F8B9 RLCA F8BA XOR (HL) F8BB LD D,A F8BC DEC SP F8BD DEC SP F8BE POP HL F8BF SBC HL,DE F8C1 JP NZ,#F5D3 F8C4 PUSH HL F8C5 POP IX F8C7 CALL #F694 F8CA LD DE,#30DA F8CD ADD IX,DE F8CF LD E,(HL) F8D0 INC HL F8D1 LD D,(HL) F8D2 LD A,#01 F8D4 OUT (#FE),A F8D6 JP #F8A1 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
As could perhaps be expected, the JP at F8D6 is to the game. Change it to 65000ish to bung your pokes in.
|