HOW TO HACK

By Jon North

Sinclair ZX Spectrum
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 be 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:
1. After a LD A,I; LD I,A; LD A,R; LD R,A if interrupts are disabled
2. After a CPI; CPD; LDI LDD; CPIR; CPDR; LDIR; LDDR if BC=0
3. After an AND; OR; XOR if there are an even number of set bits (i.e. 1's)
4. After an ADD; SUB; INC; DEC if result is above 127 or below -128
Similarly, a JP PE,address will JP if one of the above is not true. You will need to know these when hacking Speedlock.
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 (i.e. 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 PE

62AC-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 FD24
Firstly, 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 f

Incidentally, 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 58616
So 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 E4FD

To 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 E512

As 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 E512

Again, 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,E549

The 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,E555

This 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 E56A

This 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 E56A

Move 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,E587

Cracking 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, i.e. 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 #8AF4

This 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 58616
The 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 DF19

Crack 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...
Sinclair ZX Spectrum

  Previous Page Back Next Page