Date: 2007-08-08 14:37
Checksums Part 2 or "How to crack The Settlers"
A tutorial by StingRay written for www.flashtro.com
At the end of my last tutorial about checksums I mentioned that you could try your luck with "The Settlers" as that game uses checksums too. Well, I thought it might be a good idea to write a tutorial about how to crack this very game and that's actually the reason why you are reading this now. As I want to have somewhat interesting tutorials, I'll try to crack this game without actually starting it one time, i.e. only by looking at the ReSourced code and using my instinct and maybe a bit of luck. :) You might remember excellent crackers like Phil Douglas, it's said he cracked games without being able to run them. This is what I want to do in this tutorial too. I will exactly describe all of my steps, that means, even if I'll do something that didn't help to crack the game or was just plain wrong, I'll write it here! So even I don't know yet how this tutorial will look like at the end. :) But enough of this preamble, let's get to work!
To follow this tutorial, you'll need the following things:
- The game (I have used CAPS/SPS 143 here)
- An assembler, I'll use Asm-Pro here
- An Amiga or emulator like WinUAE
Let's get things rolling. Looking at the first disk I couldn't find a file called "Settlers" or "TheSettlers" so the mainfile is probably on another disk. And indeed, on disk 3 we can find a "The Settlers" file which is only 15 bytes so it's probably just a tiny shellscript which starts the game. We can also find a file called "TheSettlers" with a size of 192.700 bytes. Now that looks very much like it would be the game file. Let's just load it into ReSource to check it. And indeed, it looks like 68k code to me. Ok then, let's try to find where the protection routine is located. I just entered "please" in the "Search" requester (you can find the "Search" button in the lower part of the screen) as most games that have a novella (i.e. manual) protection ask you kindly to "please enter word xxx" or something similar. So, the word "please" should be a good search string to find such texts I think. So let's enter this search string and press the "Forwards" button. And lo and behold, at offset $388d ReSource found a text saying "Please identify the symbols on".
It looks promising because this text is referenced directly which we can see because ReSource already created a label for it. So let's just continue our search to see where this label is used. With a bit of luck we are already in the protection routine then. ReSource finds the next occurrence at offset $65cc. Let's examine the code a bit deeper, could that be the protection routine? Short answer, definitely not, it just looks like a generic "Print Text" routine. We can easily see that by just scrolling down a bit, at offset $660e another text is loaded into register a2 and the same routine that was called after a2 was loaded with the "please identify the symbols on" text is executed. To me it looks like the routine (lbC026B58) takes 3 parameters:
a2: ptr to text to print d0: x position d1: y position
That of course is all guess work and I could be totally wrong here. However, we don't have to care about this, we know this routine doesn't have anything to do with the protection so we can ignore it! Hmm, too bad, what now? I have this habit to check the areas of code that could have anything to do with protections a bit deeper. So I'll do the same here too. Let's scroll down a bit to see if we can find anything of interest. And indeed, at offset $68f4 there is a line of code that loads "PAGE.MSG" into register a2, loads register d0/d1 like before but instead of calling the routine at offset $26b58 now a routine at offset $6bf6 is called. Could it be that the game prepares the texts for the manual protection here? Maybe it gets a random number and then creates a text like "from PAGE number 25" where 25 would be the converted random value? Let's look a bit further. The next thing that catched my interest is the "cmp.w #3,d6" instruction at offset $6a10. I can't really explain why but I have a certain feeling this is the "check the number of wrong answers" code. So I scroll up a bit and see something that looks like a classic "copy graphics to screen" loop at offset $69e8. Scrolling up a bit more I see that my feeling was wrong, d6 is used to calculate an offset in the destination bitmap. Now, I remember the "symbols" part in the text I found before. Could it be that game copies 3 symbols to the screen here? I scroll down again to check what happens after this "copy graphics" loop. At offset $6a18 register a1 is loaded with a pointer to something, then some calculations are performed and 2 bytes from the area that a1 points to are moved into register d0 and the last instruction before the rts is a "cmp.w d0,d5" and a branch to offset $6806 if the comparison fails, i.e. both registers contain different values. I don't know about you but I am pretty sure that this is the actual "manual check"! I guess, if we would just remove the branch after the compare, we could enter whatever we want at the protection check. Why do I think that? Well, if we check where it branches to if the compare failed, we'll see it is right before the "prepare the page number" routine and generally, it all looks like it's the protection routine to me. It is easier to see than to explain, if you look at the screenshot (or load the game into ReSource yourself), you'll see what I mean. Also, if we check the data at $6a64 (remember the code at offset $6a18? a1 is loaded with a ptr to data at offset $6a64 there), we'll see nothing that looks like useful data, it more or less looks to me like some crypted or otherwise pre-processed data. Most probably the right answers are hidden there and to avoid that they are visible when loading the exe into an hex editor, they have been protected. That's my guess at least. Anyway, so far I think if we remove the bne.w lbC006806 instruction at offset $6a4a, we could enter whatever we want at the protection routine.
Now let's see if that routine is protected in any way. Let's go back to the start of the file and search for lbC006806. ReSource only finds 2 occurrences, one is the routine itself and the other one is the branch at offset $6a4a. Ok, so obviously the game doesn't directly access this routine from anywhere else. Now, let's check for eor instructions. Why that you may ask. Well, if you've seen your fair share of checksum routines you know that MANY of them use the eor instruction in the loop to calculate the checksum. So, let's just check for that instruction and see if we can find something interesting. And indeed, ReSource finds something. The first occurence is at offset $52e but that loop doesn't look very interesting so we'll continue searching. Next one is found at offset $224e but it does't look interesting either, looks like normal game code to me, no loop, no compare with a checksum etc. So to make it short, I'll ignore that one too and continue searching. Same for the one that is found at offset $225c as it looks pretty similar to the one we just found. The next one at $67c2 looks a little bit more interesting but as there is no obvious check of a checksum and stuff, I decide to ignore that one too. Same for the ones at offset $67d0, $8c28, $8c7a, $8cc8, $a0f4, they all don't catch my interest either. However, the next one found at offset $ba80 does!
What is going on there? In the loop some value is calculated and then at offset $ba8a there is a compare with a constant, somehow that looks very very suspicious to me! Apparently the start of the routine is at offset $ba66, there a0 points to offset $e338 and some lines below, at offset $ba70, the value $7ba4 is subtracted from a0 so it points to $e338-$7ba4=$6794. Let's check the code at offset $6794! It looks like that is the start of the protection routine! So something is very very fishy! Let's go back to offset $ba80 and save the code for the checksum routine so we can try it out in our Assembler. I set offset $BA6C as start and $ba8e as end. However, before I save the routine using ReSource's "Save Asm->Partial" function I first create the missing label at offset $ba88 using the "Create single->Label - fwd ref" function in the "LABELS" menu.
Once done I loaded that routine in AsmPro and adapted it a bit, i.e. I removed the "sub.l #$7ba4,a0" instruction and replaced it with "lea data+32+$6794,a0". The reason for that should be clear, originally the routine calculated the offset to the start address, as we already know that one, we don't have to do that anymore. The "+32" is, as mentioned in my last tutorial, to skip the hunk header. Now, after executing this routine, d2 will have the value $7f60 and I can't say I'm surprised about that. :)
Now let's see what happens when we remove the branch at offset $6A4A, my bet is the checksum will be different and it would prove my theory that this was the protection check. As I'm old and lazy I usually avoid every extra work and so instead of writing one line of code (hard! :D) to remove the branch, I just assemble the source again but before typing 'j' to execute it, I type 'd data+32+$6a4a' to disassemble the code at that offset. Then I simply press 'DEL' to remove (i.e. nop out) the code. Having done that I press 'ESC' to return to normal mode and execute the code with 'j' as usual. d2 now has the value $b898 so that means it's checked if we have modified the code at offset $6a4a. Somehow that doesn't surprise me much either. :)
Now just for fun I continue searching to see if there are more checksum routines. But as said, that's just done for fun, I already know there is at least one so I'll have to code a loader for the game. And as expected, there is another checksum routine at offset $c370. This time it starts with a "lea START+ffffd480,a2" instruction. What does that mean? It just means, a2 is loaded with a ptr to an address that is outside the executable, $ffffd480 is a negative number (-11136 in decimal) and we know that "START" is the beginning of the executable, i.e. offset 0. Thus, a2 will point to the address that is 0-11136 bytes in front of the exe. 2 lines below at offset $c37a the value $9314 is added to a2, so the final offset is: -11136+9314=$6794. That offset looks familiar, doesn't it? :) Let's continue searching just for fun, I'm curious to see how many more checksum routines there are in the game. I find 2 more at offsets $cca0 and $25704. So there are at least 4 checksum routines in the game but as I didn't look very thoroughly (because there is no need to), there are probably more! The checksum routines all contain slightly different code btw, this is probably to avoid them being detected by searching for a single opcode. However, in my opinion this was a wasted effort as all of them use the "eor" instruction. You remember the search term I've used? So even if the code is different in the checksum routines, I could still find them by just looking for eor instructions. I suppose the coder thought that if the bad guy who's attempting to crack the game found one checksum, he would just do a simple opcode search to find more checksum routines. And that would fail. Like f.e. in the first checksum routine we found, "eor.w d1,d2" is used in the loop to calculate the checksum value. This instruction has the opcode $B342. So one could think searching for all $B342 opcodes would reveal all the checksum routines. That approach is bound to fail however as the next checksum routine uses "eor.w d3,d1" which apparently has a different opcode ($B741), another one uses "eor.w d2,d1 ($B541) and the one after that uses "eor.w d4,d5" ($BB44). I think you get the point.
Ok, so now that we know the game doesn't want us to mess with the protection routine we have to find a way around that. What we have to do is clear:
- remove the protection check at offset $6a4a with 2 nops, another approach would be to change the "cmp.w d0,d5" instruction at offset $6a48 to "moveq #0,d5", that way we ensure the branch below would never be taken. And since that is just a 2 byte modification as opposed to the 4 byte nop hack, I'll use that. I like to avoid nops whenever I can, don't really know why though. :)
- after the protection routine is passed, we need to restore the original code as quickly as possible so the checksum checks won't fail
That doesn't sound too complicated I think so let's go. First we need to know from where the protection routine is called. So let's go to offset $6794 as that is where the checksum routines start checking the code. Who said those routines can't be helpful? :) To jump to a specified offset you can use the "Absolute->Specify offset" function that you can find in ReSource's "CURSOR" menu. As this is a pretty useful function I recommend creating a hotkey for it. Anyway, ReSource will open a requester where you can enter the offset you want to jump to then. In this case we would simply enter "$6794", notice the "$" prefix which is used for hexadecimal offsets. After pressing "OK" ReSource will jump to offset $6794. Now we have to find the real start of the routine. This is at offset $6578. There is no general approach how to do this, here it is simple as we see an "rts" instruction at offset $6576. That means another routine ends there and a new one starts at offset $6578. Now let's enter "lbC006578" as search string and see where the routine is called. Remember to go back to offset 0, i.e. the beginning of the file before starting the search. ReSource return offset $FF6, we see a "bsr lbC006794" there. Below that is a branch to offset $392e so let's see what happens there. To quickly jump to a branch destination within ReSource you can use the "Absolute->Forward reference" function in the "CURSOR" menu. In my version of ReSource the hotkey for that function is "cursor right" but as I did set up ReSource to suit my needs more than a decade ago, I can't remember if that's a default setting or not. ;)
At offset $392e we see a jsr to another routine and that's actually totally great for us as it helps us to achieve our evil plan of doing a proper crack for the game. Now, why is that? The code at this offset is not pc relative, that means we can safely place a patch at this position and don't have to fear that a checksum routine will detect that! In ReSource we see "jsr lbC026826", this means it is an absolute address. Thus the code here, once the game has been loaded, will always look different as AmigaDOS adds the offset to the current memory location at runtime, this is known as "relocating". This is not a totally correct explanation but should give you an idea why the code can't be checked by a checksum routine.
Now that we know that, we can start coding a loader for the game. This loader will have to do the following:
- load the game using LoadSeg
- remove the manual check at offset $6a48
- place a patch that will restore the original code in the protection routine to please "Mr. Checksum" :) at offset $392e
- last not least, start the game :)
Ok, let's code that then. The core of my patch looks like:
Patch move.l a0,-(a7) move.l 4(a7),a0 ; get return address move.w #$ba40,$6a48-$3934(a0) ; restore original code add.l #$26826-$3934,a0 ; excute original routine jsr (a0) move.l (a7)+,a0 rts
Now, that looks cute and tiny, doesn't it? If you have followed the tutorial carefully, you should not have any problems to understand what I do here. The only thing you might wonder about is the "move.l 4(a7),a0", it actually is just to get the current return address so I can use that as a base address then. As you may know, before a subroutine is executed, the return address is pushed on the stack. And because I save a0 on the stack, I have to add 4 bytes to get the correct return address. This might sound complicated but it is in fact pretty simple. If you have problems to understand it, just experiment a little in Asm1/Pro and watch the registers. Call a subroutine with a jsr instruction and look at the stack. You'll surely see how it works then.
Ok, now that I've coded the cute and tiny loader for the game, it's time to test it. Let's quickly load the startup-sequence in Asm-Pro's editor and change it so it would execute our loader instead of the game. Now, looking at it, we see the game is called with a parameter "-f". That means, I have to adapt my loader a bit, I'll simply "pass through" the commandline given to my loader to the game, thus "emulating" the original behaviour. :) This is very easily done, I only have to save registers d0 (length of commandline) and a0 (ptr to commandline string) and restore them just before calling the game. It's as simple as it sounds, not even 30 seconds of work. :) After I have done that, I simply change the startup-sequence so it contains a "loader -f" as the first command and simply comment out the original "run nil: nil: TheSettlers nil: nil: -f" line.
Now the time has come to actually test my work. Let's boot the disk and see what happens. :) For some reason I'm pretty confident it will work as expected, i.e. the protection is removed and we can start the game. This might sound arrogant but it is not meant like that. The reason why I'm confident is that I think I understood how the core of the protection works and thus I'm sure I've disabled it. But we'll see in some minutes when the game has finished loading.
Well, seems my feeling was right. :) The game did let me enter anything at the protection check and I could start it.
Now there's only one thing I need to test. It could be that the game executes some of the checksum routines before the protection routine is called. That would mean some of the checksum checks might fail because we restore the code AFTER the protection routine has been run. It's unlikely but well, I want to be sure. :) To easily check this, I'll just place an "illegal" instruction in every checksum routine that I've found. If the game executes them, it will crash. So if the game won't crash before we see the protection screen, it means our crack should be perfect. So I quickly adapt the loader and start the game again. And it seems it's my lucky day, I can still pass the protection screen without a crash so none of the checksum routines have been executed before. :) You might like to know what I would have done if the opposite would've happened, i.e. one of the checksum routines would have been executed. Well, I would have done the same I did to find a place for the "restore code" patch. That means, I would have checked the protection routine (easy as I already know the start and end of it) and would have tried to find a place where I could have placed a "crack game" patch, i.e. instead of removing the protection check before the game is started, I would crack it "on the fly" and then execute the "clean up" patch afterwards. This could be an exercise for you, dear reader of this tutorial, try to crack the game using that approach.
So I guess that concludes my second tutorial. I hope you had fun reading it and I could show you something new. Actually, my aim was to give away some general tips about cracking a game as contrary to the self-proclaimed world's best coder/cracker/hd patcher called Codetapper I like to give background information, not just "you can use tool xyz to do task zyx". That was the reason why I have cracked the game the way I did, i.e. without checking it until all of the work was done. I always admired crackers like Phil Douglas and back then I thought that it must be pretty damn hard to crack a game without having a possibility to test it. I hope I could show that it is not as hard as it may sound, as long as you know what you are doing, everything is possible! :) This game had a pretty nice protection but I actually didn't find it very hard to crack, the opposite rather, but only because I knew about the "where/how/why". And with these wise words you have reached the end of another tutorial, see you in the next one.
P.S.: As usual I have included the full source code for the loader.
StingRay, still in August 2007 (yes, even I am amazed ;D)
Filesize: 0KB, downloaded 85 times