How to Hack, by Jon North

At the end of 1990, Jon North - well-known for his hacking work in all three major
Spectrum magazines - started to write a series of articles describing How To Hack
in detail.

 

 

These articles were to be published in Your Sinclair starting at issue 54 or 55.

  • Issue 54 or 55 discusses the basics of hacking and tells how to find infinite lives pokes.
  • Issue 56 goes a bit further, giving a set of tools that are needed to hack special loaders. It also shows how headerless blocks are done.
  • Issue 57 tells you what a decrypter is.
  • Issue 58 shows you how to hack BleepLoad.
    • The first stage
    • The basic bit
    • The loader (the juicy bit)

  • Issue 59 continues on BleepLoad.
    • The BleepLoad crack
    • The stack
    • The Red LED hack

  • Issue 60 is a Q&A session.

  • Issue 61 is the beginning of the huge Christmas special showing how to hack Speedlock.
    • Speedlock 1
      • The small basic bit
      • The big basic bit
      • PO and PE
      • What a load of crap!
      • Changes, changes
      • Setting the table
      • The Army Moves hack
    • Speedlock 2
      • The basic bit
      • Six of one...
      • Where'd the loader go?
      • Moving around
      • The Athena hack
    • Speedlock 3
      • ...And half a dozen of the other
      • Moving Speedlock 3

  • Issue 62 is the continuation of the special
    • Speedlock 4
      • Never-ending story
      • The CPIR command
      • The Arky II hack

  • Issue 63 handles Speedlock 5 through 7
    • Getting started
    • The decrypters
    • Final decrypter on Speedlock 7
    • The hack: Speedlock 5-7

  • Issue 64 shows you how to hack SoftLock
    • The basic bit
    • The Chimera hack

  • Issue 65 is another Q&A session
    • Is your * key stuck?
    • Where's the game?
    • Will Steve Adams please stand up?
    • Why not do a machine code course?
    • How are load and save routines related?
    • How are encrypters and decrypters related?
    • How do you do Speedlock 4?

  • Issue 66 rips MovieLoad apart
    • The first basic bit
    • Loading the second bit
    • Making a start

  • Issue 67 handles the Search Loader trick
    • Getting started
    • Decrypting the game
    • The Rana Rama hack

  • Issue 68 is unfortunately the last part...


You'll probably want to check the Z80instructions.html"> Z80 Instruction Information for the exact timing of instructions if you're interested in the loaders themselves.

Issue 54 or Issue 55

 

After about five years of hacking for all three Speccy mags, I have decided to tell the world exactly what to do and how to do it - and it's been causing quite a stir amongst hacking circles! Over the next few months I'll be showing how to hack infinite lives and energy out of games, and how to crack just about every protection system ever written. You won't need an in-depth knowledge of machine code, and everything you will need will be handed to you on a plate. I'll be concentrating mainly on old YS Covertapes, so you won't need to shell out too much on new games. Anyway, enough of the waffle and on with the show...


What You'll Need
First and foremost, you'll need a disassembler, preferably one that you can load anywhere. HiSoft's Devpac springs to mind. If you want to find pokes for protected games before I've gone through the protection system, you'll also need a Multiface with Genie. Finally, and most importantly, you'll need time, determination and patience. You won't find pokes within a second of looking for them - not yet anyway.

How To Hack
There are three ways of hacking out an infinite lives poke - working forwards, working backwards and not working at all(!).

WORKING FORWARDS
First of all, find the number of lives you get (say, 5). Your disassembler should have a "find" or "search" option, so use that. Now look in the code for 3E 05 32 (where 05 is the number of lives). This is hex for the machine code instruction LD A,05 which is the same as the Basic command LET a=5. The 32 is the code for instruction LD (address),A. The brackets signify PEEK, so this instruction is the same as Basic's POKE address,a. Write down all the addresses you find. Now do the same, but using lives+1 and lives-1, for example if you have 5 lives, look for 3E 04 32 and 3E 06 32.

Now for the trial and error part - the most time-consuming. This is where you'll ideally need a Multiface. POKE each value of 5 you've found, one by one, with a different value, say 2 or 3. Eventually you'll find the one that gives you 2 or 3 lives. If you don't have any success, try repeating this whole procedure, but this time looking for number of lives + or - 1, ie search for 4 and 6.

You've just found the number of lives POKE. Make a note of the address it's put into. For instance, if the instruction after LD A,05 was LD (5B3A),A then the address you need to know is 5B3A. This is called the "lives store", and is what you need to look for next.

Search for 21 address or 3A address. Note that address should be entered with the second two digits, then the first two. In this example, search for 21 3A 5B or 3A 3A 5B. Note down every value you find, then disassemble them. For every 21 you check, the instruction you want to find is DEC (HL). DEC implies "subtract 1", and "(HL)" signifies PEEK HL, ie POKE HL,PEEK HL-1. Note the addresses of every one you find. Similarly, when you check 3A, look for DEC A and SUB n, where n is a number between 1 and 255 (usually between 1 and 20). 3A is code for LD A,(address). After the DEC A or SUB n you should find LD (address),A where the address is the lives store. If not, you can ignore the DEC or SUB because they have no effect. If you find several of DEC A, DEC (HL) or SUB n instructions, note them all. They will be for loss of life at different points in the game, for instance one may be for level 1 and another for level 2. Now for the good bit - POKE all the addresses you've written down for DEC (HL) or DEC A with 0. POKE any SUB n's you've found to read SUB 0 (POKE the address after the SUB instruction), then play the game. Infinite lives should be yours. Note that when you try the game with the POKEs in place, you may get just one life before the "Game Over" message. If this happens, just replace all the POKEs with 182 for DEC (HL) and 183 for DEC A. This is code for OR (HL) and OR A. I'm not sure why this happens, but it is not important.

Example: A Nightmare on Robinson Street
You get 50 life points at the start of the game. Search for 32 32 3A. There are two, one at C2E1 and the other at C322. The one at C322 does nothing, the other gives 'x' amount of life points. The instruction after the one at C2E1 is LD (D310),A so you know that the lives are stored at D310. Now look for 3A 10 D3. There are four - at C3B0, D00D, D3E6 and DB47. The code at C3B0 reads:

LD   A,(D310)    (A is the value in the lives store)  CP   0           (Compare with 0)  JP   Z,DE4B      (If it is, Jump to address DE4B. This is the same as GOTO)  
There are no DEC A's here, so ignore it. The code at DOOD reads:
LD   A,(D310)    (A is the value in the lives store)  CP   0           (Compare with 0)  RET  Z           (RETurn if it is. This is the same as RETURN in Basic)  DEC  A           (Aha!)  LD   (D310),A    (Put the new value back in the lives store)  RET              (And return)  
You should POKE this DEC A with 0. The address is D013. The code at D3E6:
LD   A,(D310)    (A is the value in the lives store)  LD   E,0A        (LET e=10)  LD   D,30        (LET d=48)  SUB  E           (LET a=a-e)  JR   C,D3F4      (Jump forward if less than 0)  INC  D           (LET d=d+1)  JP   D3ED        (GOTO address D3ED)  
This does nothing. Although there is a SUB E here, it is not put back into the lives store and can be ignored. The code at DB47:
LD   A,(D310)    (A is the value in the lives store)  SUB  4           (SUBtract 4)  LD   (D310),A    (Put the new value back in the lives store)  JP   NC,DB37     (Jump to DB37 if greater than 0)  XOR  A           (Otherwise A=0)  LD   (D310),A    (Put 0 in the lives store)  JP   DB37        (And jump to DB37)  
The SUB 4 should be POKEd to read SUB 0. The SUB instruction is at DB4A, but the 4, which you want to change, is one after this, ie DB4B.

So for infinite lives, POKE D013,0 and POKE DB4B,0


WORKING BACKWARDS
This is known as "backtracking". You work backwards from the Game Over message to find infinite lives. To start with, find the message you get after you lose your last life, like "Game Over" or "GAME OVER" or "You're Dead" etc. Now convert each letter into it's ASCII value and search for the first, say, 5 or 6. Don't search for the last one, because this sometimes has a different value, to tell the printing routine that it is the last letter. If the message is "GAME OVER", the values you search for are 47 41 4D 45 20 4F 56. This will search for GAME OV which can only be the Game Over message, and so will only appear once. If you can't find it, forget any ideas about backtracking for that game - the text will be encrypted and will take lots of knowledge and time to find.

If you do find it, you now search for the address it appears at - if the address is ED47, say, search for 47 ED. If nothing comes up, try going one or two back from this, ie 46 ED or 45 ED. There may be some special characters at the start of the message, like the PRINT AT coordinates, or the ink colour. Go back up to about 5 or 6 bytes away.

Now check the values before each occurance of the address. The values you are looking for are 01, 11 and 21, which are LD HL,address; LD DE,address and LD BC,address. This is the routine that prints the message on the screen. If the address occurs several times, there should only be one occurance that prints it. If there are more, write them all down and treat them seperately.

Go back about 30 or 40 bytes from each LD BC/DE/HL you find and look for the start of the Game Over routine. You are looking for JP, JR and RET instructions. The address after these should be the start of the routine. If you don't find one, go back even further.

When you know the start of the routine, look for that address in the same way as you looked for the address of the message. Write down every address it occurs at. Now check the byte before the occurance - you are looking for JP (perhaps with a Z,NZ,C,NC after it) or a CALL (again with the same letters after it, perhaps). For each one you find, go back about 10 bytes and have a look. Somewhere you should find a LD A,(address). The address will be the lives store, and you can search for infinite lives in exactly the same way as you did by going forwards.

Example: A Nightmare on Robinson Street
The message is GAME OVER, so search for 47 41 4D 45 20 4F 56. This occurs at DF8D. Now look for 8D DF. Nothing useful appears, but when you search for 8C DF there is a LD DE at DE53. Go back about 10 bytes and the start of the routine can be seen to be DE4B. Now look for 4B DE; there is a JP Z at C3B5. Go back about 10 bytes and you will see LD A,(D310) so you know that D310 is the lives store. You can now look for infinite lives as described above.


NOT WORKING AT ALL
This is the ultimate cheat - hacking without hacking. You will need a Multiface with Genie or something similar, and a game where you can press the button while you are actually dying - perhaps when the screen flashes or a bleep bleeps. This is the first step - press the button AS you die. Timing is critical, because if you are too fast or too slow, you will not find out what you need to.

When you break into the game, look at the address of SP - one of the Z80 registers (like Basic variables). Examine the address and write down the value there and for the next, say, 10 bytes. Check the contents of the address given by the first two bytes at SP, for instance, if they are A3 B5 then disassemble B5A3. Look for the start of the routine, and backtrack from it as described above.

Example: Moley Christmas
When you lose all your energy, the energy icon flashes for about a second. Press the button while it is flashing. Your values may be slightly different from mine, but when I did it, the value of SP was 5DF8. At this address were the following values: F1 A2 9A 1D 49 92. Disassemble A2F1, you will see:
POP  BC  DJNZ A2D8  RET  
Because of the RET I know I am towards the end of the routine, so go back a bit, say to A2D0. Here we see:
RET  LD   IY,5C3A  
So I know where the start of the routine is - A2D1. The RET is the end of the previous routine. Now search for D1 A2. There is only one, at 9247. Go back from here, say to 9230:
SET  2,(HL)  LD   A,(HL)  RET  LD   (95E2),SP  CALL 9EA0  LD   IX,8125  LD   A,(810D)  OR   A  JP   P,925B  CALL A2D1  
etc. The address it checks before it ends up at the flashing energy bar routine is 810D, so this will be the energy store. Search for 0D 81, there are four - at 8543, 855F,876E and 9240.
8542:  LD   HL,810D  DEC  (HL)  RET  M  JP   876D  
POKE the DEC (HL) with 0 (at 8545).
855E: LD   (810D),A  
There are no DECs here, so you can ignore it.
876E:  LD   A,(810D)  AND  F0  ADD  A,A  LD   L,A  LD   H,0  ADD  HL,HL  
etc. There are no DECs here, either. Hence, for infinite energy simply POKE 8545,0.


Well, that lot should keep you out of trouble for a month or two. From next month on, I'll be dealing with loading systems. Next month I'll cover headerless loaders, easy turboloaders, decryption and Firebird Bleepload - and I'll show you how I went about writing the Multipoke. In the meantime, if you've got any questions, write to Jon North, How-2-Hack, YS, 30 Monmouth Street, Bath, Avon BA1 2AP. Remember - if it loads, hack it!

 

Issue 56

For the last couple of months, I've been showing you how to hack infinite lives out of games. From now on, I'll be concentrating on showing you how to crack the protection systems, so that you'll be writitng Multipokes before you know it.


Revenge Of The Mutant Cock-Ups From Hell
In the first How-2-Hack, to find number of lives, search the code for 3E nn 32, not 3E nn 3D or 3A nn 32. Sorry about that (ahem).


LOADING THE FIRST BIT
The first program on any game tape is called the loader - because it loads the rest of the program (logical, huh?). To crack any protection system, however simple, you need to keep track of what it's doing at all times.

The *LOAD Routine
This program is a special loading routine. Instead of typing LOAD "" to load the loader, type RANDOMIZE USR 30000. This will load the basic program and stop with the OK message. When it loads, it displays the filename, the start line of the program (this is usually 0,1 or 10) and it's length.

listing 1

10 REM *Load by Jon North  20 LET t=0  30 FOR f=3e4 to 30083  40 READ a: POKE f,a  50 LET t=t+(f-29990)*a: NEXT f  60 IF t<>544506 THEN STOP  70 PRINT "Data O.K.": STOP  80 DATA 221,33,0,80,17  90 DATA 17,0,175,55,205  100 DATA 86,5,48,240,221  110 DATA 126,239,183,32,236  120 DATA 62,2,205,1,22  130 DATA 33,1,80,6,10  140 DATA 126,215,35,16,251  150 DATA 62,202,215,221,70  160 DATA 253,221,78,252,205  170 DATA 43,45,205,227,45  180 DATA 221,54,253,255,62  190 DATA 32,215,62,177,215  200 DATA 221,70,251,221,78  210 DATA 250,205,43,45,205  220 DATA 227,45,62,13,215  230 DATA 42,83,92,221,46  240 DATA 0,195,115,8  


DISGUISING BASIC AND GETTING PAST IT
Unfortunately, what you see and what you get with basic programs are not always the same thing. Type in this one line and RUN it:
10 PRINT 10  
Surprise surprise, 10 comes up on the screen. Now type in directly, LET A=PEEK 23635+256*PEEK 23636: POKE A+5,50. If you now list the program, it will read 10 PRINT 20, but if you run it, it still prints 10. Every time a number is put in a program, two copies of it are stored. The first is what is listed, the second it what is actually used.

The *LIST Program
This routine is a special list routine. Use RANDOMIZE USR 30085 instead of LIST to use it. What it does is show you the program as it would be run, that is, it strips away all the disguises and reveals the true program.

listing 2
10 REM *List by Jon North  20 LET t=0  30 FOR f=30085 TO 30200  40 READ a: POKE f,a  50 LET t=t+(f-30075)*a: NEXT f  60 IF t<>919527 THEN STOP  70 PRINT "Data O.K.": STOP  80 DATA 62,2,205,1,22  90 DATA 42,83,92,229,237  100 DATA 91,75,92,55,63  110 DATA 237,82,124,181,225  120 DATA 200,70,35,78,35  130 DATA 229,205,43,45,205  140 DATA 227,45,225,78,35  150 DATA 70,35,229,9,34  160 DATA 254,255,225,126,254  170 DATA 13,32,4,35,215  180 DATA 24,212,254,46,40  190 DATA 8,254,58,48,19  200 DATA 254,48,56,15,68  210 DATA 62,14,237,177,205  220 DATA 180,51,229,205,227  230 DATA 45,225,24,220,254  240 DATA 32,56,2,215,126  250 DATA 254,234,32,8,62  260 DATA 13,215,42,254,255  270 DATA 24,167,254,34,32  280 DATA 12,35,126,254,32  290 DATA 56,2,215,126,254  300 DATA 34,32,244,35,24  310 DATA 183  


HEADERLESS FILES
This is probably the simplest form of protection you can get. When a block of data loads, it comes in two chunks - a short one, which holds things like the filename and the length of the block, then the block itself. This first short bit is called the header, and the idea of headerless files is, surprise surprise, to be able to do without this header. It does this by holding all the information needed about the block (namely where to load it to and its length) in a machine code program, which uses this information to load the file.

What A Headerless Loader Looks Like
To load a headerless block, a short bit of code is needed:
LD   IX, start address  LD   DE, length of block  LD   A,FF  SCF  CALL 0556  RET or JP  
That's it! If you look at most of my more complex hacks, you'll see they start off with 221,33,n,n,17,n,n,62,255,55,205,86,5,48,241; this is the code to load the basic program as a headerless file (because it can't be MERGEd).

Example: Falcon Patrol II
When you *Load the basic, you'll see:
FP2     LINE 99 LEN 800  
You now know that the program starts from line 99. When it's loaded, *List it:
99 CLEAR 65367: RANDOMIZE USR (PEEK 23637+256*PEEK 23638)+5  100 REM  
To find out the value of the RANDOMIZE USR, find the address of the actual commands (use the TEXT feature of your dissassembler, or search for bytes F9 C0) and change it to PRINT ie F5 20. Now RUN the basic and it will display the value of the USR command. Your value may be different to mine, but I got 23825, which is 5D11 hex. Dissassemble this address:
LD   HL,000F  LD   DE,F000  ADD  HL,BC  LD   BC,256  LDIR  JP   F000  
Taking this line by line: HL=15,DE=61440. Whenever you do a USR command from Basic, the BC register holds the value of that USR, so here, BC=23825. The ADD HL,BC command means LET HL=HL+BC, so HL=23825+15=23840 (5C20). BC then becomes 256 and then you come across a special instruction, LDIR. What this does is to move BC bytes from HL to DE. For instance, to move a screen from 32768 (the screen is 16384-23295), you'd do LD HL,32768: LD DE,16384: LD BC,6912: LDIR

Here, the LDIR is from 23840 to 61440, for 256 bytes. Then it JP's to 61440. Put a breakpoint over the JP with your dissassembler, RUN the program and dissassemble 61440.
F000:  LD   IX,4000  LD   DE,1B00  XOR  A  CALL F04E  LD   IX,6800  LD   DE,6000  XOR  A  CALL F04E  LD   A,0F  LD   (5C8D),A  LD   (5C48),A  LD   A,01  OUT  (FE),A  LD   A,195  LD   (5C37),A  LD   BC,1400  XOR  A  IN   A,(1F)  OR   C  LD   C,A  DJNZ F02A  AND  192  JR   Z,F049  XOR  A  LD   (9EAE),A  JP   B110  
We can see that a block is loaded 4000,1B00 and another 6800,6000. Note that the CALL is different (F04E, not 0556) and the value of A is also different (0, not FF). This is simply because the loader is using a different routine to do the actual loading (a turboloader, not the normal speed ROM loader). The JP at F039 starts the game, so put a breakpoint there and load the game (make sure your dissassembler is out of the way, or the game will be loaded over it).

Hacking the game, the LD A,5 (5 lives) is at 45362; the lives store is 40549, which is referenced at 40550,40562,45364 and 45565. The routine at 40550 is:
LD   HL,40549  ADD  A,(HL)  LD   (HL),A  
Turning the LD (HL),A into a 0 (at 40554) gives infinite lives.

Coming back to the loading system, the Basic can be MERGEd, and you can work out the address of the JP in the basic program before it is moved to F039. You know that 5C20 goes to F000, so 5C20+39 goes to F039, ie 5C59. The final hack is:
100 MERGE ""  110 POKE 23897,201  120 RANDOMIZE USR 23825  130 POKE 40554,0  140 RANDOMIZE USR 45328  
(The 45328 came from the JP B110 at the end of the loader). However, the address of basic programs varies (eg. if Microdrives are connected), so the 23825 and 23897 are expressed in terms of the start of Basic. Also, the original program did a CLEAR 65367 before the USR, so we also need to include that. Hence:
100 CLEAR 65367: MERGE ""  110 LET a=PEEK 23635+256*PEEK 23636  120 POKE a+142,201  130 RANDOMIZE USR (a+70)  

The variable a is the start of basic. The rest of the hack would be the same because the game is always loaded to the same place regardless of where Basic is.

The Ballbreaker II hack is in this month's Pokes - see if you can work out how I did it (you shouldn't have too much difficulty, but bear in mind the Basic cannot be MERGEd).


Next month, I'll be discussing decryption, and using it, together with this month's column, to crack Firebird Bleepload. If you hit any problems, drop me a line at Jon North, HTH, YS, 30 Monmouth Street, Bath, Avon. If you don't send an SAE you definately won't get a reply, but you should do if you do. 'Til next month, if it loads- hack it!

 

 

Issue 57

As promised, this month I'll explain what decrypters are, and how to crack a simple one.


Decrypters? What The...?
When a loading system loads, it appears as a big block of data on tape. Within this data is, say, 20 or 30 bytes of runnable machine code and loads and loads of garbage. The runnable machine code takes the garbage, byte by byte, and changes it into something else. Part or all of this new data will be some more machine code, and, eventually, it will all be runnable, in which case you've found the loading system.

Why Bother?
As yow saw last month, to put pokes into a protected game, you need to make the computer load it in, then go back to your hack to put in the infinite lives (or whatever) poke. To do that, you need to change the JP to the game in the loading system, but to even be able to do THAT you need to have access to it. Surprise surprise, to get access you need to crack the decrypter(s) in front of it.

How Do You Recognise One?
A decrypter will change bytes in memory. If you like, they are like putting POKEs in, but the value of the POKE depends on what's already there, eg POKE addr,PEEK addr+4, although in practise they are more complex than that (usually). We saw in the first column that PEEK is denoted in machine code by brackets, so you are looking for brackets, and the end of the loop will be a JP, JR or RET followed by Z or NZ.

The R Register
This is a special register which is very often used in decrypters. Alkatrazz and the various Speedlocks use it, as well as a lot of others. Every time a machine code instruction is executed, the R register goes up. It is possible to calculate how much it goes up by, for example XOR A increments R by one, but LD IX,23000 increments R by two. If R is given a predetermined value at the start of the protection system, its value is known after every instruction until the loading system starts. Therefore, if you start a decrypter with LD A,200: LD R,A then you can reference the value of R (and decrypt with it) at any point until you actually resume loading.

Trailing Decrypters
These decrypters work out the number to put in memory by using the last number put in memory. For instance, it is known that if 44 has just been put in memory, then the next number will be PEEK address-44 (or whatever the instruction says- it may be PEEK address+44).

If you are having trouble understanding that lot (it's a bit tricky trying to put it into words), I'll be giving practical examples of each type over the next couple of months.

Example: ZOLYX (and countless other Covergames)
*Load the basic and see what you get:

Zolyx      LINE 0 LEN 142  
Now *List it, remembering that 0 is the first line executed:
10 PAPER 0: INK 0: BORDER 0: CLEAR 32767  20 LOAD ""CODE 65024  30 RANDOMIZE USR 65024  40 POKE 23418,84  50 SAVE "Zolyx" LINE 0  60 LOAD "Mast0"  
So we know to CLEAR 32767, and that the loader runs from address 65024. Load the code in and disassemble from 65024
FE00 DI  FE01 LD   HL,FE80  FE04 XOR  A  FE05 LD   R,A  FE07 LD   A,R  FE09 XOR  (HL)  FE0A LD   (HL),A  FE0B INC  HL  FE0C LD   A,H  FE0D OR   L  FE0E JP   NZ,FE07  FE11 JP   FE80  
The DI simply stops R getting corrupted. It stands for Disable Interrupts, which in English means that the processor doesn't stop every 50th of a second to read the keyboard. HL is then set to FE80, and A and R are set to 0. The loop itself starts now. A is set to the value of R (which remember is constantly changing), and this is then XORed with PEEK HL. (XOR is a logical function, and is used in the same way as you would use ADD or SUBtract). The new value is then put back into memory with the LD (HL),A instruction, and HL incremented (has 1 added to it), so it points to the next address in memory. LD A,H: OR L is just a way of seeing if HL=0. If it does not, it JPs to FE07, and does the same thing all over again with the next address in memory. If HL does equal 0, it JPs to FE80. Incidentally, doing INC HL when HL=FFFF makes HL equal 0. So we know that this particular decrypter changes every byte in memory from FE80 to FFFF inclusive.

To crack it, we want to make it come back to our hack once it has done all it's decrypting, so you can POKE FE11 with C9 (for RET). Try it directly in basic - you'll see it crashes. That's because of the DI right at the start. To overcome this, simply Enable the Interrupts (the EI instruction), which you can do by POKEing FE11 with FB and FE12 with C9.

After it has done it's decrypter, it JPs to FE80. I won't go into detail here because I covered headerless files last month, but here's a summary of the routine at FE80: FE80-FE8F makes the screen black
FE90-FEA3 loads the two game blocks
FEA4-FEB1 moves the routine at FEB2 to 6000 and JPs to it. The routine is 50 bytes long.
FEB2-FEBF moves the game from FDFF to FFFF, and JPs to it. The game is 5001 bytes long. Change the BOOO at FEBE to something convenient to put pokes in.


A USEFUL ROUTINE
If you want to hack a protected game, it is more than likely that it will crash if you try to load it and then return to Basic. The following routine will cause a NEW to 6400 (I have never seen a game where the code from 4000 to 6400 is needed to get infinite lives), so you can return to Basic which makes hacking easier. Note, that sometimes (as with Zolyx above) the game is loaded at a certain place in memory, but is moved to somewhere else. Keep a look-out for that before you hack the game itself. Generally, if the JP to the game is very low (say, 5B00-6000) or very high (FA00-FFFF) the game will be moved.
DI  XOR  A  LD   DE,6400 (change this if you want, but not lower than about 5D00)  JP   11CB  



Sorry I didn't have enough space to crack Bleepload - I'll do it next month, honest! In the meantime, why not try it yourself (here's a clue: it does the same thing 46 times then prints a picture!)? If you hit any problems or have any ideas, drop a line to Jon North, H2H, YS, 30 Monmouth Street, Bath, Avon BA1 2AP. If you send a SAE you'll definitely get a reply, if you don't you definitely won't. Before I go, I'd like to say thanks to Giles Hopson of Sutton in Surrey, who, if he hadn't lent me his Speccy, this month's column wouldn't have been written.

 

Issue 58

As has been promised to you for months, this issue I will be showing you how to crack the Firebird Bleepload. So stand by your disassemblers - this is going to be tricky.


The First Stage
As with any protection system, you will need a copy of a game with the Bleepload on it (cracking it may be a bit difficult otherwise). As an example, I will be cracking Beach Buggy, but all the other Bleepload games are almost identical, so any one will do.

The Basic Bit
First off, *Load the basic loader:

Buggy     LINE 10 LEN 179  
When *Loaded, *List it:
10 REM  20 CLEAR 25500  30 BORDER 0: PAPER 0: INK 0: CLS  40 PRINT AT 1,9; PAPER 1; INK 7;" BEACH BUGGY "  50 LOAD "Buggy1"CODE 52480  60 RANDOMIZE USR 52480  

The loader (The Juicy Bit)
Load the next block (the loading system) into 52480 and disassemble it. 52480 is CD00 hex. Following the code down from CD00, we see a JP (HL) at CD58. Normally you would put a breakpoint over the JP, but JP (HL) is a 1-byte instruction, and a breakpoint takes 3 bytes. What you do in this situation is put a breakpoint over the previous instruction, as long as you have 3 spare bytes. The first instruction you can do this on is the LD (FF15),A at CD54. Put a breakpoint here and JP to CD00. When control returns to the disassembler, inspect the Z80 registers to find the value of HL (ie, where the JP will JP to). It is FF0A; disassemble this and we see it holds the instruction JP CD1B, which will go back and load another block. Put a breakpoint at CD1B and continue (so you can now put a second breakpoint at CD54).
The next time control returns, HL=FF06 which is again another JP CD1B. This will keep going on forever, or until HL holds an instruction other than JP CD1B. Rather than repeating the procedure of running and executing breakpoints, we will write a simple routine which will do it for us.
LD   (FF15),A  INC  HL  LD   A,(HL)  DEC  HL  CP   1B  RET  Z  <breakpoint>  
Taking one instruction at a time: LD (FF15),A is simply a copy of the 3 bytes we are overwriting (at CD54) by passing control to our routine. INC HL makes HL equal to the address of the first of the two bytes of the JP address (HL originally holds the value of an address containing C3, which is Z80 code for JP) LD A,(HL) makes A equal to the contents of HL (remember the brackets), ie the first byte of the JP address. DEC HL returns HL to its original value. CP 1B stands for ComPare 1B, ie does A equal 1B? RET Z stands for RETurn if Zero, ie return back to the loader if A=1B. This routine can be placed anywhere in memory, but I will put it at CCA0, because it is close to the loader and so is unlikely to get loaded over. It is possible that it could, in which case we would have to start again, but putting the routine somewhere else. The final stage is to put a CALL CCA0 at CD54 (in place of the breakpoint) and return control to the loader. Control is returned to the disassembler after 2E has loaded. HL is FF08, which reads JP 5D00. Disassemble this:
5D00 PUSH IX  5D02 CALL CD6E  5D05 CALL CE2A  5D08 CP   (HL)  5D09 JR   Z,5D12  5D0B LD   B,0  5D0D CALL CE7E  5D10 JR   5D02  5D12 DI  5D13 POP  HL  5D14 LD   L,0  5D16 LD   DE,(FEE7)  5D1A LD   A,(DE)  5D1B XOR  (HL)  5D1C INC  H  5D1D XOR  (HL)  5D1E DEC  H  5D1F LD   (DE),A  5D20 INC  L  5D21 INC  E  5D22 JR   NZ,5D1A  
5D00-5D10 looks like it will load another block (CD6E, CE2A and CE7E are all in the loading system). The routine 5D1A-5D23 is a decrypter, which you can see by the use of brackets in LD A,(DE) and, more importantly, LD (DE),A. However, we do not know where it decrypts, as DE has a value of the contents of FEE7 and FEE8 (which may be loaded in that last block), so put a breakpoint at 5D1A and JP CD57 (this is where we broke control from the loading system, and so is where control needs to be returned to. Rule number one: always cover your tracks!)
When control comes back to you, DE=C900. The decrypter finishes when E=0, so this decrypter changes the code from C900-C9FF, and DE will equal CA00 after it. Continuing the disassembly:
5D24 LD   DE,(FEE7)  5D28 LD   HL,5D40  5D2B LD   A,(DE)  5D2C XOR  (HL)  5D2D LD   (HL),A  5D2E INC  E  5D2F INC  L  5D30 JR   NZ,5D2B  5D32 LD   HL,0  5D35 LD   (5CB0),A  5D38 LD   A,2  5D3A LD   (5C6B),A  
This is all that can be disassembled at this stage, because the routine 5D24-5D31 decrypts 5D40-5DFF. Put a breakpoint at 5D3A and continue.
5D3D LD   DE,(FEE7)  5D41 LD   HL,(FEE9)  5D44 LD   A,(DE)  5D45 XOR  (HL)  5D46 LD   (HL),A  5D47 INC  HL  5D48 LD   B,B  5D49 JR   NZ,5D44  5D4B LD   A,(FEEC)  5D4E CP   H  5D4F JR   NZ,5D44  
Before we carry on the disassembly, put a breakpoint at 5D44 and continue, because HL=(FEE9) which could be a couple of bytes after the decrypter. When control returns, however, HL=CF00 which is nowhere near the area in memory we are concentrating on. Therefore, although we didn't need to put a breakpoint there, at least we definitely know we are safe.
5D51 LD   HL,CF00  5D54 LD   DE,4000  5D57 LD   BC,1B00  5D5A LDIR  5D5C LD   HL,EA00  5D5F LD   DE,6300  5D62 LD   BC,1000  5D65 LDIR  5D67 LD   A,3D  5D69 LD   BC,7  5D6C LD   DE,6  5D6F CALL FA00  5D72 LD   SP,63BF  5D75 EI  5D76 CALL 28E  5D79 JR   Z,5D98  5D7B LD   A,D  5D7C SUB  E  5D7D CP   21  5D7F JR   NZ,5D98  
5D51-5D66 moves a couple of chunks of code around (including the screen) 5D67-5D71 must obviously load the rest of the game (it is the only CALL to somewhere other than the ROM) 5D72-5D80 sets up the stack and interrupts (unimportant as far as we are concerned) and JP to 5D98 (in the unlikely event that the JR at 5D79 is ignored, the one at 5D7F will definitely be executed). Disassembling 5D98 (where it JPs to)
5D98 JP   B1FB  

That's it! We've cracked Bleepload! You can move the POKEs you've got to 5D98 from your hacking routine, and end them with a JP B1FB to start the game. Or, if you're actually hacking the game, you can put the NEW routine I gave you last month at 5D98, so the game will load and then NEW, so enabling you to hack it.


Wasn't that exciting? Your very first "commercial" crack. Today, Bleepload... tomorrow, Barclays - who knows? If you don't, or aren't sure whether you do or not, drop a line to Jon North, H2H, YS, 30 Monmouth Street, Bath, Avon BA1 2AP. Enclose an SAE and you'll certainly get a reply; don't and you certainly won't. Catch you next month.

 

 

Issue 59

This month, I'll be finishing off last month's Bleepload explanation with the hack that you should have got for Beach Buggy. Once I've done that I'll be covering Powerload, and cracking Red LED.


The Bleepload Crack
This is the routine you should have worked out for yourselves. Basically, it takes the patches I explained last month and does them all, in order, so that the JP to the game is overwritten with the infinite lives pokes. To use it, CLEAR 25500: LOAD ""CODE (from the basic loader) then RANDOMIZE USR 32768.
listing 1

      ;Bleepload crack by Jon North        ;This one's for Beach Buggy        ORG  #8000        ;Start from #8000=32768        LD   A,#CD        ;Patch in a CALL        LD   (#CD54),A        LD   HL,CHECK     ;The CALL is to "CHECK"        LD   (#CD55),HL        JP   #CD00        ;Start the loader  CHECK LD   (#FF15),A    ;Execute the command overwritten by our patch        INC  HL           ;Go past the "JP" instruction        LD   A,(HL)       ;A=LSB of JP address        DEC  HL           ;Restore HL to its original value        CP   #1B          ;Does A=#1B?        RET  Z            ;Return if so        LD   A,#32        ;Otherwise remove the patch        LD   (#CD54),A        LD   HL,#FF15        LD   (#CD55),HL        LD   A,#C3        ;C3 is code for JP        LD   (#5D3A),A    ;Patch in a JP        LD   HL,BACK      ;The JP is to "BACK"        LD   (#5D3B),HL        JP   #5D00        ;Resume loading and wait for control  BACK  LD   (#5C6B),A    ;Execute the command overwritten by our patch        LD   HL,POKES     ;Move the pokes to overwrite the JP to the game        LD   DE,#5D98     ;The JP is at #5D98        LD   BC,END-POKES ;BC=length of the pokes        LDIR              ;Move the code down        JP   #5D3D        ;Resume loading  POKES XOR  A            ;A=0        LD   (#B336),A    ;Infinite fuel        LD   (#C779),A    ;Infinite time        LD   A,#C3        LD   (#CA44),A    ;Infinite time        JP   #B1FB        ;Start the game  END   EQU  $  
Note that this routine was written for the Devpac assembler, yours may use different notation.

The Stack
In machine code, you can store values on what is called a "stack" ng. It in fact does a JP HL, so ignore the brackets. HL was previously set to 5E68, so this is where the JP is to.
5E68 LD   A,12  5E6A LD   (5E93),A  5E6D POP  HL  5E6E PUSH HL  6E6F POP  DE  6E70 RET  
The value at the top of the stack is 5E76, so this is where the RET will go to.
5E76 POP  BC  5E77 LD   A,(HL)  5E78 NEG  5E79 LD   (HL),A  5E7A INC  HL  5E7B DJNZ 5E77  5E7D POP  HL  5E7E LD   (5E78),HL  5E81 POP  BC  5E82 LD   A,C9  5E84 LD   (5E7E),A  5E87 LD   A,0  5E89 LD   (5E7A),A  5E8C PUSH DE  5E8D POP  HL  5E8E RET  
Firstly, there is a decrypter from 5E77 to 5E7C, so put a breakpoint at 5E7D before you go any further. You may not recognise the DJNZ 5E77 command at 5E7B. DJNZ stands for Decrement B, and Jp if Not Zero, in other words, B=B-1 and then if B doesn't equal 0, JP to 5E77. It is used exactly as JP NZ, JR NZ, CALL NZ or RET NZ would be used. The RET at 5E8E is to 5E77. You may think this strange, seeing as we've just cracked that code, but look closely and you'll see it has been modified. It now reads:
5E77 LD   A,(HL)  5E78 RRD  5E7A NOP  5E7B INC  HL  5E7C DJNZ 5E77  5E7E RET  
If you think that this doesn't decrypt, because there is no LD (HL),A instruction, you should realise that RRD (and RLD) in fact change both A and (HL), so this instruction is like a decrypting instruction (ADD or SUB, for example) and a LD (HL),A all rolled into one. The RET at 5E7E is to 5E12.
5E12 LD   HL,5FB4  5E15 LD   DE,5FB5  5E18 LD   BC,88B8  5E1B LDIR  5E1D POP  HL  5E1E LD   D,H  5E1F LD   E,L  5E20 INC  E  5E21 POP  BC  5E22 LDIR  5E24 LD   B,1E  5E26 POP  HL  5E27 LD   A,(HL)  5E28 XOR  A3  5E2A LD   (HL),A  5E2B INC  HL  5E2C DJNZ 5E27  
You should POKE 5E1B, 5E1C, 5E22 and 5E23 with 0 (otherwise the disassembler will be overwritten). Put a breakpoint at 5E27 to find out where the decrypter changes data- it is at 5E2E, the address immediately after the decrypter. To overcome this, move the block of code 5E27-5E2D to somewhere convenient, put a breakpoint after it and run it from there.
5E2E POP  HL  5E2F LD   (5E02),HL  5E32 POP  HL  5E33 LD   (5E05),HL  5E36 SCF  5E37 LD   A,7  5E39 CALL 5E00  
The routine at 5E00 is a standard headerless loader. IX=9C40, DE=0190, A=7, and the code at 5E07 is the start of the ROM loading routine, followed by a JP to it. It is effectively the same as CALL 0556.
5E3C JP   NC,1  5E3D LD   HL,9C40  5E40 LD   B,FF  5E42 CALL 5E77  5E45 LD   B,FF  5E47 CALL 5E77  5E4A DI  5E4B RET  
The decrypter at 5E77 is unchanged. The RET at 5E4B is to 9C40. We can do away with the basic loader altogether in the final hack, by loading the second block of code as a standard headerless file, then decrypting it ourselves (as long as the decrypter in the hack is sufficiently different to the decrypter in the basic).
9C40 LD   HL,9C52  9C43 LD   BC,190  9C46 LD   D,A5  9C48 LD   A,(HL)  9C49 XOR  D  9C4A LD   (HL),A  9C4B INC  HL  9C4C DEC  BC  9C4D LD   A,B  9C4E OR   C  9C4F JP   NZ,9C48  
To crack this, change the JP NZ at 9C4F to a JR NZ: RET then CALL the decrypter (put a breakpoint after the call). JR NZ uses only two bytes, whereas JP NZ uses three, leaving us a spare byte for the RET.
9C52 LD   HL,9C63  9C55 LD   DE,FE52  9C58 LD   BC,190  9C5B LDIR  9C5D LD   SP,FD80  9C60 JP   FE52    FE52 LD   A,84  FE54 LD   DE,1800  FE57 LD   IX,4000  FE5B CALL FEB8  FE5E LD   DE,400  FE61 LD   IX,5BFF  FE65 CALL FF37  FE68 LD   DE,1D4  FE6B LD   IX,FE2C  FE6F CALL FF07  
The big headerless block that follows, as you can see, is treated as a series of shorter headerless blocks without leader tones. We do not know the code at FE72 yet, because the last headerless file overloads itself. To get around this, put a patch in the equivilent code from 9C63 (which is still there), and load the first part of the game from there. What this means is put a breakpoint at 9C83 and JP to 9C63. Once loaded, the following code is seen:
FE72 LD   DE,8440  FE75 LD   IX,E1FF  FE79 CALL FF37  FE7C LD   DE,12E4  FE7F LD   IX,FFFF  FE83 JP   FF7D    FF7D LD   A,0  FF7F OUT  (FE),A  FF81 CALL FE2C    FE2C LD   HL,4000  FE2F LD   BC,1B00  FE32 XOR  A  FE33 XOR  (HL)  FE34 LD   D,A  FE35 INC  HL  FE36 DEC  BC  FE37 LD   A,B  FE38 OR   C  FE39 LD   A,D  FE3A JP   NZ,FE33  FE3D RET  
The routine FE2C-FE3D checks the screen, and comes out with a value in D. It is not a decrypter, because there is no LD (HL),A instruction. The RET at FE3D is to FF84.
FF84 LD   HL,FE50  FF87 CP   (HL)  FF88 JP   Z,FF96  FF8B LD   HL,EE48  FF8E LD   BC,FFFF  FF91 LD   DE,EE49  FF94 LDIR  
The way to overcome this is similar to what we did with the decrypter on that first headerless file. Change the JP Z at FF88 to LD D,(HL): JR FF96. It must do that JR Z, because the routine at FF8B blanks out all memory, from EE48-FF94.
FF96 LD   HL,FFB0  FF99 LD   BC,50  FF9C LD   A,D  FF9D XOR  (HL)  FF9E LD   (HL),A  FF9F INC  HL  FFA0 DEC  BC  FFA1 LD   A,B  FFA2 OR   C  FFA3 JP   NZ,FF9C  FFA6 CALL FE3E  
The routine at FE3E is similar to the one at FE2C. It checks the loaded game and returns a value in E.
FFA9 LD   HL,FE51  FFAC CP   (HL)  FFAD JP   NZ,FF8B  
You should POKE FFAD, FFAE and FFAF with 0 (to remove the JP NZ). The value is never used so you don't need to put it in yourself.
FFB0 LD   HL,5DC0  FFB3 LD   BC,80E8  FFB6 CALL FFEC    FFEC LD   A,(HL)  FFED RRD  FFEF INC  HL  FFF0 DEC  BC  FFF1 LD   A,B  FFF2 OR   C  FFF3 JR   NZ,FFEC  FFF5 RET  
This decrypts from 5DC0, then RETs to FFB9.
FFB9 LD   HL,5DC0  FFBC LD   BC,80E8  FFBF CALL FFF6    FFF6 LD   A,D  FFF7 XOR  (HL)  FFF8 LD   (HL),A  FFF9 INC  HL  FFFA DEC  BC  FFFB LD   A,B  FFFC OR   C  FFFD JR   NZ,FFF6  FFFF RET  
This also decrypts from 5DC0, then RETs to FFC2.
FFC2 LD   HL,C700  FFC5 LD   DE,4000  FFC8 LD   BC,1B00  FFCB LDIR  FFCD LD   HL,C6FF  FFD0 LD   DE,DCFF  FFD3 LD   BC,6700  FFD6 LDDR  FFD8 LD   HL,A710  FFDB LD   (5C36),HL  FFDE LD   BC,3110  FFE1 XOR  A  FFE2 SBC  HL,BC  FFE4 LD   SP,5DBF  FFE7 IM   1  FFE9 JP   6F    006F JP   (HL)  
We can change the 6F at FFEA to somewhere convenient to put pokes in, then JP (HL) at the end. Make sure, though, that you don't corrupt HL in your pokes, otherwise the JP (HL) will JP to the wrong place.

The Red LED Hack
      ORG  E200  LOAD  LD   IX,#9C40        LD   DE,#190        LD   A,7        SCF        CALL #556        JR   NC,LOAD      ;This makes it loop back if it didn't load the block properly        LD   HL,#9C40     ;Start byte to decrypt        LD   BC,#1FE      ;Length from the basic: FF+FF=1FE  DCRPT LD   A,(HL)        RRD        INC  HL        DEC  BC        LD   A,B        OR   C        JR   NZ,DCRPT        LD   IX,#9C4F        LD   (IX),#20     ;20 is code for JR NZ        LD   (IX+1),#F7   ;F7 is offset byte for -8 which in this case is 9C48        LD   (IX+2),#C9   ;C9 is code for RET        CALL #9C40        ;Do the decrypter        LD   HL,BACK        LD   (#9C61),HL   ;JP to "BACK"        JP   #9C52  BACK  LD   HL,LDPCH        LD   DE,#9C83        LD   BC,9        LDIR              ;Patch in 9 bytes to #9C83 (where we had a breakpoint before)        JP   #9C63        ;Start loading the game  LDPCH LD   HL,DCPCH        LD   (#FE84),HL   ;JP to "DCPCH", not FF7D        JP   #FE72        ;Resume loading  DCPCH LD   IX,#FE88        LD   (IX),#56     ;56 is code for LD D,(HL)        LD   (IX+1),#18   ;18 is code for JR        LD   (IX+2),#B    ;0B is offset for +11, in this case FF96        LD   (IX+#25),#C9 ;Do a RET instead of three 0'S        CALL #FF7D        ;Start decrypting the next bit        LD   HL,POKES        LD   (#FFEA),HL   ;Patch the JP 006F to come back        JP   #FFB0        ;Start decrypting the game  POKES XOR  A            ;Infinite time and energy pokes        LD   (#7F72),A        LD   (#7CB8),A        LD   (#A3E9),A        LD   A,#C9        LD   (#7FEA),A        JP   (HL)  



Wasn't that good? I'm not sure what I'll be doing next month, it'll probably be Alkatrazz. I'm saving Speedlock for a massive Speedlock Special in the Christmas issue, covering all 7 of them! In the meantime, drop me a line if you have any ideas or any questions (sae if you want a reply)- Jon North, How-2-Hack (Should've Been Called Hacking Away), YS, 30 Monmouth Street, Bath, Avon BA1 2AP. Byee...

 

Issue 60

This month sees a slight difference to the column (apart from another change to the logo, probably). I'm taking a month out to answer some of your questions, because it seems that some of you are getting hopelessly lost by what I've been doing over the last few months.
First up, I've had absolutely billions of letters asking about the SoftRom (well, one or two anyway). It's basically similar to a Multiface, but instead of 8K ROM and 8K RAM, the SoftRom has 16K RAM. You can load your own ROM's into it and call them up as and when, for instance, you could load the Multiface ROM into it and change it into a Multiface. It cost 65 quid, but are now unavailable (as far as I know). I got mine from one of Graham Mason's (remember him?) mates, who builds them himself. If I find out where you can get them from (short of Input Output), I'll let you know.

Someone who doesn't have a name and address, or who simply forgot to put them on their letter, asked what the E stands for in Basic numbers, such as 33e3. E stands for Exponent, or in English, a power of 10. 33e3 is 33 with an exponent of 3, which is 10 cubed (1000), ie 33000. The easiest way to remember it is to think of 33 'e'xtended by 3 zeros.

Crosbie Smith, apart from sending his Turrican pokes, asked how to handle R-register decryption loops with DevPac. Very simply, move the loop somewhere convenient, start it with a DI: LD A,num: LD R,A and finish with LD A,R: breakpoint. The value returned in A is 2 more than the value of R (the command LD A,R increments R by two), but remember that bit 7 is always either set or reset (when R gets to 127, it increments to 0, not 128). To work out how much R will be incremented, find the amount of bytes taken by the instruction WITHOUT THE OPERANDS, for instance LD A,120 and LD HL,40000 both increment R by one, but LD A,R or LD IX,23400 will increment it by two. Finally LDIR, CPIR and the other "repeating" instructions increment R by BC*2, for instance an LDIR with BC=100 will increment R by 200 (but watch out for that 7th bit!)

A few of you wrote with problems hacking the Zythum loader, so here's Wayne Hazell of Rochester in Kent to explain it (I haven't seen it yet).

  1. *Load the basic loader;
  2. POKE 23997,43: POKE 23998,45 to make it return to Basic;
  3. RANDOMIZE USR 23972 to load the main loader;
  4. POKE 40064,43: POKE 40065,45 to make it return to Basic;
  5. CLEAR 24150: RANDOMIZE USR 4e4 to load the game;
  6. CLEAR 65535 and either hack it in the normal way or enter your pokes.
  7. RANDOMIZE USR 50944 starts the game.
Cheers, Wayne, and thanks for the compliments!

Paul Miller is looking for more information on loaders. As I said at the start of this series, Paul, I'll be covering a different loader every month or two. I've already done Flashload and Bleepload, so get a few back issues!

A bit of a tricky one next. Stefan Dawson signs "Yours in complete frustratedness" after being unable to get Project Stealth Fighter to load into his +2 (with that tape deck I'm not surprised!). What should he do? I'm not sure, because I've only got a rubbery 48K (any unwanted 128's gratefully received), but generally the 128 paging routine is:
LD   A,page  LD   BC,7FFD  OUT  (C),A  

The value in A is calculated by the following: Bit 0-2: page number 0-7, which appears at C000-FFFF
Bit 3 : in 0 then screen is from page 5; if 1 then screen is page 7
Bit 4 : if 0 then 128K ROM is resident; if 1 then 48K ROM
Bit 5 : if 1 then lock ULA in 48K mode. This is the same as typing "Spectrum" in 128K basic.
Try looking for the above code in the loader and the game, and playing around with it. But please, if you're going to send me listings, send assembler code, not hex dumps!


I hope that sorted out your problems. Next month will see a mammoth Speedlock Special, covering everything from Daley's Decathlon in 1984 to Vendetta, only a few months old. If you've got any snags, I advise you to see a doctor. If that doesn't help, write to Jon North, How-2-Hack, YS, 30 Monmouth Street, Bath, Avon BA1 2AP. Catch you next month.

 

Issue 61

I was hoping to do a huge Speedlock Special this month, covering every one released. Unfortunately, due to the fact that there are six billion of them (approximately), I'm splitting it up over two or three issues. This month- Speedlocks 1 to 3.


SPEEDLOCK 1
This is the one with the "clicking" leader tone. The earlier ones had normal loading colours, later ones used red, blue and black. It makes no odds, though - they're all virtually identical. I'll be doing Army Moves because it was on an old Covertape.

The Small Basic Bit
Firstly, *Load and *List as usual.

army 1    LINE 0 LEN 205  0 PAPER 0: INK 0: BORDER 0: CLS : PRINT USR 23829.1: LOAD ""  
All this does is a CLEAR 65535 in machine code. Indeed, the earlier ones were just CLEAR 65535: LOAD "".

The Big Basic Bit
*Load and *List the second bit of basic.
army      LINE 0 LEN 1770  0 REM  0 BORDER 0: PAPER 0: INK 0: BRIGHT 1: CLS : POKE 23624,0  0 POKE (PEEK 23641.1+256*PEEK 23642.3),PEEK 23649.2: POKE (PEEK 23641.1+256*PEEK 23642.3)+1,PEEK 23650.2  0 POKE (PEEK 23613.1+256*PEEK 23614.2),PEEK 23627.3: POKE (PEEK 23613.1+256*PEEK 23614.2)+1,PEEK 23628.3  0 POKE 23662.1,PEEK 23618.1: POKE 23663.2,PEEK 23619.1: POKE 23664.1,PEEK 23621.1  40079FINT EXP CAT FN INKEY$ZHG-2.2786987E+35T INPUT @DINT EXP DATA ......  
Obviously, line 40079 is a load of crap which can't possibly used as basic. Except it is. Take a look at the fourth line 0 (the one with PEEK 23613 in it) and refer to the list of System Variables at the back of the Spectrum manual. You'll see that 23613 is called ERRSP, which stands for ERRor Stack Pointer. I discussed stacks in issue 59, so have a look and come back.

Whenever an error occurs (such as the Nonsense in Basic error at line 40079), the ROM sets the Stack Pointer (SP) to PEEK 23613+256*PEEK 23614 and RETs. In fact, you could write an "on error goto" routine in your own basic programs by directing it to a bit of code of your own. That fourth line 0 sets the address it RETs to, to PEEK 23627+256*PEEK 23628. PRINT this value, and that's the start of the machine code. Before you start hacking it though, put a breakpoint right at the start, return to basic and GO TO 0. Why? Because the machine code assumes certain values in certain registers, which are set by the execution of all those POKEs.

PO And PE
A JP PO,address will JP if one of the following is true:
  1. After a LD A,I; LD I,A; LD A,R; LD R,A if interrupts are disabled
  2. After a CPI; CPD; LDI LDD; CPIR; CPDR; LDIR; LDDR if BC=0
  3. After an AND; OR; XOR if there are an even number of set bits (ie 1's)
  4. After an ADD; SUB; INC; DEC if result is above 127 or below -128
Similarly, a JP PE,address will JP if one of the above is not true. You will need to know these when hacking Speedlock.

What A Load Of Crap!
The start of the code for Army Moves is 6212 hex. It looks like a load of garbage, but that's the idea - you're supposed to think you're at the wrong address. The first bit of meaningful code occurs at 62A9, but watch out for the following along the way:
RET PO - if your disassembler disables interrupts, POKE this with 0 or it'll crash.
LD R,A - you need to keep track of the value in R from now on (take a look at last month's column if you are unsure).
LDIR - this one blanks out all memory (HL=63B8, DE=63E0, BC=9B63). To overcome it, simply make BC=63 (ie the first two digits, the value in B, become 0) then add 6300 to HL and DE afterwards because the values are needed. R will remain intact, so don't worry about that.
IM 2 - if your disassembler enables interrupts, POKE this with 0 or it'll crash. Note you need to POKE both the ED and the 5E. Make sure though, that your disassembler keeps track of R (DevPac doesn't, so you'll have to calculate the value yourself if you're using it).
RET PE - again, POKE with 0 if your disassembler enables interrupts (rule one above).

Changes, Changes
Now we see the first decrypter (in fact, the only bit of code that actually looks like code):
62A9 CALL PO,3008  62AC LD   A,R  62AE XOR  (HL)  62AF LD   (HL),A  62B0 LDI  62B2 RET  PO  62B3 DEC  SP  62B4 DEC  SP  62B5 RET  PE  
62AC-62AF is a standard R-register decrypter. LDI is similar to LDIR, but doesn't repeat for each byte. In other words, the byte at address HL is POKEd into address DE, HL and DE are incremented and BC decremented. If BC=0, it has finished decrypting and the RET PO will ret, to FCA3 (from the PUSH HL at 62A7). Otherwise, the stack pointer is decremented twice (so it points to the return address for the routine at 3008, ie 62AC) and the RET PE is executed.

Note that at 62A9, you should have the following values (the rest are unimportant): HL=5EFD, DE=FCA3, BC=0315, R=C5

Control comes out of the decrypter to FCA3, where the decrypted code is placed (by repeating the LDI instruction. Doing LDI 2000 times is the same as doing a LDIR with BC=2000). The code at FCA3 is another load of garbage, followed by exactly the same decrypter as the one at 62A9, but now with the following values- HL=FCD1, DE=FCD1, BC=02E7, R=B8. The RETurn address for the RET PO is set at FCAC, with LD IY,FCD1 followed by EX (SP),IY. Once you've decrypted that, the final decrypter can be seen.
FCD1 LD   BC,(FFB7)  FCD5 LD   B,89  FCD7 LD   DE,FCA3  FCDA PUSH BC  FCDB LD   A,(DE)  FCDC PUSH DE  FCDD LD   DE,038C  FCE0 SUB  C  FCE1 LD   HL,FD2C  FCE4 XOR  (HL)  FCE5 LD   (HL),A  FCE6 INC  HL  FCE7 DEC  E  FCE8 JP   NZ,FCE4  FCEB DEC  D  FCEC JP   NZ,FCE4  FCEF POP  DE  FCF0 INC  DE  FCF1 POP  BC  FCF2 LD   C,A  FCF3 DEC  B  FCF4 JP   NZ,FCDA  FCF7 LD   HL,0000  FCFA LD   DE,FF37  FCFD LD   B,81  FCFF PUSH BC  FD00 LD   A,(DE)  FD01 INC  DE  FD02 LD   B,00  FD04 LD   C,A  FD05 ADD  HL,BC  FD06 POP  BC  FD07 DEC  B  FD08 JP   NZ,FCFF  FD0B LD   DE,319C  FD0E AND  A  FD0F SBC  HL,DE  FD11 EX   AF,AF'  FD12 LD   HL,FCD1  FD15 LD   B,3D  FD17 LD   (HL),C9  FD19 INC  HL  FD1A DJNZ FD17  FB1C EX   AF,AF'  FB1D JP   Z,FF37  FB20 LD   IY,0000  FB24 LD   (IY+75),00  FB28 INC  IY  FB2A JR   FD24  
Firstly, consider the loop FCE1-FCEC; it is a very easy decrypter (R is no longer needed), decrypting 038C bytes from FD2C. But! Now consider the larger loop, FCD7-FCF6. The initial value of A for the decrypter at FCE4 is taken from the byte at address DE, starting at FCA3, for 89 bytes. Surprise surprise, the exact length of the decrypter. There are two ways around this. Firstly, we could copy the decrypter somewhere, patch all those JP NZ's to JP to the equivilent address of the copied decrypter, or alternatively copy the decrypter somewhere, patch in the new address as the start value of DE (at FCD8 and FCD9) then run the decrypter at FCD1. The second approach is quicker to get going (and will make the final hack smaller) so I'll go for that. The breakpoint you want to put in is at FB1E - the JP Z address is the start of the turboloader.

If you are hacking a Speedlock with normal loading colours, patch the JP to the game as normal and start it loading (ie JP FF37). If you're doing the one with the red, blue and black border, the patch is totally different, so listen up.

Setting The Table
The main game file loads as a series of headerless blocks, with tiny leader tones (similar to Powerload in issue 59). The values of IX and DE are stored in a table, and taken out one by one and loaded. To find the table, search the code for FD 21 (ie LD IY,address). The third one LD's IY with the address of the table. To find out where it loads to:
10 FOR f=address TO 1e9 STEP 5  20 PRINT PEEK f+256*PEEK (f+1);",";PEEK (f+2)+256*PEEK (f+3)  30 IF PEEK (f+4) THEN NEXT f  
Incidentally, PEEK (f+4) holds the 128K page number.

Find a safe place to put your pokes (probably about 5D00ish) and put them there. Now search the code for ED 53 which is code for LD (address),DE. The instruction directly above it is a LD DE,address. Change the address to the address of your pokes, and you can now load the game. The JP to the game must be to the address you overwrote (ie the value of DE). If you are using HL to put your pokes in, you MUST firstly PUSH HL then POP HL before the JP, because the value in HL is checked to see whether the game has loaded properly or not.

The Army Moves Hack
I've made this hack as general as possible. All you should need to change is the value of VARS. Make sure you CLEAR 6e4 before you run it (RANDOMIZE USR 3e4), or the stack will get overwritten by the loading system.
      ORG  30000  VARS  EQU  #6212         ;This is the address of the start of the code in the basic  LOAD  LD   IX,#5CCB        LD   DE,1770        LD   A,255        SCF        CALL #556        JR   NC,LOAD       ;Loop back if basic hasn't loaded properly        DI                 ;To preserve R        LD   HL,#5EFD      ;The initial values for the first decrypter are put in manually        PUSH HL            ;Keep this value temporarily        LD   DE,#FCA3        LD   BC,VARS-#5EFD        LD   A,#C4         ;R will be incremented once by the CALL to the decrypter        LD   R,A        CALL VARS+151      ;Do the first decrypter and RET PO back        LD   HL,#FCD1      ;Put in the initial values for the second decrypter        LD   DE,#5F2B      ;This was #FCD1 but doing this will make another copy of the code        LD   BC,#2E7        LD   A,R        ADD  A,21          ;Compensate for the extra code we've executed and for not executing FCA3-FCC3        SET  7,A           ;R always preserves bit 7, and so must we. This could be an "OR 128" instruction        LD   R,A           ;Put the new value back into R        CALL #FCC4         ;Do the second decrypter and RET PO back        POP  HL            ;Take that 5EFD we pushed onto the stack earlier        LD   (#FCD8),HL    ;The code at 5EFD is now an exact copy of the code at FCA3        LD   HL,#FD1D      ;The address of the JP Z,FF37        DEC  (HL)          ;The JP Z now reads RET (CA is code for JP Z and C9 is code for RET)        CALL #FCD1         ;Do the final decrypter        LD   HL,POKES      ;Copy the pokes to a safe place        LD   DE,#FCD1      ;such as FCD1        LD   BC,END-POKES  ;BC=length of the pokes code        LD   (#FE9F),DE    ;FE9F is the address of the number in the LD DE,GAMEJP command        LDIR               ;Move the pokes        JP   #FF37         ;And now load the game  POKES EQU  $             ;PUT YOUR INFY LIVES POKES HERE BUT REMEMBER TO PRESERVE HL        JP   #FF7A         ;This is the original address for the LD DE,NUMBER  END   EQU  $  

SPEEDLOCK 2
This is the one with the flashing border and loads of annoying bleeps. I'm doing Athena as an example, because it was the first one I found.

The Basic Bit
*Load and *List as normal.
ATHEN 48  LINE 0 LEN 65  0 BORDER 0: PAPER 0: INK 0: CLEAR 32000: LOAD ""CODE : PRINT USR 58616  
So CLEAR 32e3: LOAD ""CODE and load in that huge chunk of code that follows, and start disassembling it. 58616 is E4F8 hex.

Six Of One....
There are six decrypters in Speedlock 2, but they are all very easy to crack.
E4F8 LD   B,21  E4FA LD   HL,E508  E4FD LD   A,(HL)  E4FE XOR  B  E4FF LD   B,A  E500 LD   (HL),A  E501 INC  HL  E502 LD   A,H  E503 OR   L  E504 JR   Z,E508  E506 JR   E4FD  
To crack this simply put it somewhere convenient and stick a breakpoint on the end. Note that it terminates (as do the other five) when HL=0 (ie there is no counter to check how many bytes are left). HL=0 when you INC HL if HL=FFFF, so this decrypter (and the others) decrypt from the initial value of HL (E508 in this case) through to FFFF, so don't put it there!
E508 JR   E50F  E50A LD   DE,E520  E50D JR   E512  E50F DI  E510 JR   E517  E512 LD   A,(DE)  E513 RLCA  E514 LD   (DE),A  E515 JR   E519  E517 JR   E50A  E519 INC  DE  E51A LD   A,E  E51B OR   D  E51C JR   Z,E520  E51E JR   E512  
As you can see, this one is full of JR's going all over the place. If you look at where it's going and make a note of what it does along the way, you can see what happens a bit easier.
E50F DI  E50A LD   DE,E520  E512 LD   A,(DE)  E513 RLCA  E514 LD   (DE),A  E519 INC  DE  E51A LD   A,E  E51B OR   D  E51C JR   Z,E520  E51E JR   E512  
Again, this is an easy decrypter (they all are). Simply move E508-E51F to somewhere convenient, slap a breakpoint on the end and run it from there.
E520 LD   E,85  E522 DI  E523 XOR  A  E524 OUT  (9F),A  E526 IN   A,(9F)  E528 LD   A,(300E)  E52B CP   C9  E52D JR   Z,E530  E52F RST  0  E530 LD   A,43  E532 OUT  (7F),A  E534 LD   HL,0000  E537 LD   (0000),HL  E53A LD   HL,(0000)  E53D LD   A,L  E53E OR   H  E53F JR   NZ,E546  E541 LD   A,40  E543 OUT  (7F),A  E545 RST  0  E546 LD   BC,E552  E549 LD   A,(BC)  E54A XOR  E  E54B LD   E,A  E54C LD   (BC),A  E54D INC  BC  E54E LD   A,B  E54F OR   C  E550 JR   NZ,E549  
The actual decrypter in this chunk of code is at E546-E551, but it uses the value in E, set right at the start. For those interested, the code at E522-E52F checks for a Multiface, and from E530-E545 for a SoftRom (this is pointless as they can both be made "invisible"). To crack it, do what you've been doing so far - move E520-E551 somewhere, slap a breakpoint on the end and run it from there. Make sure, before you run it, that if a Multiface or SoftRom are connected, that you have disabled them, or the checking routines will cause a crash.
E552 LD   DE,E560  E555 LD   A,(DE)  E556 XOR  D  E557 SUB  E  E558 XOR  E  E559 ADD  A,D  E55A LD   (DE),A  E55B INC  DE  E55C LD   A,D  E55D OR   E  E55E JR   NZ,E555  
This is very straightforward, and you crack it as you've been cracking the others.
E560 JR   E567  E562 LD   HL,E579  E565 JR   E56A  E567 DI  E568 JR   E570  E56A LD   A,(HL)  E56B XOR  F3  E56D LD   (HL),A  E56E JR   E572  E570 JR   E562  E572 INC  HL  E573 LD   A,H  E574 OR   L  E575 JR   Z,E579  E577 JR   E56A  
This one is similar to the one at E508, with JR's all over the place. The order in which the instructions are executed is:
E567 DI  E562 LD   HL,E579  E56A LD   A,(HL)  E56B XOR  F3  E56D LD   (HL),A  E572 INC  HL  E573 LD   A,H  E574 OR   L  E575 JR   Z,E579  E577 JR   E56A  
Move E560-E578 to somewhere convenient and slap a breakpoint on the end.
E579 LD   HL,5BFF  E57C LD   (HL),0  E57E DEC  HL  E57F LD   A,H  E580 CP   3F  E582 JR   NZ,E57C  E584 LD   HL,E58F  E587 LD   A,(HL)  E588 RRCA  E589 LD   (HL),A  E58A INC  HL  E58B LD   A,H  E58C OR   L  E58D JR   NZ,E587  
Cracking this final one (in the usual way) will reveal the Speedlock loader. Now all we need to do is find it.

Where'd The Loader Go?
From your experience with the first Speedlock, you know that LD IY,address points to the address of the table. With Speedlock 2, it's the second LD IY, not the third, that gives the address of the table, so search for FD 21 (LD IY,nn). The first one, at EE67, is LD IY,0000. Again from Speedlock 1, you know that this is the first byte of the loader, so make a note of the address. Now search for FD 21 again, and you see a LD IY,8B5E, so you know that this is where the table should be. Now look for ED 53, which is code for LD (nn),DE and is the standard Speedlock patch. For Athena, this is at F0AD, with the LD DE,nn at F0AA. Change the LD DE,nn above it to point to a convenient address where you have put your pokes. Now search for F3 31, which is code for DI: LD SP,nn. These are the first two instructions executed by Speedlock, and JPing here will start it loading (don't do it yet). Following the code from F15B (where the DI is), you will see the table of addresses to load, at F1C5 (you identify it by the 00 80 00 03 10, which loads the attribute file for the screen).

Moving Around
So far you know where the table is (F1C5) and where it should be (8B5E). You also know that EE67 is the first byte. Now you are in a position to put Speedlock into its correct address and start it loading.

If F1C5 goes to 8B5E, EE67 goes to 8B5E-(F1C5-EE67), which is 8800. The address it executes from was originally at F15B, which is now at F15B-EE67+8800, ie 8AF4. To be on the safe side, make the length of the code FFFF-EE67, to make sure you've got it all. Now that you know the address of the patch, where the loader's going to and the address to get it going, you can move it with
LD   HL,#EE67  LD   DE,#8800  LD   BC,#FFFF-#EE67  LDIR  JP   #8AF4  
This is the code in my hack, once the six decrypters have been cracked.

The Athena Hack
The way the decryption loop in this works is to have the lengths of the six decrypters stored as a little line of data at the end. The length is taken out, and a pointer used to point to the length of the next decrypter. It is similar to having a line of basic DATA, then doing a FOR-NEXT loop, and READing a length in the loop. Before using this program, make sure you CLEAR 32e3: LOAD ""CODE (from the basic loader).
      ORG  30000        LD   IX,DATA           ;IX points to the line of data        LD   HL,#E4F8          ;E4F8 is the address of the first decrypter        LD   B,6               ;Six decrypters  DCRLP PUSH BC                ;Store B temporarily        LD   C,(IX)            ;Get the length of the decrypter from the data line        LD   B,0               ;Can never be over 255 bytes long        INC  IX                ;Point to the length of the next decrypter        LD   DE,25000          ;A safe place        LDIR                   ;Move the decrypter        PUSH HL                ;HL now points to the address of the next one. store it temporarily        LD   A,#C9             ;C9 is code for RET        LD   (DE),A            ;Stick a RET on the end of the decrypter (in place of the breakpoint)        CALL 25000             ;Do the decrypter        POP  HL                ;Take the address of the next decrypter off the stack        POP  BC                ;BC holds the amount left        DJNZ DCRLP             ;Loop back if more decrypters to do        LD   HL,POKES        LD   DE,#5BA0          ;A safe place        LD   BC,DATA-POKES     ;BC=length of pokes        LD   (#F0AB),DE        ;The standard Speedlock patch, FOAB is the address of the number in LD DE,NN        LDIR                   ;Move the pokes        LD   HL,#EE67          ;EE67 holds the LD IY,0        LD   DE,#8800          ;This is where it should be        LD   BC,#FFFF-#EE67    ;Make sure you've got all the code        LDIR        JP   #8AF4             ;Load the game  POKES EQU  $                 ;Make sure you preserve HL in your pokes if you're using it        JP   #8B45             ;The original number in the LD DE,NN  DATA  DEFB 16,24,50,14,25,22 ;Lengths of the decrypters  

SPEEDLOCK 3
This is virtually identical to Speedlock 2, except for the way you work out where the loader should be. I'm doing Out Run as an example. First off, *Load and *List the bit of basic.
run       LINE 0 LEN 155  0 BORDER 0: PAPER 0: INK 0: CLEAR 45000: LOAD ""CODE : GO TO USR 58616  
The rest of the basic is unimportant. CLEAR 45e3 and load the code which follows, and disassemble 58616 (DF13 hex)

...And Half A Dozen Of The Other
There are also six decrypters in this Speedlock.
DF13 DI  DF14 LD   HL,DF24  DF17 LD   B,7F  DF19 LD   A,(HL)  DF1A XOR  B  DF1B LD   B,A  DF1C LD   (HL),A  DF1D INC  HL  DF1E LD   A,H  DF1F OR   L  DF20 JR   Z,DF24  DF22 JR   DF19  
Crack this one (and the five that follow) exactly as you cracked the six in Speedlock 2. Notice that in the final hack we won't be able to PUSH HL and BC, or CALL the decrypter, because there is a LD SP,HL and a LD SP,IY. Notice that the SP instructions in the third decrypter are never executed (that code is used as a hidden message, not runnable code).

Moving Speedlock 3
First off, search for FD 21 00 00 (LD IY,0000) to find the first byte of Speedlock; you'll find it at E7B6 on OutRun. Now search for ED 53 (the standard Speedlock patch). Change the LD DE,FE9E at E9FF to read
       LD   6+1               ;Length of Speedlock         LDDR                   ;Like a LDIR but starts at the last byte and works backwards         JP   #EAB8+#FEC4-#EAD3 ;Load the game  POKES  EQU  $                 ;PUT YOUR INFY LIVES POKES HERE         JP   #FE9E             ;The address overwritten by the Speedlock patch  DATA   DEFB 17,36,57,14,25,23 ;Lengths of the six decrypters  KEEPBC DEFW 0                 ;A safe place to stick BC  KEEPHL DEFW 0                 ;A safe place to stick HL  



Three down, four to go (although I think Time Machine will make that five to go). Any ideas or problems will be answered if you send an sae to Jon North, How2Hack (I Still Think It Should've Been Called Hacking Away), YS, 30 Monmough Street, Bath, Avon BA1 2BW. Til next month...

 

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"
      ORG  50000               ;Anything safe over 32768  LDBAS LD   IX,#F1C9-#5C        ;So that Speedlock ends up in the right place        LD   DE,3452             ;Basic length from *Load        LD   A,#FF        SCF        CALL #556                ;Standard headerless load        JR   NC,LDBAS            ;Repeat until basic loaded properly        DI                       ;So that R doesn't get corrupted  DCRLP LD   HL,#F1CD            ;Address of first actual decrypter        LD   BC,10        ADD  HL,BC               ;HL is now the address of the 10th byte of the decrypter        LD   A,(HL)              ;A=PEEK HL        CP   #B8                 ;Does (HL)=B8, ie is it a LDDR?        JR   Z,ISLDR             ;Go forward if it is        SBC  HL,BC               ;Otherwise go back to the start  ISLDR ADD  HL,BC               ;Add another 10 bytes so that we are in the loop itself        LD   A,#C3               ;We want to search for a C3        LD   BC,50               ;Only search 50 bytes        CPIR                     ;Find the byte        JR   NZ,DONE             ;If not found, we must have finished the decryption        DEC  HL                  ;HL points to the address of the C3        LD   C,3        SBC  HL,BC               ;Go back 3 bytes        LD   A,(HL)              ;A=PEEK HL        CP   #CA                 ;Is it a CA, ie a JP Z?        JR   Z,ISJPZ             ;Go forward if it is        ADD  HL,BC               ;Otherwise go to the JP instead  ISJPZ INC  HL                  ;HL is now the first byte to patch        LD   E,(HL)              ;Take the LSB of next decrypter        LD   (HL),BACK&255       ;Patch in the LSB of "BACK"        INC  HL                  ;HL is now the next byte to patch        LD   D,(HL)              ;DE is now the address of the next decrypter        LD   (HL),BACK&#FF00/256 ;Patch in the MSB of "BACK"  LDGME LD   HL,(DCRLP+1)        ;HL is now the start of the current decrypter        LD   (DCRLP+1),DE        ;Store the address of the next decrypter  KEEPR LD   A,2A                ;2A=initial value of R-1        LD   R,A        JP   (HL)                ;Do the decrypter. this instruction increments R by one so it will be 2B at F1CD  BACK  LD   A,R                 ;Come back here after decrypting. A=new value of R        SUB  3                   ;SUB 2 for the LD A,R and 1 for the JP (HL)        RES  7,A                 ;Bit 7 of R is always either set or reset, in this case it is reset        LD   (KEEPR+1),A         ;Store R for the next decrypter        JR   DCRLP               ;Now do it all again for the next decrypter  DONE  LD   HL,POKES            ;Come here when all decrypting is done        LD   DE,#5BA0            ;A safe place        LD   BC,END-POKES        ;BC=length of pokes        LD   (#FE16),DE          ;Standard Speedlock patch        LDIR                     ;Copy the pokes to 5BA0        XOR  A        LD   (#FBB8),A           ;Stops blanking out the new copy of the pokes        JR   LDGME               ;Start loading the game. (DCRLP+1) is the start of the loader  POKES EQU  $                   ;BUNG YOUR INFY LIVES POKES HERE        JP   #FEC2               ;The original value of (FE16)  END   EQU  $  



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...

 

 

Issue 63

This month sees the final installment of the Speedlock series, showing how to crack the three remaining Speedlocks (5-7). Let it roll...


Getting Started
Firstly, *Load and *List as normal. Do the bit of code at the start exactly the same way as you did for Speedlock 4 last month. You can then get cracking (Very "witty". Ed.) on the decrypters.

The Decrypters
There are nine decrypters used in these Speedlocks, but each version only uses a few of them. For instance, one Speedlock may use types 1-6, whereas another could use types 3-6 and type 8. They all have one thing in common though - they decrypt themselves. If you take a look at the first byte that each type decrypts, you'll see that it is the last byte of the decrypter itself. To crack a decrypter that does this, firstly move it to somewhere convenient, then overwrite the JP NZ address at the end so that it JP's to the correct place in the copy. This will be the first byte after the constants are LD'd into the registers at the start (for instance, it would be the DEC (HL) in type one, or the LD A,R in type 2). At the start, put a DI: LD A,num: LD R,A and at the end a LD A,R: <breakpoint> to keep track of R (in exactly the same way as you did when cracking Speedlock 4 last month).

Type 1
listing 1

EA91 LD   DE,144B  EA94 LD   HL,EA9E  EA97 DEC  (HL)  EA98 DEC  DE  EA99 LD   A,D  EA9A INC  HL  EA9B OR   E  EA9C JP   NZ,EA97  EA9F JP   EAA2  
Type 2
listing 2
EAA2 LD   HL,EAA2  EAA5 LD   DE,EAA1  EAA8 LD   BC,0064  EAAB LDDR  EAAD LD   BC,1417  EAB0 LD   HL,EAD2  EAB3 CALL EAB6  EAB6 POP  IX  EAB8 LD   DE,001C  EABB ADD  IX,DE  EABD LD   A,R  EABF XOR  IXH  EAC1 SUB  (HL)  EAC2 XOR  IXL  EAC4 LD   (HL),A  EAC5 DEC  BC  EAC6 LD   A,C  EAC7 INC  HL  EAC8 OR   B  EAC9 JP   NZ,EACF  EACC JP   EAD2  EACF JP   EABD  
Cracking this one is different to normal. You change the JP address at EACC to JP to somewhere convenient, where you have placed a LD A,R: <breakpoint> (so that you keep track of R). The reason for this is that the JP NZ is to EACF, which is itself the JP backwards to EABD. If the JP NZ does not JP (because the decrypter has finished), the JP at EACC is executed, which JP's to the next decrypter. By changing this to JP somewhere else, you can keep control without having to move the decrypter anywhere.

Type 3
listing 3
EAD2 LD   SP,EAE1  EAD5 LD   HL,EADE  EAD8 LD   DE,EADD  EADB LD   BC,0020  EADE LDDR  EAE0 JP   PE,EB1B  EAE3 LD   HL,EAF5  EAE6 LD   DE,EAE0  EAE9 LD   BC,13F4  EAEC LD   A,R  EAEE XOR  (HL)  EAEF LD   (HL),A  EAF0 LDI  EAF2 DEC  DE  EAF3 RET  PO  EAF4 JR   EAEC  
You crack this one in a similar way to that needed for Type 2. As was explained in Issue 61, a JP PE after a LDDR will only JP if BC is not zero. After the LDDR at EADE, BC is zero so the JP PE will not JP. However, by this point, the Stack Pointer (SP) has been set to EAE1, so that if a RET occurs, it will be to that JP PE address. Looking down the decrypter we see a LDI followed by a RET PO. As was also explained in Issue 61, a RET PO after a LDI will RET if BC is zero, which occurs when the decrypter has finished. Hence, that JP PE address is NOT a JP PE address, but actually the address RET'd to when the decrypter has finished (sneaky, eh?) To crack it, therefore, simply change the JP PE address so that it JP's to somewhere convenient, where you have placed a LD A,R: <breakpoint>.

Type 4
listing 4
EB5B LD   HL,EB5B  EB5E LD   BC,0064  EB61 LD   DE,EB5A  EB64 LDDR  EB66 LD   HL,EB76  EB69 LD   BC,1373  EB6C LD   A,R  EB6E XOR  (HL)  EB6F LD   (HL),A  EB70 INC  HL  EB71 DEC  BC  EB72 LD   A,B  EB73 OR   C  EB74 JP   NZ,EB6C  EB77 JP   EB7A  
Crack this as you cracked Type 1.

Type 5
listing 5
FAFC LD   HL,FB14  FAFF LD   BC,03D5  FB02 LD   D,0F  FB04 LD   A,R  FB06 XOR  (HL)  FB07 XOR  D  FB08 LD   (HL),A  FB09 LD   D,A  FB0A INC  HL  FB0B DEC  BC  FB0C INC  D  FB0D LD   A,C  FB0E OR   B  FB0F JP   Z,FB17  FB12 JP   E704  FB14 JP   (IX)  
Change the JP Z address to JP somewhere convenient, like types 2 and 3. This will end up JPing when the decrypter has finished.

Type 6
listing 6
FB17 LD   DE,FB19  FB1A LD   HL,FB1A  FB1D LD   BC,0064  FB20 LDDR  FB22 LD   BC,03B4  FB25 LD   SP,FEE7  FB28 POP  DE  FB29 LD   A,R  FB2B XOR  D  FB2C LD   D,A  FB2D PUSH DE  FB2E DEC  BC  FB2F LD   A,C  FB30 DEC  SP  FB31 OR   B  FB32 JP   NZ,FB28  
Crack this, and the ones that follow, in a similar way to that used for type 1.

Type 7
listing 7
FB5C LD   HL,FB5F  FB5F LD   BC,0064  FB62 LD   DE,FB5E  FB65 LDDR  FB67 LD   HL,FB7A  FB6A LD   BC,036F  FB6D LD   D,0A  FB6F LD   A,R  FB71 ADD  A,(HL)  FB72 SUB  D  FB73 LD   (HL),A  FB74 INC  HL  FB75 DEC  BC  FB76 LD   A,B  FB77 OR   C  FB78 JP   NZ,FB6F  
Type 8
listing 8
EF65 LD   HL,EF68  EF68 LD   BC,0064  EF6B LD   DE,EF67  EF6E LDDR  EF70 LD   HL,EF84  EF73 LD   BC,0F65  EF76 LD   D,08  EF78 LD   A,R  EF7A XOR  D  EF7B ADD  A,(HL)  EF7C CPL  EF7D LD   (HL),A  EF7E INC  HL  EF7F DEC  BC  EF80 LD   A,B  EF81 OR   C  EF82 JP   NZ,EF78  
Type 9
listing 9
F8A8 LD   BC,3FFD  F8AB LD   A,03  F8AD NOP  F8AE NOP  F8AF LD   HL,F8B4  F8B2 LD   BC,001E  F8B5 LD   DE,F8B3  F8B8 LDDR  F8BA LD   HL,F8CF  F8BD LD   BC,063E  F8C0 LD   D,FA  F8C2 LD   A,R  F8C4 XOR  D  F8C5 ADD  A,(HL)  F8C6 SUB  07  F8C8 LD   (HL),A  F8C9 INC  HL  F8CA DEC  BC  F8CB LD   A,B  F8CC OR   C  F8CD JP   NZ,F8C2  F8D0 JP   F8D3  
Final Decrypter On Speedlock 7
Speedlock 7 has it's own unique decrypter at the very end, which is cracked differently to any of the others, and has to be done seperately.
listing 10
F8D3 LD   BC,001E  F8D6 LD   HL,F8D5  F8D9 LD   DE,F8D4  F8DC CALL F8DF  F8DF LDDR  F8E1 LD   DE,0615  F8E4 POP  BC  F8E5 LD   HL,0019  F8E8 ADD  HL,BC  F8E9 LD   A,R  F8EB XOR  E  F8EC SUB  (HL)  F8ED DEC  DE  F8EE LD   (HL),A  F8EF LD   A,E  F8F0 INC  HL  F8F1 OR   D  F8F2 ????  F8F4 NOP  F8F5 NOP  F8F6 JP   NZ,F8E9  
To crack this, change the three bytes at F8F5 to a JP to a convenient address, where you have placed JP NZ,F8E9: <breakpoint>. The JP NZ is needed because you have overwritten it with your JP. R will remain intact, because NOP and JP both increase R by 1.

The Hack: Speedlock 5-7
This hack was written for Daley's Olympic Challenge (Speedlock 5) but by changing the values at the start it can be used on anything using these three Speedlocks.

Firstly, it loads the big basic block as a headerless file to where it would be after the LDIR (similar to the start of last month's Speedlock 4 hack). It then ensures that HL points to something in the middle of the decrypter, so that it's address is an instruction and not part of one of the numbers at the start. It then checks what the instruction is, from which it can identify what decrypter it has found. Having recognised it, it LD's BC with the length of the decrypter and A with an index for a JR NZ (in place of the JP NZ at the end). Then it LDIRs the decrypter to a convenient place, sticks a JR NZ and a JP back on the end of it and executes it. When it gets back, it calculates and stores R then goes back and does it all again. If it does not recognise a decrypter, it must have finished, and patches the Speedlock loader in the usual way. Note that the block of code in bold is only needed for Speedlock 7, to crack that final decrypter.
listing 11
LDTO   EQU  #EA8D-#5C            ;Start address of basic  LDLEN  EQU  5305                 ;Basic length  FIRST  EQU  #EA91                ;Address of first decrypter  LAST   EQU  #F8F5                ;Address of last decrypter on Speedlock 7  INITR  EQU  #70                  ;Initial value of R         ORG  40000  LDBAS  LD   IX,LDTO              ;Start address         LD   DE,LDLEN             ;Length         LD   A,#FF         SCF         CALL #556                 ;Standard headerless load         JR   NC,LDBAS             ;Go back if load is unsuccessful         DI                        ;So that R does not get corrupted  DCRLP  LD   HL,FIRST             ;Address of first decrypter         LD   A,(HL)               ;A=first byte         CP   #C3                  ;Is it a C3, ie a JP?         JR   NZ,TYPE3             ;Go forward if not         INC  HL                   ;Otherwise go past it. JP takes 3 bytes         INC  HL         INC  HL  TYPE3  LD   A,(HL)               ;A=first byte         CP   #31                  ;Is it a 31, ie a LD SP?         JR   NZ,CHKB8             ;Go forward if not         LD   BC,15                ;Otherwise must be Type 3  PATCH  ADD  HL,BC                ;HL=address after JP PE         LD   E,(HL)               ;Get the value out         LD   (HL),BACK&255        ;Patch in LSB of "Back"         INC  HL                   ;Next byte         LD   D,(HL)               ;Get the value out         LD   (HL),BACK&#FF00/256  ;Patch in MSB of "Back"  LDGME  LD   HL,(DCRLP+1)         ;HL is now first byte of decrypter         LD   (DCRLP+1),DE         ;DE is address of next decrypter         PUSH HL                   ;Stick address of decrypter onto stack  KEEPR  LD   A,INITR              ;Initial value of R         LD   R,A                  ;R=70         RET                       ;To decrypter (after that PUSH)  CHKB8  LD   BC,10         ADD  HL,BC                ;Go forward 10 bytes         LD   A,(HL)               ;A=value at this address         CP   #B8                  ;Is it a B8?         JR   NZ,NOTB8             ;Go forward if not, we're in the decrypter itself now         ADD  HL,BC                ;Otherwise add another 10 so we're in the dectypter itself  NOTB8  LD   A,(HL)               ;Get the byte at this address  TYPE1  CP   #B3                  ;Is it a B3?         JR   NZ,TYPE2             ;Go forward if not         LD   C,11                 ;Otherwise it must be Type 1, which is 11 bytes long         LD   A,249                ;JR NZ will go to DEC (HL)         JR   DODCR                ;Go forward  TYPE2  CP   #DD                  ;Is byte at HL a DD?         JR   NZ,TYPE4             ;Go forward if not         LD   C,23                 ;Otherwise must be Type 2, so go forward 23 bytes         JR   PATCH                ;And patch in similar to type 3  TYPE4  CP   #77                  ;Is byte at HL a 77?         JR   NZ,TYPE5             ;Go forward if not         LD   C,25                 ;Otherwise it must be Type 4, which is 25 bytes long         LD   A,246                ;Offset for JR NZ         JR   DODCR                ;Do the decrypter  TYPE5  CP   #AE                  ;Is byte at HL a AE?         JR   Z,PATCH              ;If so, crack similar to type 3. Go forward 10 bytes, BC is 10 already  TYPE6  CP   #AA                  ;Is byte at HL a AA?         JR   NZ,CHK5F             ;Go forward if not         LD   C,27                 ;Otherwise it must be Type 6, which is 27 bytes long         LD   A,244                ;Offset for JR NZ         JR   DODCR                ;Go forward to do the decrypter  CHK5F  CP   #5F                  ;Is byte at HL a 5F?         JR   NZ,TYPE9             ;Go forward if not  TYPE7  INC  HL                   ;Otherwise it could be either Type 7 or 8         LD   A,(HL)               ;Check following byte to decide whether it's a Type 7 or 8         CP   #AA                  ;Is it a AA?         JR   Z,TYPE8              ;Go forward if it is         LD   C,28                 ;Otherwise it must be Type 7, which is 28 bytes long         LD   A,245                ;Offset for JR NZ         JR   DODCR                ;Go forward and do the decrypter  TYPE8  LD   C,29                 ;Must be Type 8 if byte was AA, which is 29 bytes long         LD   A,244                ;Offset for JP NZ         JR   DODCR                ;Do the decrypter  TYPE9  CP   1                    ;Is byte at HL a 1?         JR   NZ,DONE              ;Must be finished if not because byte is not recognised         LD   C,37                 ;Type 9 is 37 bytes long         LD   A,243                ;Offset for JR NZ  DODCR  LD   (DCREND+1),A         ;Patch the value of A into JR NZ         LD   HL,(DCRLP+1)         ;HL=address of start of decrypter         LD   DE,50000             ;A convenient address         PUSH DE                   ;Stick 50000 onto the stack         LD   A,(HL)               ;A=first byte         CP   #C3                  ;Is it a C3, ie a JP?         JR   NZ,NOTJP             ;Go forward if not         INC  C                    ;Otherwise add 3 to length of decrypter         INC  C         INC  C         LD   (HL),33              ;Overwrite C3 with 33, which is LD HL,num and is harmless  NOTJP  LDIR                      ;Copy the decrypter down         INC  HL                   ;Go past the JP NZ in the decrypter. JP NZ takes 3 bytes         INC  HL         INC  HL         LD   (DCRLP+1),HL         ;HL is now the start of the next decrypter         LD   HL,DCREND            ;HL=start of the bit to stick on the end         LD   C,5                  ;This bit is 5 bytes long         LDIR                      ;Copy it down onto the end         JR   KEEPR                ;Go backwards to keep track of R  DCREND JR   NZ,$                 ;This is the JR NZ we're sticking on the end         JP   BACK2                ;And a JP to "Back2"  BACK   LD   A,R                  ;Come back here on types 2, 3 and 5 (where we patch numbers in)  DOR    SUB  3                    ;Subtract 2 for the LD A,R and one for the JP to decrypter         RES  7,A                  ;Ensure bit 7 is reset         LD   (KEEPR+1),A          ;Keep the new value for next time         JR   DCRLP                ;And loop back to do it all again  BACK2  LD   A,R                  ;Come back here on the other types, where we copy the decrypter somewhere         DEC  A                    ;Need to subtract an extra 1 for the JP back to this hacking routine         JR   DOR                  ;Go back to sort out R  DONE   EQU  $         LD   HL,LAST              ;Address of the NOP         LD   (HL),#C3             ;Stick a JP in         INC  HL                   ;Point to next byte         LD   (HL),BACK3&255       ;Stick in LSB of "Back3"         INC  HL                   ;Point to next byte         LD   (HL),BACK3&#FF00/256 ;Stick in MSB of "Back3"         LD   DE,#F8F9             ;Start of decrypter         JP   LDGME                ;Do the decrypter  BACK3  JP   NZ,#F8E9             ;The JP NZ we've overwritten by the JP BACK3         LD   HL,POKES             ;Start of infy lives pokes         LD   DE,#5BA0             ;A safe place         LD   BC,END-POKES         ;Length         LD   (#FE17),DE           ;Standard Speedlock patch         LDIR                      ;Copy pokes down         XOR  A         LD   (#FBB8),A            ;Stop printer buffer getting cleared         JP   LDGME                ;Load the game  POKES  EQU  $                    ;Stick your infy lives pokes here         JP   #FEC3                ;The original value of DE in Speedlock patch  END    EQU  $  



Well, that's got all the Speedlocks out of the way (until the next one comes out), so what am I going to do next month? I know what, how about Softlock? Yeah, OK, Softlock it is. So between now and next month, invest in a copy of Chimera, Thunderbirds, Cylu or some other old Firebird cheapie. Or write some words of wisdom to Jon North, How to Hack, YS, 30 Monmouth Street, Bath, Avon BA1 2BW. Catch you next month.

 

Issue 64

As promised, this month I'm doing SoftLock. So go dig out an old Firebird game then come back. I'm doing Chimera as an example.


The Basic Bit
First up, *Load and *List as usual...

CHIMERA    LINE 0 LEN 355  0 BORDER 0: INK 0: PAPER 0: CLS : PRINT AT 21,11;"*LOADING*": POKE 20107,255: RANDOMIZE USR (PEEK 23627+256*PEEK 23628)  1 SAVE "CHIMERA" LINE 0  
...so we see it runs from 23923, which is 5D73 hex.
5D73 LD   IYL,A  5D75 DEC  SP  5D76 DEC  SP  5D77 POP  BC  5D78 LD   HL,0000  5D7B PUSH HL  5D7C POP  IX  5D7E LD   A,2E  5D80 LD   IXH,40  5D83 SLA  A  5D85 LD   D,(IX+0)  5D88 LD   E,(IX+1)  5D8B INC  IX  5D8D INC  IX  5D8F ADD  HL,DE  5D90 CP   IXH  5D92 JR   NZ,5D85  
This checks the screen (IXH=40 hex, which is the start of the screen area), so put a breakpoint at 5D94, return to Basic then GOTO 0 (because the screen is set up by the basic). When control returns to the disassembler, BC is 5D73 and DE is CA4E. These two values are used by the decrypter which follows.
5D94 EX   DE,HL  5D95 LD   HL,003D  5D98 ADD  HL,BC  5D99 LD   IXH,B  5D9B LD   IXL,C  5D9D LD   C,32  5D9F LD   A,(HL)  5DA0 XOR  E  5DA1 ADD  A,C  5DA2 LD   (HL),A  5DA3 LD   C,A  5DA4 INC  HL  5DA5 INC  DE  5DA6 LD   A,(HL)  5DA7 XOR  D  5DA8 ADD  A,C  5DA9 LD   (HL),A  5DAA LD   C,A  5DAB INC  HL  5DAC INC  DE  5DAD CP   48  5DAF LD   A,A  5DB0 JR   NZ,5D9F  
This decrypts two bytes at a time, starting at 5DB0 (the JR NZ instruction). When it comes to cracking it in a routine, we'll move it to somewhere convenient, stick the JR NZ on the end and run it from there. As it is, firstly single-step through it, then move 5D9F-5DB1 to somewhere, stick a breakpoint on the end and run it from there.

When finished, you'll see the following code at 5DB2...
5DB2 LD   SP,0000  5DB5 LD   (5C3D),SP  5DB9 LD   HL,0556  5DBC LD   DE,FF00  5DBF LD   B,H  5DC0 LD   C,L  5DC1 LDIR  5DC3 LD   H,FF  5DC5 LD   DE,007E  5DC8 ADD  IX,DE  5DCA PUSH IX  5DCC POP  DE  5DCD LD   B,05  5DCF LD   A,(DE)  5DD0 LD   L,A  5DD1 LD   A,(HL)  5DD2 SRL  (HL)  5DD4 SRL  (HL)  5DD6 SUB  (HL)  5DD7 LD   (HL),A  5DD8 INC  DE  5DD9 DJNZ 5DCF  5DDB LD   B,17  5DDD LD   A,(DE)  5DDE INC  DE  5DDF LD   L,A  5DE0 LD   A,(DE)  5DE1 INC  DE  5DE2 LD   (HL),A  5DE3 DJNZ 5DDD  5DE5 XOR  A  5DE6 LD   L,A  5DE7 DEC  A  5DE8 LD   IX,4000  5DEC LD   DE,1C00  5DEF SCF  5DF0 JP   (HL)  
Some of this code will be new to you, but what it does is to make a copy of the ROM loader (at 0556) at FF00, by the LDIR at the start. It then uses a table to change some of the timing constants so that it turboloads (which is what the rest of the code does). Finally, it sets IX and DE to load from 4000-5C00 (the screen and a bit of code) and off it goes.
FF00 INC  D  FF01 EX   AF,AF'  FF02 DEC  D  FF03 DI  FF04 LD   A,0F  FF06 OUT  (FE),A  FF08 LD   HL,5B00  FF0B PUSH HL  
This is the start of the ROM loader, and how it works is unimportant, All you need to know is that the PUSH HL at FF0B PUSHes the return address for when loading finishes, which in this case is 5B00. To find the code at 5B00 (remember it hasn't been loaded yet), change the 5B00 at FF09 to something convenient, where you have placed a breakpoint. Once loaded, the code at 5B00 looks a bit like this...
5B00 DEC  SP  5B01 DEC  SP  5B02 CALL FF70  5B05 LD   A,L  5B06 LD   IXL,A  5B08 CALL FF70  5B0B LD   A,L  5B0C LD   IXH,A  5B0E PUSH IX  5B10 CALL FF70  5B13 LD   A,L  5B14 LD   IXL,A  5B16 CALL FF70  5B19 LD   A,L  5B1A LD   IXH,A  5B1C LD   A,IXL  5B1E OR   IXH  5B20 RET  Z  5B21 POP  DE  5B22 JP   FF70  
This code loads four bytes, and treats them as new values of IX and DE. These new values then get loaded as another headerless block (like Powerload). The DEC SP: DEC SP at the start ensures that this routine is always what control is returned to once the block has loaded, unless one of the following happens:
  1. The code at 5B00 gets overloaded, in which case control is returned to the new code
  2. FFFE and FFFF get overloaded. These two addresses hold the return address, and if overloaded, control will return to the address of the new values
  3. The loaded value for IX is zero, in which case the loaded value for DE is RETed to.
To find out which of these it is, we are going to write a simple routine which will load those values and store them somewhere, and which will load code at 5B00 but nowhere else.
FE00 LD   IX,4000  FE04 LD   DE,1C00  FE07 SCF  FE08 LD   HL,FE11  FE0B LD   (FF09),HL  FE0E JP   FF00  FE11 LD   A,(5B24)  FE14 CP   FF  FE16 JR   Z,FE1B  FE18 <breakpoint>  FE1B LD   A,28  FE1D LD   (5B23),A  FE20 LD   A,FE  FE22 LD   (5B24),A  FE25 JP   5B00  FE28 LD   (FEF0),SP  FE2C LD   SP,(FEF2)  FE30 PUSH IX  FE32 PUSH DE  FE33 LD   (FEF2),SP  FE37 LD   SP,(FEF0)  FE3B LD   A,IXH  FE3D CP   5B  FE3F JR   NZ,FE4E  FE41 LD   A,DD  FE43 LD   (FF58),A  FE46 LD   A,75  FE48 LD   (FF59),A  FE4B JP   FF70  FE4E XOR  A  FE4F LD   (FF58),A  FE52 LD   (FF59),A  FE55 JP   FF70  
Before using this routine, POKE 65266,254 so that you know where the stack is. To find out where the game loads to:
10 FOR F=65020 TO 0 STEP -4: IF PEEK F THEN PRINT PEEK (F+2)+256*PEEK (F+3);",";PEEK F+256*PEEK (F+1): NEXT F  
The program will give you the following results:
56320,6232  61000,2000  64900,400  23296,100  65455,48  23324,2  39936,16384  23324,5  23296,256  63000,800  64000,1000  23552,16384  23324,2  23296,92  
As you can see, 23296 is loaded over a few times, but loading continues. We can therefore assume that these blocks do not alter the code there in any way, or at least if they do, not sufficiently enough to worry about. Loading finished when that block of 92 bytes was loaded, so this must be different. One disassembly later....
5B00 XOR  A  5B01 OUT  (FE),A  5B03 LD   HL,F870  5B06 LD   DE,F870  5B09 LD   BC,9470  5B0C LD   IX,5AFF  5B10 LD   A,FF  5B12 LD   R,A  5B14 LD   A,(HL)  5B15 SUB  (IX+0)  5B18 XOR  IYL  5B1A RLCA  5B1B XOR  IYH  5B1D LD   (DE),A  5B1E DEC  HL  5B1F DEC  DE  5B20 DEC  BC  5B21 DEC  IX  5B23 LD   A,IXH  5B25 OR   IXL  5B27 JR   NZ,5B2C  5B29 LD   IXH,5A  5B2C LD   A,B  5B2D OR   C  5B2E JR   NZ,5B14  5B30 LD   HL,F8D4  5B33 LD   DE,5B01  5B36 LD   BC,00FF  5B39 LD   SP,5FB4  5B3C PUSH HL  5B3D LD   HL,5B00  5B40 LD   A,C9  5B42 LD   (HL),A  5B43 LDIR  
This routine firstly decrypts the game, then sets the stack pointer and PUSHes the return address for the game (the PUSH at 5B3C), then fills the printer buffer with RETs. To stick pokes in, simply move them down into 5B3D, then stick a RET at the end to start the game.

The Chimera Hack
This routine loads the basic, then moves the decrypter to a convenient address. Once there, the JR NZ at the end is put in manually, then the entry values are put in and it is CALLed. It then puts a RET at the end of the routine which creates the turboloader and CALLs it, and once in memory the return address is patched and it starts loading. After each short headerless and leaderless block is loaded, it checks a value in the printer buffer to check whether or not the game decrypter is there - if it is then loading must have finished and the infy lives pokes are stuck on the end of the decrypter. Otherwise, control is returned to 5B00 so that the next block can be loaded. The routine is ORGed to 63801, because this is a safe place which never gets loaded over (as can be seen by the table of load addresses). Note that before the game decrypter is run, the hacking routine is deleted, because the game is decrypted through it.
       ORG  63801  LOAD   LD   IX,#5CCB         LD   DE,355         LD   A,#FF         SCF         CALL #556               ;Load basic with a standard headerless load         JR   NC,LOAD            ;Go back if load unsuccessful         LD   HL,#5D99           ;Start of decrypter         LD   DE,#4600           ;Bung it in the screen because it will be safe         LD   BC,#17             ;Length of decrypter         LDIR                    ;Copy it down         EX   DE,HL              ;HL is now the end of the copy         LD   (HL),#20           ;20 is code for jr nz         INC  HL                 ;Point to next address         LD   (HL),#ED           ;Offset for the jr nz         INC  HL                 ;Point to next address         LD   (HL),#C9           ;Stick a ret on the end         LD   HL,#5DB0           ;Initial value of HL         LD   BC,#5D73           ;Initial value of BC         LD   DE,#CA4E           ;Initial value of DE         CALL #4600              ;Do the decrypter         LD   A,#C9              ;C9 is code for ret         LD   (#5DF0),A          ;Stick a ret at the end of the turboload creator         CALL #5DB9              ;Create the turboload         LD   HL,NEWRET          ;Patch in a new return address         LD   (#FF09),HL         ;The patch is at ff09         LD   SP,0               ;Initial value of SP         JP   #FF00              ;Start loading  NEWRET LD   A,(#5B32)          ;See if there's any code here         CP   #F8                ;Check if the byte at 5B32 is a F8         JP   NZ,#5B00           ;If not, load another block         LD   HL,POKES           ;Otherwise copy the pokes down         LD   DE,#5B3D         LD   BC,END-POKES         LDIR         JP   #5B3D+DELETE-POKES ;Need to delete this routine before decrypting the game  POKES  XOR  A                  ;A=0         LD   H,A         LD   L,A                ;HL=A=0         LD   (#E6EE),A          ;Infy time poke         LD   (#EE20),HL         ;Infy food poke         LD   (#EDF1),A          LD   (#EF9C),HL         ;Infy water pokes         RET                     ;To the game  DELETE LD   HL,63801           ;Start of this routine         LD   DE,63802           ;Next byte         LD   BC,END-63801       ;Length of routine         LD   (HL),0             ;Put a 0 in at the start         LDIR                    ;Delete the rest of it         JP   #5B00              ;You can now decrypt the game  END    EQU  $  



Well, that's another one down. Between now and next month, get hold of a copy of MoonStrike, because I'm going to go through the Movieload on it (be warned though, it's quite a tough nut to crack). Ideas, probs, offers of dates and unwanted +3's should be sent to Jon's Hacking Bit at the usual YS address. See you next month.

 

 

Issue 65

I've put MovieLoad on ice this month, to concentrate on some more of your letters. I'll do it next month (or maybe not, we'll see).


Is Your * Key Stuck?
Stephen Gregory of Derbyshire wants to know what the * means in front of *Load and *List. These two are not basic commands, but listings I gave in issue 56. You'll need them both to hack just about anything. *Load loads a basic program and stops it autorunning, and *List lists the program as it would be run (because it's possible to disguise basic so that it LISTs differently to how it RUNs).

Where's The Game?
Loads of you have written asking the simple question, how do you load a game and disassembler at the same time? For old games, which start at 32768, you can load the game code to it's normal address and load Devpac in low memory (about 25000ish). Remember that Devpac will execute wherever you load it to - it relocates itself! On larger games, which use all the memory, load the game then load Devpac in either low memory (about 25000ish) or high memory (about 60000ish). That way, you'll be more likely to overwrite graphic and map data rather than the all-important game code. The ideal set-up should be Devpac for hacking protection systems, and a Multiface and Genie, or SoftRom and SoftCrack to hack games - for hacking games you only need a very limited disassembler, but the advanced features of Devpac make it ideal for protection.
One last point for anyone hacking the new Speedlocks (5 upwards). Check the CALL address in the routine which loads the first short turboload block. That address is later overwritten with a very simple game decrypter, which you will need to crack before you can hack the game (it usually resides around FE5Cish). And don't forget to check if the game is moved when loaded - you won't be able to backtrack if you don't move it to where it should be.

Will Steven Adams Please Stand Up
For anyone not born in the stone age, Steve Adams used to write a technical column in Your Spectrum. He once said something about a 32K RAM-bank hardware switch, which is needed by Stephen Shepherd of 50 Lincoln Street, Norwich, Norfolk NR2 3LA. Stephen may well be flooding the market with SoftRoms in the not-too-distant future, but needs Steve Adams' RAM-bank switch to get them working. If anyone knows where he is, or for more information and prices on the SoftRoms, contact Stephen at the address given.

Why Not Do A Machine Code Course?
There were a number of people asking this one. The simple reason is that it would be too long. If I started one now it would probably go on well into the 23rd century! I've been outlining the most important instructions which you'll need for hacking games, but to start writing them instead your best bet is to buy a good book on the subject. The best one I know of, Spectrum Machine Language For The Absolute Beginner, is now sadly out of print (you could always try an ad in Input Output), but whatever you do, don't get the Rodnay Zaks book - not yet. It's a very technical book which will later prove invaluable, but to learn machine code it is not the obvious choice.

How Are Load And Save Routines Related?
A couple of you thought that the timings of the instructions was all-important, but they are negligable. What are important are the values in the delay loops. These wait for a specific amount of time before doing anything - the smaller they are, the faster the load/save. Have a hack into the turboload on my POKE tapes - it copies the ROM loader then alters these timing constants to load and save in about two thirds of the normal time. Get the relationship between the original values and the new values (basically, multiply each by 2/3) and you'll have your own turbo tape system.

How Are Encrypters And Decrypters related?
An encrypter does the opposite of a decrypter. A decrypter with SUB would be encrypted with ADD, a RLCA (rotate left) with a RRCA (rotate right), and XOR with XOR. Non-trailers can start with the same values in both encrypters and decrypters, but trailers have to start at the last byte and work backwards.

Example
Decrypter

     LD   HL,50000 ;Start       LD   BC,10000 ;Length  LOOP LD   A,(HL)       XOR  H       SUB  L       RLCA       ADD  A,C       LD   (HL),A       INC  HL       DEC  BC       LD   A,B       OR   C       JR   NZ,LOOP       RET  
Encrypter
     LD   HL,50000       LD   BC,10000  LOOP LD   A,(HL)       SUB   C       ;Do the last decrypting instruction first. SUB is opposite to ADD       RRCA          ;Opposite to RLCA       ADD  A,L      ;Opposite to SUB L       XOR  H        ;Opposite to XOR H       LD   (HL),A   ;The rest is the same       INC  HL       DEC  BC       LD   A,B       OR   C       JR   NZ,LOOP       RET  

How Do You Do Speedlock 4?
This should have gone in a couple of months ago, but ended up in the bin instead. Sorry! It's the start of the Speedlock series where identification starts getting difficult.

(continues in Issue 62)

 

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: <breakpoint>. When control returns, examine (6000) and (6001) to find the value of SP (which should be 0F78).
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.
      ORG  33000  LOAD  LD   IX,#5CCB        LD   DE,2410        LD   A,#FF        SCF        CALL #556        JR   NC,LOAD        DI        LD   SP,33000        LD   HL,#5E0C        LD   (HL),#C9        INC  HL        INC  HL        LD   DE,#F807        LD   BC,#7E5  DCR1  CALL #5DFD        JP   PE,DCR1        LD   HL,#F81B        LD   (HL),#C9        INC  HL        INC  HL        LD   BC,#7C4        LD   A,#1F  DCR2  CALL #F817        JP   PE,DCR2        LD   HL,#F8DE        LD   DE,#A000        LD   BC,39        LDIR        EX   DE,HL        LD   (HL),222        INC  HL        LD   (HL),#C9        LD   HL,#F905        LD   BC,#6DC        LD   A,#84        LD   R,A  DCR3  CALL #A000        LD   SP,STACK  DCR4  POP  HL        POP  DE        POP  BC        LD   A,#8E        LD   R,A        RET  DCR5  POP  HL        POP  DE        POP  BC        LD   A,#8B        LD   R,A        RET  DCR6  POP  HL        POP  DE        POP  BC        LD   A,#D2        LD   R,A        CALL #F3F9        LD   HL,POKES        LD   DE,65000        LD   BC,END-POKES        LD   (#F8D7),DE        LDIR        LD   SP,0        JP   #F408  STACK DEFW #F946,#F47F,#69B,#FF98,DCR5        DEFW #F47F,#F382,#55A,#FA18,DCR6        DEFW #F40B,#F408,#4D1  POKES LD   A,#C9        LD   (#98ED),A        JP   #F8A1  END   EQU  $

 

Issue 67

This month sees the long-awaited Search loader, used on games such as Rana Rama, Deflektor, City Slicker, Costa Capers and, more recently, Shadow of the Beast. I'm doing Rana Rama as an example because it's just been re-released by Players.


Getting Started
What you'll need for this one is a disassembler, Multiface with Genie and a stopwatch (you'll find out why in a mo). Firstly, *Load and *List as usual.

Rana Rama LINE 0 LEN 320  0 RANDOMIZE USR 2377930000  32768-4.5078551E+32 RESTORE STOP READ - LLIST .....  
Line zero looks impossible, but it's just two numbers next to each other (23779 and 30000) with nothing to seperate them. Therefore the only basic instruction carried out by the loader is that simple RANDOMIZE USR 23779, which is 5CE3 hex.
5CE3 LD   BC,0117  5CE6 LD   DE,E833  5CE9 LD   HL,5CF4  5CEC LD   SP,5C00  5CEF LDIR  5CF1 JP   E856  
This just copies the loading system up to where it should be and runs it from there. Notice that it's left completely unprotected - the only decrypters in this entire system are right at the end, for the game itself.
E856 LD   HL,4000  E859 LD   DE,4001  E85C LD   BC,1AFF  E85F LD   (HL),L  E860 LDIR  E862 LD   A,08  E864 IN   A,(FE)  E866 LD   B,03  E868 LD   HL,3D00  E86B LD   D,EE  E86D LD   E,C  E86E LDIR  E870 DI  E871 CALL E886  E874 JP   NC,0000  E877 LD   H,00  E879 LD   IX,E94A  E87D LD   DE,00F2  E880 CALL E917  E883 JP   EA29  
E856-E865 just makes the screen and border black. Then it makes a copy of the ROM's character set in RAM (which will be used to bring up those funny little messages while the game loads) and then loads the leader tone (the short continuous tone at the start of the following headerless block). Then it loads F2 bytes starting at E94A (standard headerless load at E879) and JP's to it. If you try and disassemble it now, you'll see there's nothing there - it hasn't been loaded yet. All you need to do is stick a breakpoint at E883 and return control to E856 (to start the load).
EA29 LD   A,08  EA2B LD   (E833),A  EA2E LD   A,(E838)  EA31 SET  1,A  EA33 LD   (E838),A  EA36 LD   DE,0072  EA39 CALL E917  
This is similar to what you've already cracked. There's a LD DE at EA36, then a CALL to the headerless loader. IX is already EA3C (from the end of the previous load), but there isn't a JP - it just carries on. To retain control, change the CALL E917 to CALL a convenient address, where you have put CALL E917 followed by a breakpoint. Now set control BACK TO E856, because remember that each of these short headerless blocks is just one big block on the tape, so you'll have to write a little routine somewhere and run that instead.
      LD   HL,LOAD1        LD   (#E884),HL        JP   #E856  LOAD1 PUSH HL        LD   HL,LOAD2        LD   (#EA3A),HL        POP  HL        JP   #EA29  LOAD2 CALL #E917        <breakpoint>  
Notice that I PUSHed and POPed HL each time I used it, because we don't know whether it will be needed by the loading system or not. When control returns to the disassembler, you can see the following code at EA3C.
EA3C LD   A,(E838)  EA3F SET  0,A  EA41 LD   (E838),A  EA44 LD   DE,01CB  EA47 CALL E917  EA4A JP   EBE2  
This is the same sort of thing as we had last time. In place of the breakpoint in the routine we're using, stick this code:
      PUSH HL        LD   HL,LOAD3        LD   (#EA4B),HL        POP  HL        RET  LOAD3 <breakpoint>  
When control comes back, examine the code at EBE2.
EBE2 LD   A,(E838)  EBE5 SET  1,A  EBE7 LD   (E838),A  EBEA LD   A,(EC74)  EBED LD   (E839),A  EBF0 LD   DE,5800  EBF3 LD   (E83A),DE  EBF7 XOR  A  EBF8 LD   (E83C),A  EBFB LD   DE,(EC72)  EBFF LD   (E83F),DE  EC03 LD   IX,EE00  EC07 LD   DE,(EC70)  EC0B CALL E917  EC0E LD   IX,4000  EC12 LD   DE,2000  EC15 CALL E917  EC18 LD   IX,5800  EC1C LD   DE,0200  EC1F CALL E917  EC22 LD   IX,(EC75)  EC26 LD   DE,(EC77)  EC2A PUSH IX  EC2C CALL E917  EC2F RET  
This does a lot of buggering about, but the outcome is that the screen piccy is loaded (EC0E-EC21) and then the game block (EC22-EC2E) which is RETed to. To keep control, simply POKE that PUSH IX at EC2B with zero, then CALL EBE2 (which is exactly what the game hack is going to do). Make sure though that you check (EC75) and (EC76) because they hold the return address for the game. The values are 5A and 66 respectively, so the game starts at 665A. To get it in, add a few lines of code to that hacking routine so that, instead of a breakpoint after LOAD3 it puts a zero into EC2B, CALLs EBE2 then NEWs to about 6600ish (the NEW routine is DI:XOR A:LD DE,address to new to: JP #11B7). Don't put a breakpoint there instead because it's more than likely your disassembler will be loaded over. When it NEWs, load you disassembler back in and have a gander at the code at 665A.
665A LD   HL,666D  665D LD   BC,7194  6660 LD   DE,8E6B  6663 PUSH DE  6664 ADD  HL,BC  6665 EX   DE,HL  6666 ADD  HL,BC  6667 EX   DE,HL  6668 DEC  HL  6669 DEC  DE  666A LDDR  666C RET  
This simply moves a block of code from 666D to 8E6B, it's length being 7194. Change the length to about 300ish (otherwise your disassembler will be moved too, causing a crash), and single-step through it. Now SAVE the code at 8E6B with SAVE "rana1"CODE 36459,768 and verify it. Now reset the machine and load the game normally with LOAD "". Get ready on your stopwatch, because once the counter reaches zero, you need to time how long it takes for the game to start. When you've got a time, reset the machine and load it again, but this time press your Multiface button just before the game tries to start, and disassemble 8E6B.
8E6B DI  8E6C LD   DE,0002  8E6F LD   HL,5B00  8E72 LD   BC,336B  8E75 LD   A,D  8E76 LD   (HL),A  8E77 ADD  A,A  8E78 ADD  A,A  8E79 ADD  A,A  8E7A ADD  A,A  8E7B ADD  A,A  8E7C ADD  A,D  8E7D ADD  A,L  8E7E ADD  A,0B  8E80 LD   D,A  8E81 INC  HL  8E82 DEC  BC  8E83 LD   A,B  8E84 OR   C  8E85 JP   NZ,8E75  8E88 LD   HL,FFFF  8E8B LD   BC,1  8E8D DEC  E  8E8E JR   NZ,8E75  8E90 LD   HL,4000  8E93 LD   BC,0001  8E96 LD   A,D  8E97 ADD  A,(HL)  8E98 ADD  HL,BC  8E99 JP   NC,8E97  8E9C JR   C,8ECA    8ECA LD   HL,8EB4  8ECD LD   (HL),ED  8ECF LD   BC,C10D  8ED2 CALL 8E9E    8E9E POP  HL  8E9F PUSH HL  8EA0 LD   E,B  8EA1 INC  HL  8EA2 LD   D,A  8EA3 ADD  A,A  8EA4 ADD  A,A  8EA5 ADD  A,A  8EA6 ADD  A,A  8EA7 ADD  A,D  8EA8 ADD  A,C  8EA9 XOR  (HL)  8EAA LD   (HL),A  8EAB DJNZ 8EA1  8EAD LD   B,E  8EAE POP  HL  8EAF ADD  A,(HL)  8EB0 LD   (HL),ED  8EB2 INC  HL  8EB3 JP   (HL)    8ED6 CALL 8E9E    8EDA DEC  B  8EDB DEC  B  8EDC CALL 8E9E    8EE0 CALL 8E9E    8EE4 LD   C,22  8EE6 CALL 8E9E    8EEA DEC  B  8EEB CALL 8E9E    8EEF DEC  B  8EF0 CALL 8E9E    8EF4 JR   8F01    8F01 LD   C,05  8F03 CALL 8EF6    8EF6 LD   HL,4000  8EF9 LD   B,L  8EFA ADD  A,(HL)  8EFB ADD  HL,BC  8EFC JP   NC,8EFA  8EFF JR   8EAE    8F07 INC  C  8F08 CALL 8E9E    8F0C CALL 8E9E    8F10 CALL 8EF6    8F14 LD   BC,870A  8F17 CALL 8E9E    8F1B CALL 8E9E    8F1F JR   8F30    8F30 INC  C  8F31 INC  C  8F32 CALL 8F21    8F21 LD   HL,4000  8F24 LD   B,L  8F25 ADD  A,(HL)  8F26 ADD  HL,BC  8F27 JP   NC,8F25  8F2A POP  HL  8F2B ADD  A,(HL)  8F2C LD   (HL),ED  8F2E INC  HL  8F2F JP   (HL)    8F36 LD   BC,1690  8F39 CALL 8E9E    8F3D CALL 8F21    8F41 INC  B  8F42 CALL 8EF6    8F46 CALL 8E9E    8F4A LD   D,00  8F4C LD   E,A  8F4D XOR  A  8F4E LD   (8F4B),A  8F51 LD   HL,4000  8F54 LD   BC,0001  8F57 LD   A,E  8F58 ADD  A,(HL)  8F59 LD   E,A  8F5A INC  HL  8F5B LD   A,D  8F5C ADC  A,(HL)  8F5D LD   D,A  8F5E ADD  HL,BC  8F5F JP   NC,8F57  8F62 EX   DE,HL  8F63 LD   DE,9009  8F66 LD   C,29  8F68 LD   B,H  8F69 LD   H,L  8F6A ADD  HL,BC  8F6B LD   A,(DE)  8F6C XOR  L  8F6D LD   (DE),A  8F6E LD   L,A  8F6F INC  DE  8F70 LD   A,(DE)  8F71 XOR  H  8F72 LD   (DE),A  8F73 INC  DE  8F74 LD   B,A  8F75 LD   A,E  8F76 CP   FF  8F78 JP   NZ,8F69  8F7B LD   A,D  8F7C CP   FF  8F7E JR   NZ,8F69  8F80 LD   H,B  8F81 LD   DE,A06E  8F84 ADD  HL,DE  8F85 LD   DE,0000  8F88 LD   (5C09),DE  8F8C LD   SP,5FB3  8F8F PUSH HL  8F90 LD   A,R  8F92 SET  7,A  8F94 LD   R,A  8F96 LD   A,CD  8F98 LD   DE,5FB4  8F9B LD   (BEE7),A  8F9E LD   (BEE8),DE  8FA2 LD   HL,8FC9  8FA5 LD   BC,000A  8FA8 LDIR  8FAA LD   HL,9009  8FAD LD   DE,61A9  8FB0 LD   BC,1E57  8FB3 LDIR  8FB5 LD   DE,A500  8FB8 LD   BC,3EA0  8FBB LDIR  8FBD LD   HL,8000  8FC0 LD   DE,8001  8FC3 LD   BC,0FD2  8FC6 LD   (HL),L  8FC7 JR   8FD3    8FD3 LDIR  8FD5 RET    9009 DEFB C3,F7,C7,C0,61,60,67,0A  
Firstly, all the unused memory (336B bytes starting from 5B00) is filled with garbage, by the routine at 8E6B-8E8F. Then the whole memory is added together, including the screen, the garbage and the encrypted game, and a value retained in A. This value is kept for the whole of the game decryption. Virtually all the code from 8ECA to 8F46 consists of strange things happening to BC, followed by a CALL to 8E9E. Occasionally the memory is all added together again (by the routines at 8EF6 and 8F21) and the new value of A used. Finally, at 8F4A, the memory is added together one last time and a large value is kept for it in DE (8F51-8F61), which is used by the decrypter which follows to decrypt the game. A few blocks of code are moved about (8FA2-8FD4) and finally, the game is RETed to. Get a listing of all the code (from 8E6B right though to about 9010) then crash the game. Now load your disassembler and that small chunk of code you saved earlier - things are going to start getting interesting.

Decrypting The Game
First of all, tap in this bit of basic:
10 FOR F=40000 TO 40023  20 READ A: POKE F,A: NEXT F  30 DATA 62,0,33,213,142  40 DATA 17,0,200,1,0  50 DATA 1,237,176,33,0  60 DATA 200,1,13,193,205  70 DATA 160,142,0,201  80 FOR F=0 TO 255: POKE 40001,F  90 RANDOMIZE USR 40000  100 FOR G=51200 TO 51220  110 IF PEEK G=205 AND PEEK (G+1)=158 AND PEEK (G+2)=142 THEN PRINT F: STOP  120 NEXT G: NEXT F  
What this does it to move the code from 8ED5 to a convenient address, then decrypt it using every possible value of A. Once decrypted it looks at it to try and find a CALL 8E9E - if it finds one, it must have used the right value and prints it. RUN it and leave it for a while - after a few minutes it will return with 203 on the screen, which is CB hex. Go into your disassembler, give A the value CB, put a breakpoint at 8EB3 (just after the decrypter) and give control to 8ECA. It returns with A=21 hex, so make a note. Now put another breakpoint at 8EB3, return control to the disassembler and make a note of the new value of A (which is 55 hex). Keep going like that until you get to 8F08, because the whole memory is checked again at 8F02. Make a note of the value in BC (it's 6) and go back to basic. Put the following new values into the DATA statements and re-run that hack:
30 DATA 62,0,33,11,143  60 DATA 200,1,6,0,205  
When it returns, the value of A is 10, which is 0A hex. Do as you did before until 8F14, when another adding routine is executed. This time, HL is 8F1A (the address after the CALL 8E9E) and BC is 870A, so lines 30 and 60 should read:
30 DATA 62,0,33,26,143  60 DATA 200,1,10,135,205  
The new value of A is 14, which is 0E hex. The next time you use the basic is at 8F36, where HL is 8F3C and BC is 1690. The value returned in A is 168, which is A8 hex. You'll then need to do it one last time, for the CALL 8E9E at 8F46. HL is 8F49 and BC is 0090, but you'll need to change line 110 to check for something else, because there are no more CALL 8E9E's. Make it check for that LD HL,4000 at 8F51 by changing line 110 to read:
110 IF PEEK G=33 AND PEEK (G+1)=0 AND PEEK (G+2)=64 THEN PRINT F: STOP  
The value returned in A is 43, which is 2B hex. Patch that in as you have been, and then tackle that big game decrypter at the end.
10 FOR F=30000 TO 30034  20 READ A: POKE F,A: NEXT F  30 DATA 33,184,159,34,9,144  40 DATA 42,0,64,205,99,143  50 DATA 58,9,144,254,195,32,6  60 DATA 58,10,144,254,247,200  70 DATA 42,0,64,35,34,0,64,195,48,117  80 POKE 36731,201  90 RANDOMIZE USR 30000  
What this does is to put in the original values of B8 and 9F at 9009 and 900A (where the big decrypter starts from), then decrypt up to 90FF (I put the POKE 36731,201 in to make it RET after 90FF, otherwise it would go through the entire memory). Once it's done, it checks the new values of 9009 and 900A to see if they're what they should be if the right value had been used - if they are, the right value WAS used and it comes back to basic. Run it then PRINT PEEK 16384+256*PEEK 16385 to get the value - you'll see it's 5714. Now we know everything we need to write a hack for the game.

The Rana Rama Hack
This firstly loads the basic as a headerless file, to where it would be after the LDIR at 5CE3. Then it does exactly the same routine as we used earlier to load the game. Once loaded, it POKEs the PUSH DE at 6663 with zero, so that a CALL to 665A will move the code to the right place then return to our hack. When the code is where it should be, it sticks a JP back at 8E9E (the start of the decrypter) and sets IX to the start of a table of values. Then it JPs to 8ECA because we don't need to fill the memory with garbage or add it all up. When control comes back, it's from the start of the decrypter, so POP HL, PUSH HL and LD E,B are there because they were removed by the JP we put there. A is given it's correct value, from the table of values at the end (like the table of decrypter lengths in the Speedlock 2 and 3 hacks), and the value checked. If it's not 2B, it just JPs back to the decrypter and waits for control to be returned by the next time the decrypter is used.
Otherwise, it just CALLs it (so that control will be returned afterwards). The RET to the game, at 8FD5, is replaced with a JP for the pokes, and the correct value of 5714 given to HL for the main decrypter at 8F63 (which is then JP'd to). Finally, in go the infy lives pokes and a RET to the game starts it playing. Note that there is a NOP after the CALL 8EA1, because when it's finished it returns to the address AFTER the one it's supposed to (by the POP HL: INC HL: JP (HL) at the end).
      ORG  23296      ;A definite safe place  LOAD  LD   IX,#E833-#5C4F+#5CCB        LD   DE,00320        LD   A,#FF        SCF        CALL #556        JR   NC,LOAD        LD   HL,BACK1        LD   (#E884),HL        LD   SP,#5C00        JP   #E856  BACK1 PUSH HL        LD   HL,BACK2        LD   (#EA3A),HL        POP  HL        JP   #EA29  BACK2 CALL #E917        PUSH HL        LD   HL,BACK3        LD   (#EA4B),HL        POP  HL        RET  BACK3 XOR  A        LD   (#EC2B),A        CALL #EBE2        ;the game has loaded now        XOR  A        LD   (#6663),A        CALL #665A        LD   A,#C3        LD   (8E9E),A        LD   HL,BACK4        LD   (#8E9F),HL        LD   IX,TABLE        JP   #8ECA  BACK4 POP  HL        PUSH HL        LD   E,B        LD   A,(IX)        INC  IX        CP   #2B        JP   NZ,#8EA1        CALL #8EA1        NOP        LD   A,#C3        LD   (#8FD5),A        LD   HL,BACK5        LD   (#8FD6),HL        LD   HL,05714        JP   #8F63  BACK5 ;STICK YOUR POKES HERE        RET  TABLE DEFB #CB,#21,#55,#F7,#BB,#B2,#25,#0A,#10,#F3,#0E,#75,#A8,#2B

 

Issue 68

This issue marks the end of this series, because I've more or less covered everything that I wanted to. There are just a few things left to clear up, so I thought I'd do them as a question-and-answer type of thing. Oh, and there are some pointers for the Search loader and Alkatrazz in there too.


A Few Questions

Is Your * Key Stuck?
Stephen Gregory of Derbyshire wants to know what the * means in front of *Load and *List. These two are not basic commands, but listings I gave in issue 56. You'll need them both to hack just about anything. *Load loads a basic program and stops it autorunning, and *List lists the program as it would be run (because it's possible to disguise basic so that it LISTs differently to how it RUNs).

Where's The Game?
Loads of you have written asking the simple question, how do you load a game and disassembler at the same time? For old games, which start at 32768, you can load the game code to it's normal address and load Devpac in low memory (about 25000ish). Remember that Devpac will execute wherever you load it to - it relocates itself! On larger games, which use all the memory, load the game then load Devpac in either low memory (about 25000ish) or high memory (about 60000ish). That way, you'll be more likely to overwrite graphic and map data rather than the all-important game code. The ideal set-up should be Devpac for hacking protection systems, and a Multiface and Genie, or SoftRom and SoftCrack to hack games - for hacking games you only need a very limited disassembler, but the advanced features of Devpac make it ideal for protection.
One last point for anyone hacking the new Speedlocks (5 upwards). Check the CALL address in the routine which loads the first short turboload block. That address is later overwritten with a very simple game decrypter, which you will need to crack before you can hack the game (it usually resides around FE5Cish). And don't forget to check if the game is moved when loaded - you won't be able to backtrack if you don't move it to where it should be.


HOW DO YOU FIND TIME POKES?
There are two ways of hacking infy time. Firstly, backtrack from the Game Over message and simply remove all JPs and CALLs to it, and that will make the counter loop back to it's highest value when it reaches zero. Alternatively, slap on your Multiface button and check the value of I (a special register used for Interrupt Mode 2). Go to the page number that I dictates (eg. if I is 9C, then check 9C00) and check the contents. Whatever is at that address, go to where it points by typing it twice (eg. if (9C00) is 9D, check 9D9D). It will probably be a JP to another routine. Check this other routine and play around with it (maybe take a CALL out of it or something). Somewhere in that routine is the code to decrease the timer, because interrupts work in real time (50 every second) so it's ideal.


NOTES ON ALKATRAZZ
Basically, Alkatrazz is dead easy as long as you can handle R-reg decrypters. The only thing it is notorious for is it's length - an average Alkatrazz game has about 150-200 decrypters. The basic has about 10 or 20 standard decrypters with nothing to worry about. The turboloader to load the first short turbo block overloads itself and changes while its doing it, so watch out for that. Three NOPs toward the end are changed into a JP to the main decryption, so they'll need patching at some stage. The main decrypters have different endings and, like recent Speedlocks, use their own last byte as the first byte for decryption. They end in JP NZ, JR NZ, RET NZ and a few other variations, so make sure if you move them that you know what they're doing and where they're going. The main turboloader is easy to crack. There is a LDIR towards the end of it which blanks itself out once the game has loaded - simply replace it with your infy lives pokes and follow them with a RET to start the game.


NOTES ON THE SEARCH LOADER
First of all, that big headerless block is treated as a series of shorter blocks without leader tones (like Powerload and Softlock), but you need to hack each one so you'll have to keep going back to the start of the block each time. Don't worry though - there are only three or four you need to keep control over before you can access the game. The game decrypters work by filling all the unused memory with garbage, then adding the whole memory together (including the encrypted game) to get a value in A - this value is used to decrypt. The easiest way of overcoming it is to write a simple FOR-NEXT loop in Basic to move the code to be decrypted somewhere, and patch in every possible value of A. Check the code after it's been decrypted and see if it makes sense (if it's another CALL to the decrypter you've used the correct value of A). The main game decrypter works in a similar way but returns a value from the addition routine in HL (so it's anything from 0-65535, not 0-255).
The easiest way of getting the value of HL is with a Multiface and stopwatch. Load the game and time how long it takes to start, then reload and press your Multiface button just before - with a bit of luck you'll break in while it's in the middle of that decrypter and be able to just look at HL to find it's value. Your hack can load the game, stop the garbage routine (so you've got somewhere to put your hack) and patch in the correct values for those checksums (ie instead of letting it add all the memory to get a value for A or HL, just do LD A,nn or LD HL,nnnn in your hack followed by a CALL to the decrypter).


Is That It Then?
Yep, 'fraid so. That's it. If another juicy protection system comes out, I might do a one-off special. We'll see. If you've got any hacking probs, you can still drop me a line. The name's Jon North and the address, as ever, is How to Hack, YS, 30 Monmouth Street, Bath, Avon BA1 2BW. See you in the scrolly.