Before we get down to some serious hacking, it will be a good idea to know what we are looking for. Okay, I know that some of you may think that this is pointless, but if you don't know what you're aiming at, you'll never get anywhere.
Basically, we are going to examine a program, and change it so that certain instructions are altered so that the game becomes more easier to the user. This may be in the form of infinite lives, infinite energy, immunity, infinite bullets etc.
The only way we can hope to do this is to understand what is going on in the game. And because most games are written in machine code, we're going to have to understand that as well. Please don't be put off by the thought of learning a new language; in fact you need know very little machine code knowledge to hack most games.
To start with, we'll just look at infinite lives. Lives are normally a small number, between 3 and 9 (although some games may have more), and the common thing with all games that have lives is that somewhere in the game, the amount of lives are set as a definite number, and somewhere else, the amount of lives goes down by one. In order to get infinite lives, we would have to remove the command in the program which decreased a player's lives.
You probably have and idea about how a lives system would work in BASIC. Say if, for argument's sake, a BASIC game had three lives, you would expect to see something like...
100 LET LIVES=3
...contained in the program. Then, a bit further on, you'd expect to see...
500 LET LIVES=LIVES-1
In order to get infinite lives, we would simply remove line 500 altogether and RUN the program.
A similar idea appears in machine code, but the way it's done is slightly different.
For starters, machine code doesn't have any variables! You might therefore wonder how on earth the computer can store anything. In actual fact, the computer can store information anywhere in RAM, as you may well know, and this is exactly what happens in machine code.
In Chapter 24 ("The Memory") of the Spectrum manual, there's a detailed description of the Spectrum's memory. The best way to visualise the memory, I think, is to imagine 65,536 boxes, each one containing a piece of paper with a number from 0 to 255 written on it.
Therefore, it is no problem for a computer to store the number of lives in machine code, since it can just put it as a byte in a memory location, leave it there, and come back to it later.
You should be aware that in machine code, commands are also stored in memory locations as bytes; so if you get commands and data mixed up in memory, the computer could easily try and execute the data, thinking it's a command, and trying to execute it. Unlike BASIC, there are no errors in machine code, and the computer can execute anything it finds, so in this case you will get a crash. So most programs keep program data and program commands separately.
Anyway, in order to store three lives in machine code, we'd put the number 3 in a memory location. Unfortunately, we can't do this straight away in machine code, and we can only do it by using what are called registers.
Registers store information in the same way as memory locations. They are bit more versatile though, as you can perform calculations with them. All the same, they are not the same as variables in BASIC, and are more like a pair of hands used for counting.
The main register we'll look at for now is the A register (sometimes called the accumulator), which can store a single byte and have sums done to it.
What we would do to store the number three in a memory location is to put the number 3 into the A register, then put the contents of the A register (which are of course, 3) into a memory location.
The actual way of writing this in machine code is:
LD A,3 LD (#8000),A
Actually, strictly speaking, the above isn't machine code at all! Machine code as the computer sees it is, as I explained earlier, consists of many bytes in memory, which are pretty meaningless to humans. So some people invented assembly language (which is what the above is), where each instruction carried out by the computer is given a name (called a mnemonic).
The above program features one command used in two different ways. The command is LD, which is pronounced "load". This has nothing at all to do with loading a program from tape. It basically is a transfer of information from one place to another. The comma in the instructions is read as "with", so the whole instruction is read as "Load A with 3". It now seems obvious that this instruction is putting the number 3 into the A register.
The second command is also LD, but the way its used is slightly different. The brackets mean "the contents of", so the whole instruction is read as "load the contents of #8000 with A". (Think of a bracket as a byte in memory, where everything in the bracket is part of that byte). Therefore, this instruction would make the computer take whatever value is in the A register, and store it in memory location #8000 (of course, it could be any other memory location as long as it is unused).
So the overall result of the two commands (normally called operations) would be to put the number 3 in memory location #8000.
Congratulations! You've just learned the first way to hack. Clearly, if in a real program, we found these operations, we could change the LD A,3 to something like LD A,100 to get 100 lives!
Before we can do any "real" hacking, I'd better discuss how "real" machine code is written.
Every machine code instruction contains and opcode, and some instructions need an operand. An opcode is simply the instruction the computer is going to do. Every number from 0 to #FF correspondswith a specific opcode. You can find a complete list of opcodes in Appendix A of your Spectrum manual.
The operand is used whenever there is ambiguity over something. If you look in Appendix A of the Spectrum manual, you will see that the opcode #3E is "LD A,n". "n" in this case can mean any single byte number ie: a number from 0 to 255. But it's possible to put any number within this range eg: LD A,3 or LD A,#40 or LD A,#80 etc. The computer has to somehow know what data it is dealing with, and this is where the operand comes in. In machine code, whenever the computer comes across the opcode #3E, it looks at the byte after the opcode, and assumes it's the data needed. So, if the computer came across the bytes #3E and #40 in succession, it would put the value #40 in the A register. In this example, #3E is the opcode, while #40 is the operand. After executing the instruction, the computer goes to the byte after the operand, and starts running code from there.
In the second instruction of our example, the opcode is #32, ie: "LD (NN),A". The ambiguity is in the address where we are going to store the value of the A register. In this case, the operand takes up two bytes, hence the "NN", which again comes after the opcode. You should note that this is an address in memory, and is always referred to as two bytes. So you might expect the machine code equivalent of LD (#8000),A to be #32 #80 #00. Except it isn't! For some odd reason, in machine code, all two byte operands are written the wrong way round, so the actual machine code equivalent of LD (#8000),A is #32 #00 #80. There is no hard and fast reason why, it's just vitally important that you remember this.
In short, the program of the previous page is written as...
#3E #03 #32 #00 #80
...which takes up five bytes.
Not all instructions require operands. For example, DEC A (short for "decrease A", which subtracts one from the A register) has no ambiguity at all. There is only one way to decrease the value in the A register, so the instruction only takes up one byte, in this case #3D. No operands are needed.
Right, time for your first bit of hacking! From what we've discussed above, we want to find, somewhere in the game's code, a set of instructions which put the number of lives into a byte in memory. So if the game had three lives, we could expect to see the bytes...
#3E #03 #32
...unfortunately, we don't know where in memory the number of lives is going to go, so we can't work out the operands for the second instruction (#32). But in fact, we don't need to, for if we find the above sequence of bytes in a program, we can simply examine the two bytes after this sequence to find out where in memory the number is being put.
So let's put this into practice and hack an actual game. For convenience I've chosen Sweevo's World, which featured on a YS Covertape Issue 60 December 1990. I would have chosen a more recent game, but they all have some form of protection on them. Besides, obtaining infinite lives is relatively easy.
Getting the game in memory without it running is easy. If you've typed out a fair few POKEs in your time, this will be no problem. Just MERGE the BASIC loader and put a STOP statement before the RANDOMIZE USR statement. Then RUN the program and wait for it to load, until the OK message appears.
Now we have the game in memory, we can load STK and examine it. You have to be a bit careful here, because STK occupies 6K of the Spectrum's memory. Although it can be anywhere in memory, it possible to overwrite the all-important lives code in the game with STK, so we have to be careful. The best places to put STK are in the graphics, map or sound data. There's no easy way to tell where this is, so you'll have to try pot luck. But it helps if you know where the game loads to, so load up STK at any address, and press J and then Caps+9 to read in a header a couple of times. Then read the headers of the three blocks of code after the BASIC. They are:
Bytes: S 4000,1B00 Bytes: M FB90,043D Bytes: P 60E0,82B0
The first block is the loading screen. The second block is in actual fact the game's music (but you wouldn't be expected to know this), and the third block is the actual game itself. Therefore, we can put STK anywhere above (60E0+82B0)=E390. For argument's sake, let's put it at EA60, which is 60000 decimal. When we've finished hacking, we can reload "Bytes: M" and run the program. Load up STK (after having stopped the BASIC and returned with a STOP statement) at address 60000.
Now at last, some hacking. Bearing in mind that you start the game with five lives. Press Q to search for a byte. Enter the address we want to start searching at as 60E0, because that's the start of the game. Now type in the following: #3E #05 #32
These are the search bytes we described on the previous page. Keep pressing N for "next" until all of the memory has been searched. You will get the following addresses: 905C and EEDC. You can ignore the one at EEDC, because it's in the middle of STK and outside the main game code, so that leaves just the one at 905C. Press E for edit and type #905C. You'll see the following bytes:
3E 05 32 1A 61
So this tells us that the computer puts the number five in box number 611A (remember that 2 byte numbers are reversed!) Now to hack the game, we simply change the number 5 at 905D to any number of lives we want (the maximum is #FF).
Now, get out of STK, reload the "Bytes: M" file and RANDOMIZE USR 24800 (the original command in the BASIC), and hey presto - you will have whatever amount of lives you wanted!
All that remains to do is to write a proper hack for it. 905D is 36957 in decimal, so your hack would be something like "MERGE the BASIC loader, and insert POKE 36957,n before the RANDOMIZE USR statement, where 'n' is the number of lives."
And it's as simple as that. If you can understand what we've done so far, you're doing well, so stick at it. Any unprotected game like Sweevo's World is hacked in the same way, except you will probably have to reload STK to a different address, and you may find that in your search for #3e <lives> #32, you may come across several locations in memory outside STK that have this pattern. In this case, you'll have to use trial and error to work out which one holds the number of lives.
It is, of course, perfectly possible for you now to find 'number of lives' POKEs for any unprotected game under the sun, and in the early days of Spectrums ('82-'84), this would have been perfectly adequate. Of course, what your really need is the real nitty gritty - INFINITE lives. This is done by taking things just a step further.
What you basically need to do is find out which memory location the number of lives are being put in. Then you need to search for parts of the program which put the value of that memory location in a register, subtract one from it, and put the new value in the register back. Then you have to rewrite the code slightly so that the computer "forgets" to decrease the value in the register, and simply puts the old value back in again.
Coming back to Sweevo's World, we already know that the number of lives are stored at memory location 611A. I normally refer to this memory location as the "lives store" for obvious reasons. All we have to do is search for all the occurrences of the address of the lives store. So, search for #1A,#61, and you will find it referred to at the following addresses:
779B 8160 81A9 905F EEDC
You can ignore the one at EEDC because it's in STK, but you can also ignore the one at 905F, since that's part of the lives setting routine we discussed earlier. So the routine to decrease the number of lives must lie at one of the other locations.
You should note, that any instruction that involves the lives store will begin at the byte before, because 1A and 61 are two byte operands (see page 3 for more about operands).
So for starters, press E to edit an address and type in #779A. You'll see the following:
779A - 3A 1A 61 C3 61 99
If you look up 3A in Appendix A of your Spectrum manual, you'll see it corresponds to the instruction LD A,(NN). This is simply a reverse of the LD (NN),A instruction, in that the value of a memory location is put into the A register. This is important, because subtraction of any sort can only be done in a register, and usually in the A register.
After the computer has executed the three byte instruction 3A 1A 61 (which is LD A,(611A in mnemonics), it executes the instruction C3. If you look up C3 in Appendix A of your Spectrum manual, you'll see it corresponds to the instruction JP. JP is short for "jump", and is in a sense like GOTO in BASIC. What the computer does is to jump to a location in memory. As you can see, there is ambiguity as to where it is going to jump, so we need a two byte operand. Like the ones me have met before, the bytes are written the wrong way round. So C3 61 99 means JP 9961. In this case, the computer would go to address 9961, and start executing code from there.
It is possible that the code to decrease the number of lives is at 9961, but is unlikely, because it pointless to have to jump to a completely different area of memory. So we'll leave this part of memory, and go onto the next instruction, at 8160. Press EDIT to leave the editing procedure, and edit address 815F. You'll see the following:
815F - 21 1A 61 35
21 is the instruction LD HL,NN. HL is another register like A, but its main difference is that it can store two bytes at once. So LD HL,NN requires a two byte operand, whereas LD A,N only requires one. So here the instruction 21 1A 61 means LD HL,611A. The next instruction, 35 doesn't need any operands, and is the instruction we've been looking for. 35 means DEC (HL). You've already come across brackets meaning "the contents of", so as you might have guessed, DEC (HL) decreases whatever is at the memory location with the same number as HL by one. In this case, we know that HL is 611A, because we've just set it in the last instruction. So DEC (HL) will decrease the value of whatever is in memory location 611A by one in this case.
But we already know that the number of lives is stored at memory location 611A. So clearly DEC (HL) is going to decrease the number of lives by one!
What we need to do to make an infinite lives POKE is to somehow overwrite the DEC (HL) so that the computer doesn't decrease the number of lives. There are two things that can be done. Firstly the address containing DEC (HL) can be replaced by 0. The number 0 relates to an instruction called NOP. NOP is short for "No operand", and in short means absolutely nothing! When the computer encounters the instruction NOP, it will do nothing and execute the next instruction. So if we overwrite DEC (HL) with NOP, the computer won't decrease the number of lives, but do nothing instead. The vast majority of POKEs have the format POKE address,0 for the reasons described above.
If you run Sweevo's World changing the DEC (HL) to NOP, you'll find you only get one life instead of five! In this case, you should overwrite the DEC (HL) with OR (HL). OR (HL) is a single byte instruction, B6. Don't worry about what it does, because it isn't important. What is important is to remember to do this if you only get one life.
Rerun Sweevo's World, replacing the DEC (HL) with OR (HL), and you'll have your infinite lives! The DEC (HL) is at address 8162, which is 33122 decimal, while B6 is 182 decimal, so the POKE would go something like "MERGE the loader, and put POKE 33122,182 before the RANDOMIZE USR statement, RUN the program and restart the tape."
Now we've covered the rudiments of machine code involved in hacking, we can look at more detailed ways of finding POKEs.