If you can understand everything we've done so far, you can now probably crack just about any budget game or YS covergame that's thrown at you. And indeed, you can probably get featured in "Practical POKEs" month in month out (like a load of anonymous hackers, I might add!) by using the knowledge you've got. However, if you want to become a hacking legend, you should have a go at some of the numerous commercial protection systems, which have been written by freelancers for software houses.
I think we're getting seriously into Multiface territory now, but I'll try and do as much as possible with only STK and 007 Disassembler.
I think I should also say that cracking commercial protection systems is NOT easy. The code is deliberately badly structured and obscurely coded to put you off, so you'll have to perservere. You really do need something like a Multiface or Devpac to crack some of these systems, because they can overwrite the system variabes in BASIC, and you sometimes need to know the values of certain registers, which is impossible to determine using BASIC. You'll also need some games other than YS stuff to hack, but fortunately, protection systems such as Speedlock or Alkatraz are so common, you're bound to have a game with one of them on. I'll be doing examples specific to one game, but you'll find that another game with the same protection is pretty much the same, except you're likely to find that some of the addresses will be different.
Before we start, I'd just like to point out that I'll be referring to the term "breakpoint" a lot. This is simply a small bit of code which will stop the program dead in its tracks. Using DEVPAC, you just press the W key. On a Multiface, you do the same as a stack trace, by writing down the two bytes at the place you want to put a breakpoint, then replacing them with #18 and #FE. If you are using 007 disassembler and/or STK, you'll need to put a jump to the start of the program (#C3 #00 #40 for 007 disassembler; STK varies depending on where you put it).
So let's start with something relatively simple....
BLEEPLOAD
"Bleepload" first appeared on Firebird games around March 1987, and was used by them on every release by them from then on until their demise in 1989. It emulates a BBC loading system in that each file loads in a series of blocks, which are numbered in hexadecimal. The hardness is not because it uses non standard code, it's just that it jumps around so much in memory you need to put in an awful lot of software patches. I'll be hacking Bubble Bobble as an example.
First of all, load in *Hack, and load in the BASIC loader.
Bubble LINE 10 LEN 179
10 REMThere is absolutely nothing difficult about this BASIC loader, so just type CLEAR 50000:LOAD "" CODE and start the tape to load the first block of code. Stop the tape when it's loaded, and load in your disassembler into address 32768 (it's a safe one), and have a look at the code at CD00.
CD00 3A 5C 5B LD A,(#5B5C) CD03 32 00 60 LD (#6000),A
This takes the byte at #5B5C and puts it in #6000. #5B5C is the system variable for the 128K page number, in case you're interested.
CD06 3E 02 LD A,#02 CD08 CD 01 16 CALL #1601
This is a standard ROM routine, and all it does it to tell the computer we want to print something on the screen.
CD0B AF XOR A CD0C 32 6B 5C LD (#5C6B),A
As you may be aware, poking #5C6B (23659 decimal) with 0 will cause the computer to crash if you press BREAK or return to BASIC. So POKE CD0E,0 which changes it to LD (#006B),A; this is harmless.
CD0F CD CE CE CALL #CECE
The routine at #CECE prints the message "Searching" on screen.
CD12 10 09 DJNZ #CD1D
We haven't come across the command DJNZ before. It basically means "decrease the value in the B register, and jump if B is not zero."
CD14 11 08 FF LD DE,#FF08 CD17 16 00 LD D,0 CD19 CD 1A CE CALL #CEA1
This routine prints the number 00 on screen.
CD1C 3E 08 LD A,#08 CD1E 32 15 FF LD (#FF15),A CD21 CD 74 CD CALL #CD74
This routine loads in a block of code from tape (in actual fact the start address is #FE00 and its length is #100 bytes).
CD24 3E 00 FA LD A,(#FE00) CD27 FE 64 CP #64 CD29 20 F6 JR NZ,#CD21
This routine loads A with the value at #FE00. The CP instruction compares the value in the A register with something, in this case the number #64. If there is no match, the routine jumps back to #CD21, otherwise it continues. This routine actually checks to see if the block is found.
CD2B 3A 01 FF LD A,(#FF01) CD2E BA CP D CD2F 28 05 JR Z,#CD36
This routine checks to see if the block has been loaded successfully. If so, it jumps to #CD36, otherwise it continues.
CD31 CD 84 CE CALL #CE84 CD34 18 EB JP #CD21
This routine prints up the "loading error" message, and attemps to load the block again.
CD36 CD 30 CE CALL #CE30
The routine at #CE30 is a decrypter (have a look - do you see why?), which decrypts the block loaded in ie: from #FE00 to FEFF. You don't need to crack it yourself.
CD39 BE CP (HL) CD3A 28 05 JR Z,#CD41
This routine reloads the block if the value of A equals the value at (HL). Don't ask me why.
CD41 CD 5F CD CALL #CD5F
This routine moves the code at #FE00 to where it should really be in memory.
CD44 CD 5D CE CALL #CE5D
This routine prints the "loading" message on the screen, but this should in actual fact be "loaded", because the block has just been read in at this point of the code.
CD47 21 04 FF LD HL,#FF04 CD4A 7E LD A,(HL) CD4B 23 INC HL CD4C 3D DEC A CD4D 20 FC JR NZ,#CD4B CD4F 23 INC HL CD50 23 INC HL CD51 23 INC HL CD52 23 INC HL CD53 7E LD A,(HL) CD54 2B DEC HL CD55 2B DEC HL CD56 2B DEC HL CD57 E6 07 AND #07 CD59 3C INC A CD5A 32 15 FF LD (#FF15),A CD5D 14 INC D CD5E E9 JP (HL)
This routine starts off with HL as FF04, then does a lot of sums, and comes out with a value in the HL register, which it jumps to after its loaded the block. This is what we need to hack. So POKE CD5E with C9 and RANDOMIZE USR 52480 - you'll find out it loads in one block and then stops. However, this isn't much use as you can't find out the value of the HL register. So put this routine somewhere, such as #5B00.
5B00 CD 00 CD CALL #CD00 5B03 22 10 5B LD (#5B10),HL 5B06 C9 RET
This routine simply loads the first block, and puts the value of HL in #5B10 so we can find out what it is from BASIC. Now rewind the tape before the first Bleepload block again, and RANDOMIZE USR 23296. When that's finished, type PRINT PEEK 23312+256*PEEK 23313. You should get the answer 65293, which is #FF0D. Disassemble this address.
FF0D C3 21 CD JP #CD21
This will go back and load the next block from tape. We can crack it in the same way as the first be changing our routine at 5B00.
5B00 CD 00 CD CALL #CD00 5B03 CD 21 CD CALL #CD21 5B06 22 10 5B LD (#5B10),HL 5B09 C9 RET
Now wind the tape back to the first Bleepload block again, RANDOMIZE USR 23296 and start the tape. When the OK message comes up, type PRINT PEEK 23312+256*PEEK 23313, and you should get 65286 which is FF06 hex. Disassemble this address.
FF06 C3 21 CD JP #CD21
This goes back and loads another block. By now, you might have guessed that the value of HL will always contain the address of a JP #CD21 instruction - except for the last block which will jump elsewhere. Now we can write a routine which will load any block as long as it jumps to #CD21 at the end. I'm putting the routine at #CCEC, because it's right next to the loading system, and hence is unlikely to be overloaded (although it could be, in which case we'd just put the routine elsewhere). The routine goes like this.
CCEC CD 00 CD CALL #CD00
This is just loading the first block
CCEF CD 21 CD CALL #CD21
This loads in a block from tape.
CCF0 23 INC HL CCF1 7E LD A,(HL) CCF2 2B DEC HL
This routine loads the A register with the value of (HL+1). This will be #21 if another block is to be loaded.
CCF3 FE 21 CP #21 CCF5 20 02 JR NZ,#CCF8 CCF6 18 F7 JR #CCEF
This compares the value in the A register to 21. If there is no match, then the routine jumps to the end to preserve the value of HL, and to return to BASIC. Otherwise, it goes back to load another block.
CCF8 22 FE CC LD (#CCFE),HL CCFB <breakpoint>
This puts the value of HL in address #CCFE, then returns to control of the disassembler.
Now, run this routine (RANDOMIZE USR 52463), rewind to the first Bleepload block, and start loading. The program will now load blocks 00-2D, and return to control of the disassembler. The value at #CCFE is #FF06, so disassemble this address.
FF06 C3 00 5B JP #5B00
Now disassemble #5B00, which is the real meat of the loading system!
5B00 DD E5 PUSH IX 5B02 CD 74 CD CALL #CD74 5B05 CD 30 CE CALL #CE30 5B08 28 07 JR Z,#5B12 5B0B 06 00 LD B,#00 5B0D CD 84 CE CALL #CE84 5B10 18 F0 JR #5B02
This routine loads in another block of code, and will jump to 5B12 when it has been successfully loaded.
5B12 F3 DI 5B13 E1 POP HL 5B14 2E 00 LD L,#00 5B16 ED 5B E7 FE LD DE,(#FEE7) 5B1A 1A LD A,(#DE) 5B1B AE XOR (HL) 5B1C 24 INC H 5B1D AE XOR (HL) 5B1E 25 DEC H 5B1F 12 LD (#DE),A 5B20 2C INC L 5B21 IC INC E 5B22 20 F6 JR NZ,#5B1A
This routine is a decrypter, which decrypts some of the code we just loaded in from tape.
5B24 ED 5B E7 FE LD DE,(#FEE7) 5B26 21 40 5B LD HL,#5B40 5B2B 1A LD A,(DE) 5B2C AE XOR (HL) 5B2D 77 LD (HL),A 5B2E 1C INC E 5B2F 2C INC L 5B30 20 F9 JR NZ,#5B2B
This code decrypts some more code loaded in from tape, but it puts it at #5B40, which is right in the middle of the code we are working on at the moment. So put a breakpoint at #5B32 (the first instruction after the decrypter), and jump to #5B00 (because we haven't executed any of the code from #5B00 onwards yet!)
5B32 21 00 00 LD HL,#0000 5B35 22 B0 5C LD (#5CB0),HL 5B38 2E 02 LD A,#02 5B3A 32 6B 5C LD (#5C6B),A
This puts the value #0000 into #5CB0, but I'm not sure why, because #5CB0 is an unused system variable. It then changes the value of #5C6B to #02, which is what it was originally before it was changed to protect the loader.
5B3D ED 5B E7 FE LD DE,(#FEE7) 5B41 2A E9 FE LD HL,(#FEE9) 5B44 1A LD A,(DE) 5B45 AE XOR (HL) 5B46 77 LD (HL),A 5B47 23 INC HL 5B48 IC INC E 5B49 20 F9 JR NZ,#5B44 5B4B 3A EC FE LA A,(#FEEC) 5B4E BC CP H 5B4F 20 F3 JR NZ,#5B44
This is another decrypter, which works in exactly the same way as the others.
5B51 31 FF 60 LD SP,#60FF 5B54 21 00 CF LD HL,#CF00 5B57 11 00 40 LD DE,#4000 5B5A 01 00 1B LD BC,#1B00 5B5D ED B0 LDIR 5B5F 21 00 EA LD HL,#EA00 5B62 11 00 61 LD DE,#6100 5B65 01 00 10 LD BC,#1000 5B68 ED B0 LDIR
This code moves all the decrypted code to where it should be. This includes the loading screen (as you can see by the reference to #4000.)
5B6A 3E 65 LD A,#65 5B6C 32 00 5B LD (#5B00),A 5B6F 21 0F 14 LD HL,#140F 5B72 22 01 5B LD (#5B01),HL 5B75 21 0F 00 LD HL,#004F 5N78 22 03 5B LD (#5B03),HL 5B7B CD 00 FA CALL #FA00
This code loads the next Bleepload block, from 00 to 87, but will return to 5B7E when it's finished.
5B7E 21 00 40 LD HL,#4000 5B81 11 01 40 LD DE,#4001 5B84 36 00 LD (HL),0 5B86 01 FF 1A LD BC,#1AFF 5B89 ED B0 LDIR 5B8B 3E 66 LD A,#66 5B8D 32 00 5B LD (#5B00),A 5B90 21 0A 0A LD HL,#0A0A 5B92 22 01 5B LD (#5B01),HL 5B96 21 0D 0A LD HL,#0A0D 5B99 22 03 5B LD (#5B03),HL 5B9C CD 00 FA CALL #FA00
This code blanks out the screen and loads some code into it. Some Bleepload games do not have this code, and it is only used on games whos game code overwrites the loading system at #FA00.
5B9F 21 00 40 LD HL,#4000 5BA2 11 00 FA LD DE,#FA00 5BA5 01 00 06 LD BC,#0600 5BA8 ED B0 LDIR
This moves the code loaded from the screen to #FA00 (where it should be).
5BAA 3A 00 60 LD A,(#6000) 5BAD 32 5C 5B LD (#5B5C),A 5BB0 31 A7 61 LD SP,#61A7 5BB3 CD 8E 02 CALL #28E 5BB6 28 1D JR Z,#5BD5
This routine restores the value of #5B5C that was stored in #6000 right at the very start. It then sets the stack to #61A7, and calls the ROM keycheck routine. If no key is pressed (and there shouldn't be), the routine jumps to 5BD5. In fact, it must jump there, otherwise it would attempt to load a normal headerless block, and there are none!
5BD5 C3 BC F5 JP #F5BC
This is what we've all been waiting for - the JP to the game itself. You can simply put POKEs on the end of #5BD5, and follow them with a JP #F5BC to load the game. For now, though, it might be a good idea to put the NEW routine up to #61A7 there, instead, and JP to #5B32 (where we left off). Then load the rest of the game, which will reset at the end, enabling you to load in STK, Devpac or whatever.
Now we've gone all the way through Bleepload, perhaps we should write a hack for the complete game. However, I'm going to put most of the hack in machine code, rather than have long lines of decimal DATA statements. You should be able to convert the machine code into DATA statements and get a short program which reads them in and POKEs them into memory.
The only thing that has to be done from BASIC is the CLEAR 50000:LOAD "" CODE 52480 from the BASIC loader. The machine code hack will consist of the first routine we wrote, followed by a few patches to the main loading system, so that the JP to the game is overwritten with our POKEs. I'll be putting it at #CC80, because it's a safe place in memory.
CC80 3E C9 LD A,#C9 CC82 32 5E CD LD (#CD5E),A
This puts a RET in place of the JP (HL) at #CD5E so we can CALL the loading system.
CC85 CD 00 CD CALL #CD00
This loads in the first Bleepload block.
CC88 CD 21 CD CALL #CD21
This loads in another Bleepload block.
CC8B 23 INC HL CC8C 7E LD A,(HL) CC8D 2B DEC HL CC8E FE 21 CP #21 CC90 20 02 JR NZ,#CC94 CC92 18 F4 JR #CC88
This checks to see if all the Bleepload blocks have been loaded, and jumps ahead if they have, otherwise it jumps back to load the next block.
CC94 3E C3 LD A,#C3 CC96 32 32 5B LD (#5B32),A CC99 21 A1 CC LD HL,CCA1 CC9B 22 33 5B LD (#5B33),HL CC9E C3 00 5B JP #5B00
This puts the instruction JP #CCA1 at #5B32 so the loader decrypter will return to our hack at #CCA1 when finished.
CCA1 21 B2 CC LD HL,#CCB2 CCA4 11 D5 5B LD DE,#5BD5 CCA7 01 08 00 LD BC,#0008 CCAA ED B0 LDIR
This copies the final part of our hacking routine to #5BD5, where it will be executed once the whole game has been loaded.
CCAC 21 00 00 LD HL,#0000 CCAF C3 35 5B JP #5B35
The LD HL,#0000 instruction is important, because it's the instruction we overwrote with out JP back to the hack. Therefore, we've got to execute it, otherwise the loading system may crash. Then it resumes loading at #5B35 with the POKEs firmly in place.
CCB2 3E B6 LD A,#B6 CCB4 32 5F AB LD (#AB5F),A CCB7 C3 BC F5 JP #F5BC
This is the hacking routine which will be copied into the loading system. AB5F,B6 is the POKE for infinite lives (which can be worked out by a forwards or a backwards trace), and JP #F5BC jumps to the game.
And that's about it for Bleepload! Hopefully, if you were hacking a different game, you still managed to do it (they're all virtually identical anyway).
ULTIMATE LOADER
Remember Ultimate? They were one of the finest software houses of all time. Most of their games from 1983 to 1987 had the same type of loader (but a few were Speedlocked - more about them later). On the face of it, it just looks like a totally unprotected BASIC loader, but the appearance is deceptive. The five blocks it loads are the loading screen, the game itself, a decrypter at #5B80, and two very short blocks of system variables. The system variables are, in actual fact the BASIC clock, and determine how many 50ths of a second the computer has been switched on for. The decrypter works using this system variable. The upshot of all this is that if you stop the program for even 1/50th of a second, you'll mess up the decrypter. You can get round this with a Multiface by loading in the first three blocks of code, then replacing the code at #5B80 with #F3,#18 and #FE. This disables interrupts, so the system variable doesn't get updated, and causes an endless loop. Load in the last two blocks, activate the Multiface, and find out what the system variable should be. Then you can put this into the decrypter automatically.
MIKRO-GEN LOADER
This loading system appeared on just about every game released by the software house Mikro-Gen (oddly enough!) from about mid-84 to their demise in 1987. They come in two varieties, and you'll need a Multiface to hack some of the later ones, unfortunately.
The first type are recognised by black and white loading stripes, which loads in a screen block, and then the main game block separately. I'll be doing Pyjamarama as an example, but any Mikro Gen game which fits the above description will do.
So the first thing to do is to *Hack the BASIC loader.
PYJAMARAMA LINE 0 LEN 504
0 BORDER 7:PAPER 7:INK 0:BRIGHT 0:FLASH 0:CLS:PRINT ATThe BASIC loader actually features much more than what we can list. If you're old enough to remember the ZX81, you'll recall that the best place to put a machine code program is in a REM statement. And that's almost the case here, except the machine code comes after the ASCII code #0D (newline), so you can't list it. But it's there. It's activated by the RANDOMIZE USR command. Type PRINT (PEEK 23627+256*PEEK 23628+6) and you'll find out the start address of the code. I made it 23984, which is 5DB0 hex (but you might find it to be something different), so disassemble this address.
5DB0 F3 DI 5DB1 31 00 00 LD SP,#0000 5DB4 2A 4B 5C LD HL,(#5C4B) 5DB7 11 1C 00 LD DE,#001C 5DBA 19 ADD HL,DE 5DBB 11 16 80 LD DE,8016 5DBE 01 E7 00 LD BC,00E7 5DC1 ED B0 LDIR 5DC3 C3 16 80 JP 8016
Hopefully the DI and the LD SP,#0000 should be familiar. The next line loads HL with the two byte value starting at 5C4B. I made it 5DAA. This then has 1C added onto it, making it 5DC6. The rest of the code is a simple LDIR command, which puts the loading system to where it should be.
In our hack, we can simply use a headerless loader to load the code into place. We know that 5DC6 goes to 8016. BASIC always starts at the value in #5C53, which is #5CCB in this case. We know that the length is 504, or #1F8 hex bytes long, and the start address is (#5CCB-#5DC6)+8016 = #7F1B. So, run the following routine.
5B00 DD 21 1B 7F LD IX,#7F1B 5B04 11 F8 01 LD DE,#01F8 5B07 3E FF LD A,#FF 5B09 37 SCF 5B0A CD 56 05 CALL #0556 5B0D 30 F1 JR NC,#5B00 5B0F C9 RET
I've put a JR NC,#5B00 in, so that the computer ignores the BASIC header, and will only return on loading the main BASIC block. You should also note, that in the final hack, we'll have to add a DI and a LD SP,#0000 sometime. For now, disassemble #8016
8016 DD 21 00 40 LD IX,#4000 801A 11 01 1B LD DE,#1B01 801D CD 4F 80 CALL #804F
This code activates the turboloader, which loads in the title screen.
8020 21 00 40 LD HL,#4000 8023 01 00 1B LD BC,#1B00 8026 CD 3F 80 CALL #803F
This code verifies that the screen has loaded in properly (the routine at #803F adds up all the memory with start HL and length BC, and compares it with the byte after this block), and resets the computer if it hasn't.
8029 DD 21 00 82 LD IX,#8200 802D 11 A0 7A LD DE,#7AA0 8030 CD 4F 80 CALL #804F 8033 21 00 82 LD HL,#8200 8036 01 9F 7A LD BC,#7A9F 8039 CD 3F 80 CALL #803F
This is exactly the same as with the previous code, except it loads and checks the main game instead of the loading screen.
803C C3 89 FC JP #FC89
Put a breakpoint over this instruction. Now POKE #8012 with F3, #8013 with #31, #8014 with #00 and #8015 with #00 (because we didn't execute the DI:LD SP,#0000 from the BASIC loader, and the game will not load otherwise), JP #8012 and start the tape. When the main game's loaded, disassemble #FC89.
FC89 21 EF B4 LD HL,#B4EF FC8C 11 00 40 LD DE,#4000 FC8F 01 00 1B LD BC,#1B00 FC92 1A LD A,(DE) FC93 AE XOR (HL) FC94 77 LD (HL),A FC95 23 INC HL FC96 13 INC DE FC97 0B DEC BC FC98 78 LD A,B FC99 B1 OR C FC9A 20 F6 JR NZ,#FC92 FC9C C3 EA BE JP #BEEA
This decrypter uses values in the screen memory, so you'll have to put a breakpoint at FC9C, put a JP #FC89 at #8029, JP to #8012 and reload the loading screen before you can run it. Then disassemble #BEEA.
BEEA 31 00 00 LD SP,#0000 BEED CD CC BE CALL #BECC BEF0 C3 00 82 JP #8200
This code puts the stack pointer back at #0000, CALLs another decrypter, and JPs to #8200, which is the start of the game. Change the #8200 to a suitable place to put POKEs; finish them with a JP #8200 to start the game.
Here's the final hack, and I've put it at #5B00, because it doesn't get overloaded, apart from the byte at #5B00 itself, which is no longer needed by that time. Also, I've executed the DI:LD SP,#0000 directly, as well as the code from BEEA to BEF2.
5B00 DD 21 1B 7F LD IX,#7F1B 5B04 11 F8 01 LD DE,#01F8 5B07 3E FF LD A,#FF 5B09 37 SCF 5B0A CD 56 05 CALL #0556 5B0D 30 F1 JR NC,#5B00 5B0F 21 1C 5B LD HL,#5B1C 5B12 22 3D 80 LD (#803D),HL 5B15 F3 DI 5B16 31 00 00 LD SP,#0000 5B19 C3 16 80 JP #8016 5B1C 21 25 5B LD HL,#5B25 5B1F 22 9D FC LD (#FC9D),HL 5B22 C3 89 FC JP #FC89 5B25 31 00 00 LD SP,#0000 5B28 CD CC BE CALL #BECC 5B2B AF XOR A 5B2C 32 ?? ?? LD (????),A 5B2F C3 00 82 JP #8200
The other type of Mikro Gen loader is almost identical, except the whole game loads in one long block. Then end of the BASIC loading system is missing to start with, and is only loaded right at the end of the main headerless block. You can find out the missing code by loading the game as normal, then stopping it with a Multiface in the pause between the game loading, and the game starting (approx. 3 seconds), and hack it in the same way as Pyjamarama.
POWERLOAD
This protection system appeared first around the start of 1984, and was written by "Tag" (Phil Taglione) for Incentive Software. However, it's been used by quite a lot of other software companies as well, including Beyond, Mirrorsoft, Prism and Ariolasoft. It can be recognised by the screen turning black, accompnied by a few ascending beeps. It then loads one short headerless block, and then a longer headerless block, which includes the attribute file for the game coming up "backwards" ie: right to left, starting from the bottom. The game also stops loading just before the end of the long headerless block.
The only thing I know of that YS have put on the covertape that has Powerload is the Graphic Adventure Creator, but that's pointless hacking, so instead I'll be hacking Dynamite Dan. Of course, most other Powerload games are identical apart from some addresses, and, in fact, the BASIC loaders are all identical.
Before we start, I need to explain a little more about the stack, because Powerload uses it a lot. There are four commands which use the stack, and they are:
PUSH X (where X is any register) - this takes the value in a register, and puts it onto the stack. The stack pointer then decreases by two (to be in the right place to store another value).
POP X - this takes the two byte value at the stack pointer (ie: the top of the stack), and puts them in a register. This also increases the stack pointer by two.
CALL XXXX - when you CALL a subroutine, the return address (ie: the address after the call) is PUSHed onto the stack, and the subroutine is JPed to. The stack pointer also decreases by two.
RET - when a RET instruction occurs, the computer takes the value on the top of the stack, and JPs to it. The stack pointer increases by two.
Now we've cleared that up, let's start hacking. *Hack the BASIC as usual.
D.D. LINE 0 LEN 496
0 REMThe POKEs in line 10 just make the screen black and prevent you from pressing break. 24146 is #5E52 hex; but a breakpoint at #5E52 and GOTO 0. This is because the stack is set up in a specific way by the BASIC commands.
5E52 F3 DI 5E53 21 00 00 LD HL,#0000 5E56 39 ADD HL,SP 5E57 22 F2 5D LD (#5DF2),HL
This code simply puts the value of the stack pointer into address #5DF2, so it can be retreived later.
5E5A 31 95 5E LD SP,#5E95 5E5D 26 5E LD H,#5E 5E5F E5 PUSH HL 5E60 21 68 5E LD HL,#5E68 5E63 E9 JP (HL) 5E68 3E 12 LD A,#12 5E6A 32 93 53 LD (#5E93),A 5E6D E1 POP HL 5E6E E5 PUSH HL 5E6F D1 POP DE 5E70 C9 RET
Put a breakpoint at 5E70 and JP to 5E52. At 5E70, the value on the top of the stack is #5E76, so a RET will JP to there.
5E76 C1 POP BC 5E77 7E LD A,(HL) 5E78 ED 44 NEG 5E7A 77 LD (HL),A 5E7B 23 INC HL 5E7C 10 F9 DJNZ #5E77This code is, as you might realise, a decrypter. The start value of HL is #5E12, and the initial value of B is #3A. In case you're interested, the NEG instruction turns the value in the A register into its negative form; in other words, the value in A is subtracted from #100 hex. Put a breakpoint at #5E7E and JP #5E70 (which is where we left off).
5E7E E1 POP HL 5E7F 22 78 5E LD (#5E78),HL 5E82 C1 POP BC 5E83 3E C9 LD A,#C9 5E85 32 7E 5E LD (#5E7E),A 5E88 3E 00 LD A,#00 5E8A 32 7A 5E LD (#5E7A),A 5E8D 5D PUSH DE 5E8E E1 POP HL 5E8F C9 RET
This code changes the previous decrypter slightly, and RETs to 5E77. Put a breakpoint at 5E8F and JP #5E7E.
5E77 7E LD A,(HL) 5E78 ED 67 RRD 5E7A 00 NOP 5E7B 23 INC HL 5E7C 10 F9 DJNZ,#5E77 5E7E C9 RET
This code works with the same values as the previous one; HL=5E12 and B=3A. It then RETs to 5E12. Put a breakpoint at #5E7E, and JP #5E8F (where we left off last time).
5E12 21 B4 5F LD HL,#5FB4 5E15 11 B5 5F LD DE,#5FB5 5E18 01 B8 88 LD BC,#88B8 5E1B ED B0 LDIR 5E1D E1 POP HL 5E1E 54 LD D,H 5E1F 5D LD E,L 5E20 1C INC E 5E21 C1 POP BC 5E22 ED B0 LDIR
These two LDIR commands wipe all the memory that isn't being used by the loading system. To get round this, you should change #5E1B, #5E1C, #5E22 and #5E23 to #00, to stop them being executed. Put a breakpoint at #5E24 and JP #5E7E (where we left off).
5E24 06 1E LD B,#1E 5E26 E1 POP HL 5E27 7E LD A,(HL) 5E28 EE A3 XOR #A3 5E2A 77 LD (HL),A 5E2B 23 INC HL 5E2C 10 F9 DJNZ,5E27
The value in HL for this decrypter is #5E2E, which is right after the decrypter. To crack it, therefore, move the code from #5E24 to #5E2D somewhere safe (such as #5B00), put a breakpoint on the end, and run the code from there. When that's done, put a breakpoint at #5E2E and JP to #5E2E (so that you're back in the right place in the loading system).
Carrying on with the loader....
5E2E E1 POP HL 5E2F 22 02 5E LD (#5E02),HL 5E32 E1 POP HL 5E33 22 05 5E LD (#5E05),HL 5E36 37 SCF 5E37 3E 07 LD A,#07 5E39 CD 00 5E CALL #5E00
This code takes some values off the stack, and puts them into the subroutine at #5E00, which is then CALLed. Put a breakpoint at #5E39 and JP to #5E2E.
5E00 DD 21 40 9C LD IX,#9C40 5E04 11 90 1 LD DE,#190 5E07 14 INC D 5E08 08 EX AF,AF' 5E09 15 DEC D 5E0A 3E 0F LD A,#0F 5E0C DB FE OUT (#FE),A 5E0E CD 62 05 CALL #0562 5E11 C9 RET
This routine is a headerless loader. The start is #9C40 and the length is #190. Also the value of A is 7, and the carry flag has been set. In effect, we could have used a standard CALL #0556 headerless loader. Put a breakpoint at #5E3C and JP to #5E39. Start the tape and load in the first short headerless block. Then continue disassembling.
5E3C D2 01 00 JP NC,#0001
This code resets the computer if there was a loading error from the first headerless block.
5E3F 21 40 9C LD HL,#9C40 5E42 06 FF LD B,#FF 5E44 CD 77 5E CALL #5E77 5E47 06 FF LD B,#FF 5E49 CD 77 5E CALL #5E77 5E4C F3 DI 5E4D C9 RET
This code decrypts the headerless file we have just loaded in. The decrypter is CALLed to, and it's the same one we had before (with the RRD). So, in actual fact, we can forget about the BASIC loader; just load in the headerless file normally and run our own decrypter. For now, just put a breakpoint at #5E4D and JP to #5E3F. The RET is to #9C40
9C40 21 52 9C LD HL,#9C52 9C43 01 90 01 LD BC,#0190 9C46 16 A5 LD D,#A5 9C48 7E LD A,(HL) 9C49 AA XOR D 9C4A 77 LD (HL),A 9C4B 23 INC HL 9C4C 0B DEC BC 9C4D 78 LD A,B 9C4E B1 OR C 9C4F C2 48 9C JP NZ,9C48
This is a decrypter, and you can crack it in one of two ways. Firstly, you can copy if to somewhere else, put a breakpoint on the end, and run it from there, or you can replace the JP NZ,9C48 with JR NZ,9C48. Both do the same thing, but the JR NZ only uses two bytes. This means we can put a RET at #9C51 and CALL the decrypter. So change #9C4F to #20, #9C50 to #F7 and #9C51 to #C9, then put a CALL #9C40 and a breakpoint somewhere convenient (such as #5B00) and run the decrypter from there. When decrypted, the code continues at #9C52.
9C52 21 63 9C LD HL,#9C63 9C55 11 45 FE LD DE,#FE45 9C58 01 90 01 LD BC,#0190 9C5B ED B0 LDIR 9C5D 31 84 FD LD SP,#FD84 9C60 C3 45 FE JP #FE45
This moves the code we've just decrypted to #FE45, sets the stack pointer to #FD84, and JPs to #FE45. Put a breakpoint at #9C60 and JP to #9C52.
Now at #FE45, we come to the actual loading system itself.
FE45 3E 84 LD A,#84 FE47 11 00 18 LD DE,#1800 FE4A DD 21 00 40 LD IX,#4000 FE4E CD AB FE CALL #FEAB
This code loads in a headerless file with start #4000 and length #1800 (which is the display file for the screen). Nothing too unusual about that.....
FE51 11 00 04 LD DE,#0400 FE54 DD 21 FF 5B LD IX,#5BFF FE58 CD 2A FF CALL #FF2A
....except that as soon as it's done that,it loads in a block with start #5BFF and length #0400 straight away. This block is "sandwiched" right next to the other block on the tape. This particular block loads "backwards".
FE5B 11 E1 01 LD DE,#01E1 FE5E DD 21 1F FE LD IX,#FE1F FE62 CD FA FA CALL #FEFA
And here's another block of the same kind, except it's loaded forwards this time. What's worse is that it's going to overwrite the code we're looking at now, so it must be a "modification" to the loading system (similar to the Mikro-Gen loader). To get round this, we would have to copy the code somewhere else, stick a breakpoint on the end, and run it from there. But remember that the loading system was copied from address #9C63, so there is, in actual fact, a copy of the code anyway. You want to put a breakpoint at #9C83 (the instruction after loading these three blocks), and JP to #9C63. Then start the tape and load in the next headerless block. The loading screen will appear, and the game will load for about four seconds, then control will return to the disassembler. Now look at the code at #FE65.
FE65 11 1D 9F LD DE,#9F1D FE68 DD 21 1C FA LD IX,#FA1C FE6C CD 2A FF CALL #FF2A
This code loads the main game backwards. This will overwrite your disassembler, so you will have to put the NEW routine at #FE6F (but write down all the bytes you are replacing, because you'll need to restore all the original code later). Then you will have to go back and load the first block, because there isn't a header for the main game block. Change #FE4D to #01, #FE57 to #10 and #FE61 to #01 - this will make the computer try to load the three blocks into the ROM. Then rewind the tape back to the start of this headerless block, JP #FE45, and start the tape. Upond loading the whole block, the computer will reset. Load in your disassembler, and replace the code from the NEW routine to the values they should be. Now you can tackle the final part of the loading system.
FE6F 11 E4 12 LD DE,#12E4 FE72 DD 21 FF FF LD IX,#FFFF FE76 C3 70 FF JP #FF70 FF70 3E 00 LD A,0 FF72 D3 FE OUT (#FE),A FF74 CD 1F FE CALL #FE1F FF77 21 43 FE LD HL,#FE43 FF7A BE CP (HL) FF7B CA 89 FF JP Z,#FF89 FF7E 21 48 EE LD HL,#EE48 FF81 01 FF FF LD BC,#FFFF FF84 11 49 EE LD DE,#EE49 FF87 ED B0 LDIR
The routine at #FE1F adds up all the memory in the screen to get a value in the D register. This is then compared with the value of the byte at #FE43. If there is no match, all the memory is blanked out, so the value in the D register must be the same as the byte at #FE43. You should find that the byte is #E6. You need to know this for later on.
FF89 21 A3 FF LD HL,#FFA3 FF8C 01 45 00 LD BC,#0045 FF8F 7A LD A,D FF90 AE XOR (HL) FF92 23 INC HL FF93 0B DEC BC FF94 78 LD A,B FF95 B1 OR C FF96 C2 8F FF JP NZ,#FF8F
This is all we can disassemble for the moment, because the code from #FF89 to #FF98 decrypts the final part of the loader. Change the byte at #FF87 to #16, and the byte at #FF88 to #E6 (this is LD D,#E6, which is used in the decrypter), put a breakpoint at #FF99, and JP to #FF87. Then continue the disassembly.
FF99 CD 31 FE CALL #FE31 FF9C 21 44 FE LD HL,#FE44 FF9F BE CP (HL) FFA0 C2 7E FF JP NZ,#FF7E
This code checks the main game, coming out with a result in the E register. However, this value is never used, so you can ignore this whole routine.
Following on.....
FFA3 21 C0 5D LD HL,#5DC0 FFA6 01 30 75 LD BC,#7530 FFA9 CD D4 FF CALL #FFD4 FFAC 21 C0 5D LD HL,#5DC0 FFAF 01 30 75 LD BC,#7530 FFB2 CD DE FF CALL #FFDE FFB5 21 1C FA LD HL,#FA1C FFB8 11 1C FF LD DE,#FF1C FFBB 01 1D 9F LD BC,#9F1D FFBE ED B8 LDIR FFC0 21 10 A7 LD HL,#A710 FFC3 22 36 5C LD (#5C36),HL FFC6 01 10 DF LD BC,#DF10 FFC9 AF XOR A FFCA ED 42 SBC HL,BC FFCC 31 FF FF LD SP,FFFF FFCF ED 56 IM1 FFD1 C3 6F 00 JP #006F 006F E9 JP (HL)
This routine runs the game decrypters, moves the game into the right place, sets the stack and the interrupts, and puts the start address for the game in the HL register. Change the #006F at #FFD2 to somewhere where you can put a NEW routine (such as #5B00), because the disassembler will be overwritten. Then, change the value at #FFA1 to 16, and the value at #FFA2 to #E6 (because one decrypter uses the value in the D register), and JP to #FFA2. When that's done, you can reload your disassembler, and hack the game using a forwards and backwards trace (but you won't be able to run the code because some of it's missing!)
Now we'll write a complete hack for the game. You have to be a bit careful about where you put your hack in memory, because a lot of memory is overloaded. The first free address we can put the code at is #FA1D.
FA1D DD 21 40 9C LD IX,#9C40 FA21 11 90 01 LD DE,#0190 FA24 3E 07 LD A,#07 FA26 37 SCF FA27 CD 56 05 CALL #0556 FA2A 30 F1 JR NC,#FA1D
This loads in the first headerless block using the values set up in the BASIC loader.
FA2C 06 FF LD B,#FF FA2E 21 40 9C LD HL,#9C40 FA31 7E LD A,(HL) FA32 ED 67 RRD FA34 23 INC HL FA35 10 FA DJNZ #FA31 FA37 06 FF LD B,#FF FA39 7E LD A,(HL) FA3A ED 67 RRD FA3C 23 INC HL FA3D 10 FA DJNZ, #FA39
This decrypts the headerless block.
FA3F 21 20 F7 LD HL,#F720 FA42 22 4F 9C LD (#9C4F),HL FA45 3E C9 LD A,#C9 FA46 32 51 9C LD (#9C51),A FA49 CD 40 9C CALL #9C40
This changes the JP NZ at #9C4F to a JR NZ and a RET, then calls the decrypter.
FA4C 3E C3 LD A,#C3 FA4E 32 83 9C LD (#9C83),A FA51 21 5A FA LD HL,#FA5A FA54 22 84 9C LD (#9C84),HL FA57 C3 63 9C JP #9C63
This puts a JP back to our hack at #9C83, and jumps to #9C63 to load the first part of the headerless block.
FA5A 3E C9 LD A,#C9 FA5C 32 6F FE LD (#FE6F),A FA5F CD 65 FE CALL #FE65
This puts a RET after the code to load the rest of the game, then CALLs that loading procedure.
FA62 21 E6 16 LD HL,#16E6 FA65 22 87 FF LD (#FF87),HL FA68 3E C9 LD A,#C9 FA6A 32 99 FF LD (#FF99),A FA6D CD 87 FF CALL #FF87
This patches in the LD D,#E6, puts a RET at the end of the decrypter, and CALLs it.
FA70 21 7E FA LD HL,#FA7E FA73 11 00 40 LD DE,#4000 FA76 01 20 00 LD BC,#0020 FA79 ED B0 LDIR FA7B C3 00 40 JP #4000
This code moves our hack into the screen memory (so it isn't affected by the LDIR which overwrites it in the next bit of code), and jumps to it there.
FA7E 21 0B 40 LD HL,#400B FA81 22 D2 FF LD (#FFD2),HL FA84 16 E6 LD D,#E6 FA86 C3 A3 FF JP #FFA3
This code replaces the JP #006F with a JP back to our hack (which is in the screen memory by this time), and JPs to #FFA3. We have to include the LD D,#E6 again, because the value of DE was corrupted by the LDIR.
FA89 AF XOR A FA8A 32 C6 CD LD (#CDC6),A FA8D E9 JP (HL)This sets the infinite lives POKE, and does a JP (HL) to start the game.
Phew! I hope you managed to get all that, because it's really hard to do without a Multiface. If you can do it, then you've definitely got the hang of things, so keep it up!
SEARCH LOADER
This loading system appears on every game ever written by Steve Marsden (who wrote the original loading system), as well as a few others. You can recognise them by their fancy front end, which consists of a countdown timer, accompnied by animated graphics and/or instructions, which appear as the game loads. The only game I've actually got at the moment that's got a Search Loader on it is Technician Ted, so I'm going to have to hack that.
So, *Hack the BASIC loader, and let's see what it's got to offer....
Chip Fact LINE 0 LEN 7360 RANDOMIZE USR 24341
The rest of the BASIC is a load of garbage which consists of the machine code for the game. It is stored in a similar way to that in the Mikro Gen loader. 24341 is 5F15 hex, so disassemble this address.
5F15 F3 DI 5F16 21 00 40 LD HL,#4000 5F19 11 01 40 LD DE,#4001 5F1C 01 FF 17 LD BC,#17FF 5F1F 36 00 LD (HL),0 5F21 ED B0 LDIR
This code blanks out the screen.
5F23 CD 32 5E CALL #5E32
The routine at #5E32 sets up the attributes for the screen ie: red banners at the top and bottom, black background with varying ink colours in the middle.
5F26 C3 38 5F JP #5F38 5F38 21 AB 5F LD HL,#5FAB 5F3B 01 59 A0 LD BC,#A059 5F3E 31 00 5C LD SP,#5C00 5F41 3A A8 5F LD A,(#5FA8) 5F44 57 LD D,A 5F45 1E 0B LD E,#0B 5F47 7A LD A,D 5F48 87 ADD A,A 5F49 87 ADD A,A 5F4A 87 ADD A,A 5F4B 87 ADD A,A 5F4C 82 ADD A,D 5F4D 83 ADD A,E 5F4E 57 LD D,A 5F4F 77 LD (HL),A 5F50 23 INC HL 5F51 0B DEC BC 5F52 78 LD A,B 5F53 B1 OR C 5F54 20 F1 JR NZ,#5F47
This routine fills all of the memory above #5FAB with unexecutable code. It is, however, extremely important code, as we shall see later on.
5F56 CD 93 5F CALL #5F93
This routine at #5F93 just messes around with the garbage a bit more.
5F59 CD 80 5D CALL #5D80
The routine at #5D80 scrolls in the title messages for the game, accompanied by annoying clicks.
5F5C 3A 66 80 LD A,(#8066) 5F5F 6F LD L,A 5F60 3A E6 60 LD A,(#60E6) 5F63 67 LD H,A 5F64 E5 PUSH HL 5F65 3A 4F FC LD A,(#FC4F) 5F68 5F LE E,A 5F69 3A 0F 60 LD A,(#600F) 5F6C 57 LD D,A 5F6D DD E1 POP IX 5F6F 37 SCF 5F70 3E FF LD A,#FF 5F72 14 INC D 5F73 08 EX AF,AF' 5F74 15 DEC D 5F75 3A 66 63 LD A,(#6366) 5F78 6F LD L,A 5F79 3A E6 63 LD A,(#63E6) 5F7C 67 LD H,A 5F7D E5 PUSH HL 5F7E DB FE OUT (#FE),A 5F80 1F RRA 5F81 E6 20 AND #20 5F83 F6 01 OR #01 5F85 4F LD C,A 5F86 BF CP A 5F87 F5 PUSH AF 5F88 3A 87 65 LD A,(#6587) 5F8B 6F LD L,A 5F8C 3A 85 64 LD A,(#6485) 5F8F 67 LD H,A 5F90 F1 POP AF 5F91 E5 PUSH HL 5F92 C9 RET
This code takes values out of the garbage and puts them in certain registers. It then imitates the start of the ROM loading routine, and puts some values on the stack. At #5F92, the values of the registers are: Hl= #056B, DE=#03C3, IX=#8000, and the values on the stack are first #056B, then #8000. So, this code will load a headerless file with start #8000 and length #0363, then will JP straight to #8000. We can do away with the BASIC loader altogether in the final hack by mimicing the headerless loader. This is done using the following program.
5B00 F3 DI 5B01 31 00 5C LD SP,#5C00 5B04 DD 21 00 80 LD IX,#8000 5B08 11 C3 03 LD DE,#03C3 5B0B 3E FF LD A,#FF 5B0D 37 SCF 5B0E 14 INC D 5B0F 08 EX AF,AF' 5B10 15 DEC D 5B11 AF XOR A 5B12 DB FE OUT (#FE),A 5B14 1F RRA 5B15 E6 20 AND #20 5B17 F6 01 OR #01 5B19 4F LD C,A 5B1A CD 6B 05 CALL #056B 5B1D <breakpoint>
This routine is slightly different than the one in the loader for two reasons. Firstly, I've put values into the registers directly, rather than have their values taken from bytes in memory. Secondly, you aren't allowed by law to rip off someone else's code; if you directly copied a loading system into a hack, you could be sued. In fact, someone was, once! You're probably alright copying a five byte decrypter from Powerload across, because there really isn't any other code which can do the job in the same way. In general, I would say don't copy code into your hack unless you have to. If you do, change it if you can so it does the same job in a different way. Copying 40 bytes of code directly out of a loading system is definitely out, and most magazines wouldn't print the routine anyway.
There are a few commands we haven't met in the routine. EX AF', AF' concerns the swapping of registers. In the Z80, in actual fact, there are two different sets of each register, although only one set can ever be used at once. Think of it like a TV set, although both registers (A and A' in this case) are there, you can only see one at a time. EX AF,AF' exchanges both the A register and the contents of the flags. Don't worry any more about swapping registers for now.
RRA rotates all the bits in the A register to the right. Actually, it doesn't quite do this, but we don't need to know about it.
If you're not using a Multiface, the garbage routine will have overwritten the disassembler, so reload it in anywhere below #8000. Then run the routine and restart the tape from where you left off. A small part of the headerless block will load in, and control will return to the disassembler. Have a look at address #8000.
8000 D2 00 00 JP NC,#0000
This resets the computer if the previous headerless block didn't load properly.
8003 3E 08 LD A,#08 8005 D3 FE OUT (#FE),A
This makes the border black, and sends a signal to the cassette recorder.
8007 D9 EXX
EXX is a "general exchange" instruction, and changes the registers B,C,D,E,H and L for their alternate sets.
800E 0E 00 LD C,#00 800A D9 EXX 800B 26 00 LD H,#00 800D 06 80 LD B,#80 800F DD 21 1C 8C LD IX,#8C1C 8013 16 05 LD D,#05 8015 CD 41 83 CALL #8341 8018 D2 00 00 JP NC,#0000 801B 06 B1 LD B,#B1 801D 15 DEC D 801E 20 F5 JR NZ,#8015
This code loads in five bytes of tape (the routine at #8341 loads in information off tape into the address pointed to by the IX register), starting at #8C1C. Therefore, this tape routine will start loading code at #8C1C.
8020 11 D8 72 LD DE,#72D8 8023 D9 EXX 8024 0C INC C 8025 D9 EXX 8026 C3 7D 83 JP #837D 837D 2E 01 LD L,#01 837F CD 41 83 CALL #8341 8382 D2 00 00 JP NC,#0000 8385 3E CB LD A,#CB 8387 B8 CP B 8388 17 RLA 8389 D9 EXX 838A 47 LD B,A 838B E6 01 AND #01 838D 3D INC A 838F 11 6B 80 LD DE,#806B 8392 1A LD A,(DE) 8393 A7 AND A 8394 C4 77 82 CALL NZ,#8277
This loads in a set number of bytes from tape, and then prints some sprites on screen (the routine at #8277). This produces all the men walking forwards and backwards while the game loads.
8397 CB 18 RRB 8399 D9 EXX 839A CB 15 RL L 839C 06 B1 LD B,#B1 839E 30 DF JR NC,#837F 83A0 7C LD A,H 83A1 AD XOR L 83A2 67 LD H,A 83A3 7A LD A,D 83A4 B3 OR E 83A5 20 CE JR NZ,#8375
This updates the computer ready to do the next loading and animation sequence.
83A7 7C LD A,H 83A8 A7 AND A 83A9 C2 00 00 JP NZ,#0000 83AC 11 2F EC LD DE,#EC2F 83AF 06 EB LD B,#EB 83B1 CD 41 83 CALL #8431 83B4 D2 00 00 JP NC,#0000 83B7 3E EA LD A,#EA 83B9 B8 CO #0B 83BA D2 00 00 JP NC,#0000 83BD 42 LD B,D 83BE 15 DEC D 83BF 1D DEC E 83C0 C2 B1 83 JP NZ,#83B1
This loads in some more bytes from tape. When these have finished, the computer will continue execution at address #83C3. The code beyond this address does nothing except fiddle about with registers, so there might as well be nothing there. The first bit of useful code will appear at #8C1C, but this hasn't been loaded yet. Instead, put a breakpoint at #83C3, move the headerless loading routine so the CALL #056B is at #7FFD, and run the code from there. Rewind the tape a bit and reload in all of the main headerless block. When finished, you'll find the following code at #8C1C.
8C1C 3E 5C LD A,#5C 8C1E 21 00 40 LD HL,#4000 8C21 54 LD D,H 8C22 5D LD E,L 8C23 EB EX DE,HL 8C24 4E LD C,(HL) 8C25 23 INC HL 8C26 46 LD B,(HL) 8C27 23 INC HL 8C28 EB EX DE,HL 8C29 09 ADD HL,BC 8C2A BA CP D 8C2B 20 F6 JR NZ,8C23 8C2D 11 92 5C LD DE,#5C92 8C30 EE 5C XOR 5C 8C32 28 EF JR Z,#8C23 8C34 E5 PUSH HL
This routine adds up every single byte in memory to get a value in HL, which is pushed onto the stack. This value is important, because it is used in decrypting. This is what the garbage was all used for - to get the right value. It's impossible to calculate it yourself, because any programs you right will mean you get the wrong answer. The only way I can think of to get this value is to load the game as normal, and stop the game with a Multiface as soon as the timer hits 000. Then put a breakpoint at #8C35 and return. Wait a few seconds, then reactivate the Multiface and have a look at the stack. The first value will be #8C35, the second will be the value of HL you want. You should find it's #4DBD.
Carrying on the disassembly....
8C35 21 00 58 LD HL,#5800 8C38 11 01 58 LD DE,#5801 8C3B 01 FF 02 LD BC,#02FF 8C3E 36 00 LD (HL),#00 8C40 ED B0 LDIR 8C42 E1 POP HL
This clears the screen and restores the value of HL, which is used for the following decrypter.
8C43 11 60 8C LD DE,#8C60 8C46 0E 29 LD C,#29 8C48 7C LD A,H 8C49 65 LD H,L 8C4A 47 LD B,A 8C4B 09 ADD HL,BC 8C4C 1A LD A,(DE) 8C4D AD XOR L 8C4E 12 LD (DE),A 8C4F 6F LD L,A 8C50 13 INC DE 8C51 1A LD A,(DE) 8C52 AC XOR H 8C53 12 LD (DE),A 8C54 13 INC DE 8C55 CB 7A BIT 7,D 8C57 20 F0 JR NZ,#8C49 8C59 FB EI 8C5A 67 LD H,A 8C5B 11 70 71 LD DE,#7170 8C5E 19 ADD HL,DE 8C5F E9 JP (HL)
First of all, POKE #8C40, #8C41 and #8C42 with #21, #BD and #4D respectively (so you get the right value of HL), put a breakpoint at #8C5B (nearest place possible to the JP (HL) that we can place a breakpoint), and JP #8C40. On return, the value of HL is #38F5. Add this to #7170 (which is what happens in the next two commands) to get #AA65. This is the start address of the game. So put a JP to your POKEing routine (anywhere from #5B00 to #5BA0 is fine) at #8C5B, and finish your POKEs with a JP #AA65.
You will have to do a stack trace to find infinite lives in the actual game itself. There is a complete hack for this game by myself in YS #78, so why not disassemble it and have a look. It's slightly different to what we've done in that it intercepts the RET at the end of the loading system rather than mimic the first headerless loader, and puts a JP back to the hack at #83C3, but apart from that, it's more or less everything we'e discussed above put together.
PAUL OWEN'S PROTECTION SYSTEM
This has been used on a few Ocean games, but is in fact a standard headerless loader in disguise. The value of A to use is always #98. Load in the BASIC loader and the first block of code, then stop it with a Multiface, and use a stack trace to find out the values of IX and DE for each block, and the JP to the game.
SPEEDLOCK
Concluding the look at protection systems, I think it's only fitting that we end in quite possible the most famous protection system of all time.
Speedlock was first written by two guys called David Looker and David Aubery Jones around late 1983, although it wasn't commercially used until October 1984, on Daley Thompson's Decathlon, by which time it had reached it's third version. Since then, it has been used by many major sofware companies, especially Ocean. Its also gone many modifications, and can be split into three distinct generations.
I should state at this point that you need to have a Multiface to crack most of these Speedlocks, because they completely disrupt the operating system which will lock up any disassembler which relies on ROM routines. The Multiface relies on its own ROM, which isn't affected by the Speedlock code.
Type 1 - have one or two BASIC loaders, and load the main code with the infamous "clicking" leader tones (you know, instead of a steady "bleep", they go "blip, blip, blip, blip" a few times).
Type 2 - have one short BASIC loader, a long CODE block, lots of annoying beeps, then a similar loader to Type 1, minus the clicking leader tones, plus a countdown timer.
Type 3 - as for Type 2, except there is just one very long BASIC loader. The protection system crashes if a Multiface is left switched on. Mazemania on YS #77 covertape used a Type 3.
So, let's start at the very beginning (a very good place to start) with Type 1. In fact, there are about four different difficulty levels of Type 1 Speedlocks; the difficulty goes in chronological order (as you might expect).
The very first Type Ones were completely different to later ones, having the same initialisation routine, but a completely standard decrypter. The only differences between this Speedlock and an ordinary decrypting loader were its initialisation routine and its use of the IY register.
We came across index registers when we first met headerless loaders. There are, in fact, two index registers, IX and IY. In BASIC, the IX register is free for use in a machine code program run from a USR command, but the IY register must always contain the value #5C3A, which is the base address of the BASIC system variables which are wiped with a NEW command. If you return to BASIC with the value of IY anything other than #5C3A, the computer will crash, even if you use the "exit to BASIC" feature on a Multiface. The value of IY must also be #5C3A whenever a BASIC interrupt occurs. Both Devpac and 007 Disassembler run under the BASIC interrupts. They also use built in ROM routines, such as those to check the keyboard and print text; this is preferable, otherwise they'd have to waste memory rewriting their own versions of the routines. Hence the value of IY must always equal #5C3A.
The only safe way of using the IY register is to disable interrupts and write the whole program in RAM without using any built in ROM routines. And Speedlock fits this bill exactly, so it uses the IY register for most of its decrypter calculations.
Speedlock code also uses a lot of undocumented instructions. In theory, you cannot split the sixteen bit IY register into two eight bit registers. But the processor doesn't understand this, and you can split the IY register into two if you want. You simply put the code #FD on the front of any instructions using H or L. There are no standard names for the two halves of the IY register, but I will refer to them as IYH (Hi part of IY) and IYL (Lo part of IY).
Now let's hack a Speedlock game. To start with, I'm hacking Knight Lore, but the following games are also suitable: Beach Head, Daley Thompson's Decathlon, Gilligan's Gold and Underwurlde. Anything released after these will be explained later.
So first *Hack the BASIC loader.
KNIGHT LINE 0 LEN 1037
0 BEEP 0.1,1:BEEP 0.1,2:BEEP 0.1,3:BEEP 0.1,4:BEEP
0.1,5:PAPER
0:BORDER 0:INK 0:BRIGHT 1:CLS:PRINT BRIGHT 1;INK 0;AT 9,5;
"LOADING: KNIGHT LORE";AT 12,10;"PLEASE WAIT"
0 POKE (PEEK 23641+256*PEEK 23642),PEEK 23649:POKE (PEEK 23641+
256*PEEK 23642)+1,PEEK 23650
0 POKE (PEEK 23613+256*PEEK 23614),PEEK 23627:POKE (PEEK 23613+
256*PEEK 23614)+1,PEEK 23628
0 POKE 23662,PEEK 23618:POKE 23663,PEEK 23619:POKE 23664,PEEK
23621
23676 "REM CLOSE #ATTR....
Wait a minute, there's absolutely no sign of a RANDOMIZE USR command anywhere! There's just some BASIC which beeps a bit, sets the colours, and prints a message, a whole load of POKEs, and then a load of garbage. Surely the computer will do everything, then report with an error message as soon as it reaches 23676?
Well, that's not actually the case. Look at the third line 0 (the one which starts POKE [PEEK 23613+256* etc.). This system variable is known as ERR SP. What happens is that when an error occurs (and it will do here), the computer jumps to the value in this register. This value is PEEK 23627+256*PEEK 23628. PRINT this value, and there's the start of the machine code. You might get a different result to me, but I made the start address #60A8. Disassemble this address.
60A8 F3 DI 60A9 FD 25 DEC IYH 60AB FD 7C LD A,IYH 60AD FD AD XOR IYL
The DI is very important, because otherwise the I register can't be used. Given that IY starts off as being #5C3A, the value in A will end up being #5B XORed with #3A, which is #61.
60AF FD 26 F3 LD IYH,#F3 60B2 FD 2E A6 LD IYL,#A6 60B5 3B DEC SP 60B6 3B DEC SP 60B7 01 54 FE LD BC,#FE54 60BA FD E3 EX (SP),IY
First of all, this loads IY with the value #F3A6. It then decreases the stack pointer by two. By doing this, the stack pointer is now pointing to the start address of the machine code, which is #60A8. EX (SP),IY is a variation to the register exchange commands we've already come across. It basically swaps the value in the address pointed by the stack pointer with the value in the IY register. So, after this instruction, IY will contain #60A8, and the value on the top of the stack will be #F3A6.
60BC 21 30 F2 LD HL,#F230 60BF FD 09 ADD IY,BC 60C1 01 AC 01 LD BC,#01AC 60C4 FD 5D LD E,IYL 60C6 FD 54 LD D,IYH 60C8 EB EX DE,HL
Here, HL is being loaded with #F230. The value in BC (#FE54) is added to the value in IY (#60A8), making the value in IY #5EFC. Then BC is loaded with #01AC, and the value in IY is transferred into DE. Then the values of DE and HL are swapped. So, by the end of the code we've looked at so far, HL will equal #5EFC, DE will equal #F230, BC will equal #01AC, and A will equal #61. These values are all used in the decrypter which follows.
60C9 AE XOR (HL) 60CA 12 LD (DE),A 60CB 7E LD (HL),A 60CC 23 INC HL 60CD 13 INC DE 60CE 0B DEC BC 60CF FD 6F LD IYL,A 60D1 78 LD A,B 60D2 B1 OR C 60D3 FD 7D LD A,IYL 60D5 20 F2 JR NZ,#60C9 60D7 C9 RET
This is a straightforward decrypter, except the value for A (which is needed throughout the decrypter) is temporarily stored in part of the IY register. The RET is to #F3A6 (the top value on the stack).
To crack this, we can set up the register values manually, CALL the decrypter, and then hack the main loader ourselves. Type out this program:
5B00 F3 DI 5B01 21 FC 5E LD HL,#5EFC 5B04 11 30 F2 LD DE,#F230 5B07 01 AC 01 LD BC,#01AC 5B0A 3E 61 LD A,#61 5B0C CD C9 60 CALL #60C9 5B0F FD 21 3A 5C LD IY,#5C3A 5B13 <breakpoint>
Notice that we've disabled interrupts to avoid crashing, and we need to restore the value of IY to #5C3A afterwards, so your disassembler won't crash. RUN the program, and have a look at the code at #F3A6. You'll find it's just a straightforward headerless loader with absoultely no frills, and you should be able to hack it no problem.
As for the final hack, load the BASIC into address #5CCB, run the decryption routine above, patch the JP in the main turboloader to your POKEs, and start running.
All other Speedlock Type 1s have the same sort of decrypter. The code for the decrypter is very complicated, with the result that I have been unable to reproduce it here. Luckily, you don't have to touch the code; you can write your own decrypter as long as you have a Multiface.
I'll be doing Tapper as an example, but any other Speedlock follows this procedure almost exactly. *Hack your game and note down the length of the code (you'll need it later). I made it 1453, which is #05AD hex. Now look at address #5EFD. The byte at #5EFD is always decrypted to give the byte #42, and the byte at #5EFD is always decrypted to give the byte #55. The decrypter works by XORing the encrypted byte with a number taken from the R register. By inspecting the code before and after running, you'll see the XORing number starts off as #CB, and increases by #0A each time. If the result is more than #FF, the result has #80 subtracted from it. We can incorporate this into our decrypter. The start of the code is #5EFD, and the length is (PEEK 23627+256*PEEK 23628)-#5EFD, which is #01ED in the case of Tapper. The following code will simulate the decrypter.
LD HL,<start> LD BC,<length> LD D,<initial decrypter value> *** LD A,(HL) XOR D LD (HL),A LD A,D ADD #0A SET 7,A LD D,A INC HL DEC BC JR NZ, ***
Once you've done that decrypter, you've got to do the whole lot again, starting at #5EFD. The byte there will be decrypted to either #3E or #ED - you'll have to guess which decrypting value to use. For Tapper, the start is #5F2B, the length is #1BF, and the second decrypter value is #AB.
When you've done that, you'll either get the complete loading system or another decrypter. If you've got the loading system, then reload the BASIC loader, and do a stack trace to find out where it should go. You should have no problems with the loader.
If you've got another decrpyter, go along five bytes and find a LD DE,(XXXX). Add #2E to this value, and that's where you move it to. The length is the same as that for the second decrypter. The decrypter itself can be cracked by changing a JP Z in the code about forty bytes later (the value of this is the start of the turboloader), but the decrypter itself uses a byte which is worked out by adding all the memory together in the loading system. Since we've got an exact copy of this system elsewhere in memory, just change the value of XXXX in the aforementioned LD DE,(XXXX), and then JP to the start of the decrypter.
If the first decrypting value you used was #CB, then you can just change the JP in the turboloader to your POKEs.
If the value was #CD, then you'll need to know about the Standard Speedlock patch. Somewhere in the loading system there will be the two bytes ED 53 [LD DE,(XXXX)]. Change the XXXX to the address of your POKEs (#5BA0 is normally safe), and end your POKEs with a JP to the value you overwrote. You'll have to use this patch for the later Speedlocks as well.
There was a Speedlock Type 1 MultiPOKE in YS#79. RUN the program, press BREAK and disassemble address #5B00 to find out what to do in your own hacks.
Type 2 Speedlocks feature a very easy BASIC loader, and one big block of code, which has six short decrypters and a complex moving routine. The decrypters are all easy peasy, just move them to somewhere else in memory (such as #5B00), bung a RET on the end, and CALL the decrypter from there (but watch out for the third decrypter, which checks for a Multiface and crashes if it finds it. The moving routine fiddles about with the loader. Search for 31, which means LD SP,XXXX. Hopefully, you'll find a LD SP,#0000, with perhaps a DI right before it. Write down the address and run the moving routine (you may have to restart the tape, because some of the moving routines insist on a signal coming into the tape recorder). Use a stack trace to find out where the code has gone to. Now you can move all the code from the moving routine to the end of the machine code block to where it should be, given that you know where the LD SP,#0000 goes to. Once moved, patch the loader in the same way as the first Speedlock.
Type 3s have just one long BASIC loader, with about 144 decrypters, but that's nothing to worry about. *Hack the BASIC loader, and have a look at the first bit of code which moves the rest of the code into the right place (you can then use a headerless loader to load this into the right place in memory). The tricky bit is changing a byte in memory so a CALL to the loading system at the very top of the code is changed to a CALL somewhere else once all the decrypters have been run. The only way you can do this is to change the address of the hi byte of this CALL to something else, and RUN the huge load of the decrypters. The computer will crash if you have a Multiface attached, but only after everything's been decrypted, so then look and see what the CALL's been changed to. If it's suitable, remember the patch, position your hack around this, change the CALL to what it should be,and put in the usual Speedlock patch. Look at the start address in the turboloader. This address will be overwritten by a decrypter once loading finishes. This decrypter is nothing special, so just crack it as usual, and watch out for the game moving around.
Jon North's Pokerama Tapes usually have a Speedlock Type 3 crack on it - load up the Pokerama, choose your POKE, then do a stack trace to find it and have a look at it.