ISSUE 56 |
For the last couple of months, I've been showing you how to hack infinite lives out of games. From now on, I'll be concentrating on showing you how to crack the protection systems, so that you'll be writitng Multipokes before you know it. |
LOADING THE FIRST BIT The first program on any game tape is called the loader - because it loads the rest of the program (logical, huh?). To crack any protection system, however simple, you need to keep track of what it's doing at all times. |
The *LOAD Routine This program is a special loading routine. Instead of typing LOAD "" to load the loader, type RANDOMIZE USR 30000. This will load the basic program and stop with the OK message. When it loads, it displays the filename, the start line of the program (this is usually 0,1 or 10) and it's length. |
Listing 110 REM *Load by Jon North20 LET t=0 30 FOR f=3e4 to 30083 40 READ a: POKE f,a 50 LET t=t+(f-29990)*a: NEXT f 60 IF t<>544506 THEN STOP 70 PRINT "Data O.K.": STOP 80 DATA 221,33,0,80,17 90 DATA 17,0,175,55,205 100 DATA 86,5,48,240,221 110 DATA 126,239,183,32,236 120 DATA 62,2,205,1,22 130 DATA 33,1,80,6,10 140 DATA 126,215,35,16,251 150 DATA 62,202,215,221,70 160 DATA 253,221,78,252,205 170 DATA 43,45,205,227,45 180 DATA 221,54,253,255,62 190 DATA 32,215,62,177,215 200 DATA 221,70,251,221,78 210 DATA 250,205,43,45,205 220 DATA 227,45,62,13,215 230 DATA 42,83,92,221,46 240 DATA 0,195,115,8 |
DISGUISING BASIC AND GETTING PAST IT Unfortunately, what you see and what you get with basic programs are not always the same thing. Type in this one line and RUN it: 10 PRINT 10 Surprise surprise, 10 comes up on the screen. Now type in directly, LET A=PEEK 23635+256*PEEK 23636: POKE A+5,50 If you now list the program, it will read 10 PRINT 20, but if you run it, it still prints 10. Every time a number is put in a program, two copies of it are stored. The first is what is listed, the second it what is actually used. |
The *LIST Program
This routine is a special list routine. Use RANDOMIZE USR 30085 instead of LIST to use it. What it does is show you the program as it would be run, that is, it strips away all the disguises and reveals the true program.Listing 210 *List by Jon North20 LET t=0 30 FOR f=30085 TO 30200 40 READ a: POKE f,a 50 LET t=t+(f-30075)*a: NEXT f 60 IF t<>919527 THEN STOP 70 PRINT "Data O.K.": STOP 80 DATA 62,2,205,1,22 90 DATA 42,83,92,229,237 100 DATA 91,75,92,55,63 110 DATA 237,82,124,181,225 120 DATA 200,70,35,78,35 130 DATA 229,205,43,45,205 140 DATA 227,45,225,78,35 150 DATA 70,35,229,9,34 160 DATA 254,255,225,126,254 170 DATA 13,32,4,35,215 180 DATA 24,212,254,46,40 190 DATA 8,254,58,48,19 200 DATA 254,48,56,15,68 210 DATA 62,14,237,177,205 220 DATA 180,51,229,205,227 230 DATA 45,225,24,220,254 240 DATA 32,56,2,215,126 250 DATA 254,234,32,8,62 260 DATA 13,215,42,254,255 270 DATA 24,167,254,34,32 280 DATA 12,35,126,254,32 290 DATA 56,2,215,126,254 300 DATA 34,32,244,35,24 310 DATA 183 |
HEADERLESS FILES This is probably the simplest form of protection you can get. When a block of data loads, it comes in two chunks - a short one, which holds things like the filename and the length of the block, then the block itself. This first short bit is called the header, and the idea of headerless files is, surprise surprise, to be able to do without this header. It does this by holding all the information needed about the block (namely where to load it to and its length) in a machine code program, which uses this information to load the file. |
What A Headerless Loader Looks Like To load a headerless block, a short bit of code is needed: LD IX, start address LD DE, length of block LD A,FF SCF CALL 0556 RET or JP |
That's it! If you look at most of my more complex hacks, you'll see they start off with 221, 33, n, n, 17, n, n, 62, 255, 55, 205, 86, 5, 48, 241; this is the code to load the basic program as a headerless file (because it can't be MERGEd). |
Example: Falcon Patrol II When you *Load the basic, you'll see: FP2 LINE 99 LEN 800 You now know that the program starts from line 99. When it's loaded, *List it: 99 CLEAR 65367: RANDOMIZE USR (PEEK 23637+256*PEEK 23638)+5 100 REM To find out the value of the RANDOMIZE USR, find the address of the actual commands (use the TEXT feature of your dissassembler, or search for bytes F9 C0) and change it to PRINT i.e. F5 20. Now RUN the basic and it will display the value of the USR command. Your value may be different to mine, but I got 23825, which is 5D11 hex. Dissassemble this address: LD HL,000F LD DE,F000 ADD HL,BC LD BC,256 LDIR JP F000 Taking this line by line: HL=15,DE=61440. Whenever you do a USR command from Basic, the BC register holds the value of that USR, so here, BC=23825. The ADD HL,BC command means LET HL=HL+BC, so HL=23825+15=23840 (5C20). BC then becomes 256 and then you come across a special instruction, LDIR. What this does is to move BC bytes from HL to DE. For instance, to move a screen from 32768 (the screen is 16384-23295), you'd do LD HL,32768: LD DE,16384: LD BC,6912: LDIR |
Here, the LDIR is from 23840 to 61440, for 256 bytes. Then it JP's to 61440. Put a breakpoint over the JP with your dissassembler, RUN the program and dissassemble 61440. F000: LD IX,4000 LD DE,1B00 XOR A CALL F04E LD IX,6800 LD DE,6000 XOR A CALL F04E LD A,0F LD (5C8D),A LD (5C48),A LD A,01 OUT (FE),A LD A,195 LD (5C37),A LD BC,1400 XOR A IN A,(1F) OR C LD C,A DJNZ F02A AND 192 JR Z,F049 XOR A LD (9EAE),A JP B110 We can see that a block is loaded 4000,1B00 and another 6800,6000. Note that the CALL is different (F04E, not 0556) and the value of A is also different (0, not FF). This is simply because the loader is using a different routine to do the actual loading (a turboloader, not the normal speed ROM loader). The JP at F039 starts the game, so put a breakpoint there and load the game (make sure your dissassembler is out of the way, or the game will be loaded over it). |
Hacking the game, the LD A,5 (5 lives) is at 45362; the lives store is 40549, which is referenced at 40550,40562,45364 and 45565. The routine at 40550 is: LD HL,40549 ADD A,(HL) LD (HL),A Turning the LD (HL),A into a 0 (at 40554) gives infinite lives. |
Coming back to the loading system, the Basic can be MERGEd, and you can work out the address of the JP in the basic program before it is moved to F039. You know that 5C20 goes to F000, so 5C20+39 goes to F039, ie 5C59. The final hack is: 100 MERGE "" 110 POKE 23897,201 120 RANDOMIZE USR 23825 130 POKE 40554,0 140 RANDOMIZE USR 45328 (The 45328 came from the JP B110 at the end of the loader). However, the address of basic programs varies (eg. if Microdrives are connected), so the 23825 and 23897 are expressed in terms of the start of Basic. Also, the original program did a CLEAR 65367 before the USR, so we also need to include that. Hence: 100 CLEAR 65367: MERGE "" 110 LET a=PEEK 23635+256*PEEK 23636 120 POKE a+142,201 130 RANDOMIZE USR (a+70) The variable a is the start of basic. The rest of the hack would be the same because the game is always loaded to the same place regardless of where Basic is. |
The Ballbreaker II hack is in this month's Pokes - see if you can work out how I did it (you shouldn't have too much difficulty, but bear in mind the Basic cannot be MERGEd). |
Next month, I'll be discussing decryption, and using it, together with this month's column, to crack Firebird Bleepload. If you hit any problems, drop me a line at Jon North, HTH, YS, 30 Monmouth Street, Bath, Avon. If you don't send an SAE you definately won't get a reply, but you should do if you do. 'Til next month, if it loads - hack it! |