1) SideWinder_(1988)(Mastertronic) SPS 2) An Amiga or WinUAE (I’m using WinUAE) 3) Action Replay III or Rom Image 4) Beermon, Thrill Kill, Cartmon, Amon… etc. 5) Pencil and paper 6) Blanks, if you use a real Amiga (don’t work on your original copy)
Given that this game was cracked by BS1 / The Champs over twenty years ago and the crack is readily available on the Internet, we are not doing a disservice to the authors by analyzing the code. They will not lose any sales due to this. This is for educational purposes only and at your own risk and volition.
Make a copy of the first disk using the built in Burstnibbler (type burst at the action replay prompt) to see what we are facing.
Looks like a one track protection on track 1.
Boot the copy and it crashes after a while. Activate the cartridge and scan memory for a loader
Faq BFD100 – Using a 512Kb Chip and 512Kb Fast settings the loader is around C12800. Disassemble after the last address shown. We’re using BFD100 as it’s used for controlling the disk drive head. You could try any standard addresses which are used in a loader or search for loader op codes using the technique used in the RNC protection tutorials to find the copylock.
The below is the interesting part, but you can resource the whole thing and see exactly what they are doing. It’s loading a long track (move.w #b778,24(a6) which would be around 9800 for a normal track) which will be too long to be written by a standard drive.
The protection checks for 4454 in D1 and branches to C12A30, if equal. It subtracts 1A2c from D5 to ensure test is far enough into the buffer. If the subtraction gives a negative result then the protection (BMI C12A40) has failed and it returns 1 (MOVE.B #1,-6738(a4)). If the subtraction gives a positive result then it returns 0 (MOVE.B #0,6738(a4)). We can trace on through the protection and see where it’s passed back. You could use the st command which allows single or multiple steps after either putting an infinite loop (e.g. branching to the same line). Also, you can breakpoint certain instructions (bs <address>)
Note, I’ve reloaded the game here so the addresses are different from the above. Depending on the memory configuration you are using the addresses you see will probably be different. However, further down I load the file with the protection into memory at 30000 and then the addresses will match.
The below shows the routine which calls the protection (JSR C1152C) and the test on the
result (TST.B D0) which will result in a branch to C117F8 if D0 = 0 (BEQ C117F8). A search of memory shows that the call to this protection is only done once.
The above shows the actual call with the passing of the protection check byte in -6738(A4) back in D0. The JSR C1163E is reading the track. The JSR C116F2 is the start of the data check.
This disk is standard Amiga dos (type dir at the Action Replay prompt) with a startup-sequence, as follows (type type s/startup-sequence at the Action Replay prompt)
Endcli > nil:
We can load the program Z into memory
Lm z, 30000
Search for the loader again using BFD100
The code below calls the routines to move the disk head and read the track, as described above. Here the addresses will match no matter what your memory configuration. The JSR to 336D4 is at 3397E and there’s a TST.B D0 directly after.
Disassemble from 33860, as the interesting part of the loader is after the drive routines, as per our earlier research.
Change the instruction at 338f0 from move.b #1, -6738(a4) to move.b #0, -6738(a4). This way anytime the protection is called it will return the protection passed result. The Action Replay assembler does not seem to like move.b #0,-6738(A4) and so either we can edit the hex directly or get out another disassembler. Beermon and Thrill Kill have really useful features. Using Beermon, load the file (L z 30000) and make a note of the end load address. Disassemble from 338E0, as shown below.
Assemble the change using N 338F0 and enter move.b #0,(-$6738,A4)
Save back to disk by deleting z first (del z) and then save the memory (S z 30000 36e18)
You can try it this way with the Action Replay.
Disassemble the code at 338e0 which shows the two instructions at 338e8 and 338f0. Display the hex values at 338e8 (using m 338e8) and 338f0, as shown above. Edit the byte at 338f3 from 01 to 00 by moving the cursor to under the 1, change to 0 and press return to save it
Save the program back to disk (e.g. sm z, 30000 36E18) and reload.
Train the lives using ts 3 to begin and then t 2 when you’ve lost a life. Once you have the address, put a memory watch on that address (ms <address>) and lose a life. The replay will interrupt the program when an instruction which modifies that address is executed. The instruction which decrements the life counter is subq.w #1,8(a0). NOP out the subtract and play with infinite lives.
I’ve tested on to the second stage/level, and so please test further, if you feel inclined. Press space on the start screen shown below to select difficulty and number of players.
Thanks to Musashi9 for this great site.