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.
- What you'll need
- How to hack
- Working forwards
- Working backwards
- Not working at all
- 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.
- Revenge of the mutant cock-ups from hell
- Loading the first bit
- The *LOAD routine
- Disguising basic and getting past it
- The *LIST program
- Headerless files
- What a headerless loader looks like
- Issue 57 tells you what a decrypter is.
- Decrypters? What the...
- Why bother?
- How to recognise one?
- The R register
- Trailing decrypters
- A useful routine
- Decrypters? What the...
- 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
- Speedlock 1
- Issue 62 is the continuation of the special
- Speedlock 4
- Never-ending story
- The CPIR command
- The Arky II hack
- Speedlock 4
- 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...
- A few questions
- Is your * key stuck?
- Where's the game?
- How do you find time pokes?
- Notes on Alkatrazz
- Notes on the Search Loader
- Is that it then?
- A few questions
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 RETBecause 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,5C3ASo 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 A2D1etc. 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 876DPOKE the DEC (HL) with 0 (at 8545).
855E: LD (810D),AThere 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,HLetc. 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 10Surprise 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 JPThat'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 800You 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 REMTo 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 F000Taking 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 B110We 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),ATurning 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 142Now *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 FE80The 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 179When *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,5D1A5D00-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),AThis 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,5D44Before 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,5D985D51-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 RETThe 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 RETFirstly, 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 RETIf 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 5E27You 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 5E00The 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 RETThe 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,9C48To 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 FF07The 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 RETThe 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 LDIRThe 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 FE3EThe 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,FF8BYou 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 RETThis 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 RETThis 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).
- *Load the basic loader;
- POKE 23997,43: POKE 23998,45 to make it return to Basic;
- RANDOMIZE USR 23972 to load the main loader;
- POKE 40064,43: POKE 40065,45 to make it return to Basic;
- CLEAR 24150: RANDOMIZE USR 4e4 to load the game;
- CLEAR 65535 and either hack it in the normal way or enter your pokes.
- RANDOMIZE USR 50944 starts the game.
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:
- After a LD A,I; LD I,A; LD A,R; LD R,A if interrupts are disabled
- After a CPI; CPD; LDI LDD; CPIR; CPDR; LDIR; LDDR if BC=0
- After an AND; OR; XOR if there are an even number of set bits (ie 1's)
- After an ADD; SUB; INC; DEC if result is above 127 or below -128
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 PE62AC-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 FD24Firstly, 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 fIncidentally, 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 58616So 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 E4FDTo 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 E512As 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 E512Again, 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,E549The 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,E555This 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 E56AThis 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 E56AMove 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,E587Cracking 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 #8AF4This 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 58616The 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 DF19Crack 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 RETFirstly, 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 F1EEF1C9-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 F1FFYou 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 CPIRAfterwards, 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 EAA2Type 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 EABDCracking 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 EAECYou 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 EB7ACrack 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,FB28Crack 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,FB6FType 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,EF78Type 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 F8D3Final 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,F8E9To 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,5D85This 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,5D9FThis 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 HLThis 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 FF70This 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:
- The code at 5B00 gets overloaded, in which case control is returned to the new code
- 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
- The loaded value for IX is zero, in which case the loaded value for DE is RETed to.
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 FF70Before 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 FThe 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,92As 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 LDIRThis 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 RETEncrypter
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 2410You 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=5DE9A 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,DSo 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,#5DFDNote 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,#F815For 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 LDIRRip 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 LNow 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,AFor 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 SPThis 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 DEYou'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 #F8A1As 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 E856This 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 EA29E856-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 E917This 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 EBE2This 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 RETThis 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 RETThis 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,0AFirstly, 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 FWhat 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,205When 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,205The 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: STOPThe 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 30000What 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.