ISSUE 62 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
INTRO? WHAT INTRO? (continuation of issue 61) SPEEDLOCK 4 This is where identification starts getting difficult. All the following Speedlocks look exactly the same when loading, and you only know what version you are doing when you start getting into it. All I can safely tell you is that the original releases of Firefly, Rastan, Gutz, Star Paws, Arkanoid II and Target Renegade had Speedlock 4 on them (although rereleases may be different). I'll be doing Arkanoid II as an example. First off, *Load and *List as usual. ARKANOIDII LINE 0 LEN 3452 0 RANDOMIZE USR ((PEEK 23635+256*PEEK 23636)+59) 62241X COPY u GO SUB VAL CODE OPEN ..... |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The basic loader has only one basic command, a simple RANDOMIZE USR command. The whole of the rest of the basic is taken up by decrypters, and a few hundred bytes for the loader itself. The USR command starts running code from 5D06. 5D06 DI 5D07 LD HL,5800 5D0A LD DE,5801 5D0D LD BC,03FF 5D10 LD (HL),L 5D11 LDIR 5D13 XOR A 5D14 OUT (FE),A 5D16 LD HL,(5C53) 5D19 LD DE,005C 5D1C ADD HL,DE 5D1D LD BC,0D1F 5D20 LD DE,F1C9 5D23 PUSH DE 5D24 LDIR 5D26 RET Firstly, this disables interrupts (the DI at 5D06) which stops R getting corrupted. 5D07-5D12 makes the screen black, 5D13-5D15 makes the border black, then HL is set to the start of basic, has 5C added to it (so it points to the start of Speedlock), and is moved to F1C9, then RET'd to. It RETs to F1C9... F1C9 LD A,2B F1CB LD R,A F1CD LD DE,F1CF F1D0 LD HL,F1D0 F1D3 LD BC,0064 F1D6 LDDR F1D8 LD BC,0CFA F1DB LD SP,FEE6 F1DE POP DE F1DF LD A,R F1E1 XOR D F1E2 LD D,A F1E3 PUSH DE F1E4 DEC BC F1E5 LD A,C F1E6 DEC SP F1E7 OR B F1E8 JP NZ,F1DE F1EB JP F1EE F1C9-F1CC sets R to 2B, so make sure you keep track of R at all times. Move F1C9-F1EA to somewhere convenient, change the F1DE to the address of the POP DE in this new copy, and on the end stick a LD A,R: breakpoint. Now you can execute it. The value returned in A is two more than the value of R (the LD A,R instruction itself increments R by 2) so subtract 2 from it. Now add 1 to it, because we are not going to be executing the JP F1EE at F1EB, because the decrypter at F1EE is going to be moved somewhere convenient and executed from there. F1EE LD DE,0CE9 F1F1 LD HL,F1FF F1F4 DEC (HL) F1F5 DEC DE F1F6 LD A,D F1F7 INC HL F1F8 OR E F1F9 JP NZ,F1F4 F1FC JP F1FF You crack this in a similar way to the way you cracked the last decrypter, by moving F1EE-F1FB to somewhere convenient and ending with LD A,R: breakpoint. However, you will need to put in the value of R from the end of the last decrypter, which is 36 hex, so start it with LD A,37: LD R,A and execute it (I added 1 to it because we are not executing the JP F1EE). Afterwards, R will be 31, which is actually 2F after you subtract the 2 from it. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Never-Ending Story That's what you'll think when you go through this Speedlock (and the ones that follow) - they seem to go on forever. Just carry on as you have been doing, until you get bored with it. By now you should have noticed that there are five different types of decrypter, with one thing in common. The last instruction executed by them is a JP. We can use this fact to write a very compact hack for the game. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The CPIR Command We are going to use this command in our hack to find that C3 at the end of the decrypter. You use it as follows: LD HL, first byte to search LD BC,amount of bytes to search LD A,number to search for CPIR Afterwards, a JP Z will JP if the byte is found, and HL points to the address AFTER the address of the required number. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
The ARKY II Hack How does this work? Firstly, it loads the basic loader to where it would be after it has been moved to the top of memory. Then it checks for the LDDR command, and goes past the start of each decrypter to the actual loop itself, the reason being that we are going to look for a C3 (code for the JP command), which could be a part of one of those numbers. Having found one, by using the CPIR command explained above, it changes the address it JPs to so that control is returned to our routine, rather than the next decrypter. Then it does exactly the same thing over and over, until it doesn't find a C3, in which case it's finished and we can patch the loading system in the usual way. Note that once a C3 is found, it goes back three bytes to look for a JP Z. One of the different types JPs to the new decrypter by saying "if finished, JP to the next one" rather than "finish this one then JP"
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Next month I'll be doing Speedlocks 5-7, so stay tuned and, more importantly, keep hacking. The address for any ideas, probs or unwanted +3's is Jon North, The Hacking Bit, YS, 30 Monmouth Street, Bath, Avon BA1 2BW. No SAE, no reply. T'ra for now... |