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.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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).
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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... |