Speedlock 5-7


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 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 descrypt 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 1, 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 you did when cracking Speedlock 4 last month).

Type 1
EA91 LD   DE,144B
E494 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
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  EX,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 from usual. 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 keep control without having to move the decrypter anywhere.

Type 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 LF   (HL),A
EAF0 LDI
EAF2 DEC  DE
EAF3 RET  PO
EAF4 JR   EAEC
This is like the one for Type 2. As I said in Issue 61, a JP PE after a LDDR will only jump 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, the 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 shange the JP PE address so that it JP's to somewhere convenient, wher you have placed a LD A,R: {breakpoint}.

Type 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
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
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
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
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
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.
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: {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 its address is an instruction and not part of one of the numbers at the start. It then checks what the instruction is, from what it can identify what decrypter is 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.
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 unsuccesful
       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 it must be Type 3
PATCH  ADD  HL,BC                ;HL=address after the JP PE
       LD   E,(HL)               ;get the value out
       LD   (HL),BACK&255        ;patch the LSB of "Back"
       INC  HL                   ;next byte
       LD   D,(HL)               ;get the value out
       LD   (HL),BACK