Go back

PART 3 - EASY LOADING SYSTEMS

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.



[ Valid HTML4.01 ]
Free Web Hosting