HOW TO HACK

By Jon North

Sinclair ZX Spectrum
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: 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 EAA2
Type 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 EABD

Cracking 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: (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 EAEC

You 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.
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 EB7A

Crack 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,FB28

Crack 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,FB6F
Type 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,EF78
Type 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 F8D3
Final 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,F8E9

To crack this, change the three bytes at F8F5 to a JP to a convenient address, where you have placed JP NZ,F8E9: 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, i.e. 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, i.e. 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.
Sinclair ZX Spectrum

  Previous Page Back Next Page