So far, you've worked out the all important basics of hacking. However, there is another, equally important facet of hacking games that you should know about.
Few games these days are unprotected. They feature "protection systems" which prevent you from breaking into a program and fiddling about with it. The difficulty level varies, but in general they use two concepts - headerless loading and decryption.
Before we do anything, I should point out that you're going to need a disassembler from now on. The machine code listings in this book use Devpac's notation, but 007 Disassembler's notation is almost identical, except it uses decimal instead of hex. Hopefully, you shouldn't get lost if you use
Anyway, for now, we'll forget about decryption and concentrate of headerless loaders, since they're common to all protection systems.
A headerless loader will look something like this:
DD 21 XX XX LD IX,XXXX 11 XX XX LD DE,XXXX 3E FF LD A,#FF 37 SCF CD 56 05 CALL #0556
...where XX can be any number from #00 to #FF. IX is another register similar to HL, but has slightly different properties, which you don't need to worry about right now. The value put into IX is always the start address of the block to be loaded, and the value put into DE is always the length of the block to be loaded. So the routine works exactly like loading and saving bytes in BASIC.
The only differences you should ever find are that the CALL is to a different address (#0556 is the ROM loading routine, so other CALLS are to turboloaders in RAM), the LD A,#FF has some other value loaded into A instead, or is missing, or the SCF is missing. Basically, if you see DD 21 XX XX 11 XX XX in a protection system, you can be pretty sure it will be used to load something.
Now we know how a headerless loader works, let's try and hack a real one. As an example, I've chosen Ethnipod, which was on the May 1991 YS Covertape.
First of all, load up STK at any address (I'd suggest 32768, but you don't have to) and press Z to BLOAD in the BASIC. Then use STK to list the basic, and you'll get the following:
10 BORDER 0: PAPER 0: INK 7: CLEAR 24999: LOAD "" CODE
65000: RANDOMIZE USR 65000
Therefore, we should type in CLEAR 24999:LOAD "" CODE 65000 and restart the tape. When the OK message appears, stop the tape, load up your disassembler, and have a look at address 65000 (#FDE8). Here's a complete disassembly of the code you'll find there.
FDE8 21 00 40 LD HL,#4000 FDEB 11 01 40 LD DE,#4001 FDEE 01 FF 1A LD BC,#1AFF FDF1 36 00 LD (HL),#00 FDF3 ED B0 LDIR
LDIR is a command we haven't met before, but it's easy to understand. It's a copying routine. The start address of the block you want to copy is put in HL, the length of the block you want to copy is put in BC, and the start address of the area of memory you want to copy it to is put in DE. So, in the example above, the area of memory from #4000 is copied to #4001 for #1AFF bytes. In short, this routine is overlaying each address in this area of memory with the byte of the previous address.
The LD (HL),00 means that byte #00 is put into address #4000. Therefore, the whole of the memory from #4000 to #5AFF is filled with 0. In case you didn't know, the whole of this memory is the screen memory, so this bit of code is what makes the screen black when loading the game normally. If you want, you can change the byte at #FDED to #00 to give LD DE,#0001, so the contents of the screen memory are copied into the ROM (except that they aren't because the ROM is a read-only memory and you can't write anything into it.) This will stop the screen going black. You don't actually need to do it at all, but there we go.
Continuting the disassembly:
FDF5 11 00 1B LD DE,#1B00 FDF8 DD 21 00 80 LD IX,#8000 FDFC 3E FF LD A,#FF FDFE 37 SCF FDFF CD 56 05 CALL #0556
This portion of code loads in a block of code, with the start #8000 and the length #1B00.
FE02 3E 00 LD A,#00 FE04 D3 FE OUT (#FE),A
This part of the code includes an OUT instruction, but OUT in machine code is exactly indentical to that in BASIC. So, this routine is basically the equivalent of OUT 254,0 in BASIC. If you don't know what that does, it sets the border to black.
FE06 11 00 40 LD DE,#4000 FE09 21 00 80 LD HL,#8000 FE0C 01 00 1B LD BC,#1B00 FE0F ED B0 LDIR
This is another LDIR, and it moves the code from #8000 to #4000 for #1B00 bytes. In other words, it copies the screen picture into the screen memory so you can see it.
FE11 11 60 9D LD DE,#9D60 FE14 DD 21 B4 5F LD IX,#5FB4 FE18 37 SCF FE19 3E FF LD A,#FF FE1B CD 56 05 CALL #0556
This part of code loads another block, with start 5FB4 and length 9D60.
FE1E C3 C7 61 JP 61C7
This part of the routine jumps to the game itself once it is loaded.
To hack the game, replace the C3 at FE1E with C9. This will put a RET at the end of all the code, so the loader will return to BASIC when all loading has finished.
When the OK message comes up, you can hack the game as you've done with unprotected games. If you load STK into address #6000 (24576 decimal), and hack the game using a forwards trace, you'll eventually find that changing #EF09 to 0 gives you infinite lives for player one. Then to start the game, type RANDOMIZE USR 25031 (61C7 in decimal), and bingo!
To write a hack, we need to rewrite the BASIC loader, but make the modifications so we can put POKEs in:
10 CLEAR 24999
20 LOAD "" CODE 65000
This comes directly from the BASIC loader and loads the small headerless loader code.
30 POKE 65054,201
This means that control will return to BASIC when all the headerless code has been loaded
40 RANDOMIZE USR 65000
This starts off the headerless loader.
50 POKE 61193,0
This is the infinite lives POKE
60 RANDOMIZE USR 25031
This starts the game itself. Easy when you know how!
Now we know how a simple headerless loader works, let's crack a turboloader. There are loads of YS covertape games which have a suitable loader, but I'm going to choose Pixy the Microdot 2, although you'll find that any YS game which uses blue, black and magenta stripes when loading is almost identical.
First of all, load up STK at address 58550 (you'll find out why later on), to find out what the BASIC loader has to say, using the same method as with Ethnipod. It starts running at line 0.
1 BORDER 0:PAPER 0:CLEAR 64999:LOAD "" CODE
2 RANDOMIZE USR 65146
20 CLEAR 64999:LOAD "mc" CODE:LOAD "pixldsy"
CODE:SAVE "t:":SAVE "PIXY" LINE 1:SAVE "x"
CODE 65146,200:LOAD "screen" SCREEN$:RANDOMIZE
USR 65000
The BASIC starts at line 1. The commands should be obvious to you. Type CLEAR 64999:LOAD "" CODE, start the tape, and load in the first block of code. Stop the tape when the OK message comes up.
Now load your disassembler and examine the code at 65146, which is FE7A hex.
FE7A F3 DI
DI is short for "disable interrupts". What are interrupts, I hear you ask? Well, imagine you're watching TV when suddenly, someone says "We interrupt this program to give you an important newsflash!" Then, after the newsflash, the program you were watching resumes. Well, computer interrupts work in exactly the same way. In fact, every fiftieth of a second, a program is "interrupted" by the computer, which then checks to see if you're pressing any keys, and resumes the original program. The command DI simply stops this happening, and your program continues without any interruption! This makes the program run faster. However, you CANNOT get back to BASIC by a RET command, because the computer won't be checking the keyboard, and so it has effectively locked up. To get round this, you must execute the command EI (enable interrupts) first, so control can be resumed. Don't worry about doing this now, though.
FE7B 31 60 61 LD SP,6160
This is a new instruction. SP (short for "stack pointer") is a 16-bit register, like BC, DE and HL. However, it's far more important as far as BASIC is concerned. In machine code, there are two ways of storing numbers. The first, using memory locations, we've already come across. However, there is another method by storing numbers on what is called a stack. Think of a stack as a big spike on which you can push pieces of paper with information on. Then, later on, you can take them off the stack and use them. If you think about it, if you put the numbers 1, 2 and 3 on the stack, in that order, you'll have to take 3 off first, then 2, then 1 (think about it). And it's the same in machine code. There are instructions which enable values of registers to be put on the stack, and which enable the value on the top of the stack to be taken off and put in a register.
The stack, like everything else, has to go somewhere in memory. The SP (stack pointer) register gives the address of the top of the stack. So LD SP,6160 will mean that the stack is to start at address 6160.
This is bad news if you want to return to BASIC, because the Spectrum's ROM program puts lots of information on the stack, so if you change the stack pointer, it's going to receive garbage when it takes all the values off what it thinks is the stack. And that, of course, will mean a crash. So the general rule is LEAVE THE STACK POINTER ALONE!
You can change the value of the stack pointer using CLEAR from BASIC. If a machine code instruction has LD SP,XXXX, you can type CLEAR (XXXX)-1. So here, we should CLEAR (#6160)-1 = #615F. Bear in mind that the value will have to be in decimal, which is 24927. So exit from STK, CLEAR 24927, and go back into it again. This will mean that later on we can do the EI / RET as described above. Then you have to remove the LD SP instruction, which is most easily done by changing FE7B to 21, so it reads LD HL,6160. This is harmless in this case.
Carrying on through the code....
FE7E DD 21 00 40 LD IX,4000 FE82 11 00 1B LD DE,1B00 FE85 CD 97 FE CALL FE97
As you can probably see, this loads a headerless block, the loading screen, in fact. However, you'll notice, as I said eariler, that some of the other commands (LD A,#FF and SCF) are missing, and the CALL goes to a different address. This is because it's a turboloader.
FE88 DD 21 60 61 LD IX,6160 FE8C 11 4B 83 LD DE,834B FE8F CD 97 FE CALL FE97
This loads another block, start 6160 and length 834B. This means, that all the memory from 6160 to E4AB will be overwritten. Fortunately, you loaded STK into address 58550, which is E4B6 hex, so it won't be overwritten. Clever, eh? Meanwhile....
FE92 30 F4 JR NC,FE88
Something I haven't told you yet is that after a headerless load, a JR NC will result in that JR if there is a tape loading error. So, if there was a tape loading error in loading this game, the JR NC,FE88 would be executed (so that computer would try and reload the block).
FE94 C3 60 61 JP 6160
This starts the main program running.
To crack the loader, therefore, POKE FE94 with FB (for EI) and FE95 with C9 (for RET), along with the modifications I've already told you about. Then RANDOMIZE USR 65146, and restart the tape (it is possible that you didn't stop the tape quickly enough the previous time, so you'll miss the turboload header, in which case wind back just before it). When the game has finished loading, an OK message will appear.
And that's it! Well, actually it's not, because the game is actually compressed, and needs to be unpacked first. Don't worry, because it's easy to hack. Go into STK again, and look at address 6160. You're looking for a JP instruction to the game, which is what is executed when the game is unpacked. You'll find it at 61A3. So POKE 61A3,FB and 61A4,C9 (for an EI / RET), and RANDOMIZE USR 24928. Wait a few seconds until BASIC returns. And there we are - you've cracked the loader!
You might be wondering how you can tell that the game is compressed. Well, there are two things. Firstly, the JP from the loader (6160) is to a very low address in the usuable RAM (which only starts at 5B00). But more noticeable, you won't be able to do a forwards trace or a backwards trace until you run the decompressor. In fact, in general, if you think you should be able to forwards trace or backwards trace a game for infinite lives, and haven't overloaded any important code with a disassembler, but nothing happens, its worth looking at the start of the code executed and seeing if there's a JP a bit later on to a completely different address.
So now, perhaps, we should write a complete hack for the game.
10 CLEAR 24927:LOAD "" CODE
This is from the BASIC loader and loads in the first block of code. We've changed the CLEAR though, so the stack is in the right place.
20 POKE 65147,33
This changes the LD SP,6160 into LD HL,6160 so the SP isn't tampered with.
30 POKE 65172,251:POKE 65173,201
This changes the JP 6160 to an EI / RET so control will return to our hack once the game has loaded.
40 RANDOMIZE USR 65146
This starts the game loading
50 POKE 24995,251:POKE 24996,201
This changes the JP 86CE to an EI / RET so control will return to our hack once the game has decompressed
60 RANDOMIZE USR 24928
This starts the game decompressor.
70 POKE 28402,0
This is the infinite lives POKE, which you'll find out when you do a forwards trace on the uncompressed game.
80 RANDOMIZE USR 34510
This is the start of the game.
Now that you've done that, why not crack another game which uses the same loader? They're nearly all the same, except some of the JP addresses will be different. And then when you've done that, why not have a look at some other headerless loaders - most games by Codemasters use them.
You will find, however, that you will sometimes have to overwrite some of the memory with your disassembler. There's no easy way to tell where it should be, I'm afraid, so you'll have to take pot luck. If your forwards trace and backwards trace are both unsuccessful, try loading the disassembler elsewhere in memory, or look to see if the game is compressed.