"The Clue!" (c)1994 Neo

Hits: 3830

Checksums and how to defeat them

Author: Sting Ray
Submitted by:
Date: 2007-08-07 00:29
Edit Hits: 3830
No tags

Checksums and how to defeat them

A tutorial by StingRay written for www.flashtro.com

Ok, so here it finally is, my first tutorial for Flashtro. Lately while doing some HD fixes I found a nice protection which involved checksum checks and that's what I'm gonna write about in this tutorial. Without further ado let's have a look at the target:

"The Clue!" (c)1994 Neo

The things you'll need to follow this tutorial are:

  1. The game of course (CAPS/SPS 2134)
  2. ReSource
  3. An assembler of your choice
  4. An Amiga or emulator

Ok, let's start the game to see what happens. We are greeted by a nice "Enter word xx from the manual" window. Now that's gonna be an easy crack, right? Yes indeed but only if you do it right :) (or your name is Codetapper, then you already know everything about any 68k related things anyway and can stop reading here as this tutorial is not for such a super experienced cracker like you!)

Ok, let's load the file in ReSource to have a closer look: Load file "TheClue!" in ReSource, press "Disassemble" in the "Project" menu and scroll down a bit. At offset $58 (check Resource's menu bar), we'll see a routine that loads the texts we saw in the lovely copy protection window into some registers and well, what to say, that's of course the protection routine.

Let's check from where it's called and what happens after this call. Move back to the beginning of the file (i.e. offset 0) and press the "Search" button you can see in the lower part of the screen. Now press the "Forwards" button and ReSource returns location $3e, we see a "bsr lbC000058" at this very position. Now press "Forwards" again to find any other occurrences. There are none.

Most probably the game calls the protection routine and as long as the correct word is not entered, it won't return from the protection routine. So, let's check what the next routine after the call to the protection routine does. Et voila, as expected the next routine (lbC000628) starts the game. It loads the intro and then the game. So, to disable the protection, we only have to remove the call to the protection routine. Well, not quite. For some reason I always find such utterly simple protections suspicious so let's look around a bit more to see if there's something fishy going on.

Let's go back to the beginning of the file. Why the heck does the game store the contents of $3fc.w and initializes that very address with a pointer to the routine at offset $A5C? That deserves further investigation!

Ok, let's quickly do a search for $3fc, we'll find 3 occurrences, 1. save ptr, 2. load it with a new address, 3. restore old ptr. So it's not really used within this file, so let's load the file that is loaded after the intro ("TheClouDisk1:Tc.Base"). Once loaded and disassembled, we enter the "Search" requester again and search for $3fc. And what a surprise, ReSource finds the first occurrence at offset $875c and a bit below that at offset $8784 we see a compare with some weird looking number. Why is the game doing that? Let's find out how the routine works.

        move.w  #$3FC,a3        ; should not need any comment :)
        moveq   #0,d4           ; initialize checksum value
        move.l  (a3),d0         ; d0: ptr to offset $a5c in TheClue!
        sub.l   #$A04,d0        ; $A5C-$A04=$58 = start of protection routine
        move.l  d0,a2
        moveq   #0,d5           ; loop counter
        moveq   #$53,d0
        add.l   d0,d0           ; d0=$53*2=166 = number of longs to check
        cmp.l   d0,d5           ; i.e. check until offset $2A0 which
        bhs.b   lbC008784       ; is the end of the protection routine
        move.l  d5,d0
        asl.l   #2,d0           ; multiply loop counter by 4 to get correct offset
        move.l  (a2,d0.l),d1    ; get current long
        eor.l   d1,d4           ; xor with current checksum value
        addq.l  #1,d5           ; increase loop counter
        bra.b   lbC00876E

        cmp.l   #$42483A01,d4   ; check the checksum :)

Does that need any more explaining? I hope not. :) What we have here is a classic checksum routine. It either was obfuscated a bit on purpose or it is the product of a C compiler. Here's a simplified version done by yours truely which might be a bit easier to understand:

        move.l  $3fc.w,a2
        sub.w   #$a04,a2
        moveq   #0,d4
        move.w  #166-1,d5
.loop   move.l  (a2)+,d1
        eor.l   d1,d4
        dbf     d5,.loop

It checks 166 longwords from offset $58 in the "TheClue!" file. And what a wonder, at offset $2A0 the protection routine ends. If you want to check the routine you can do the following: Go to offset $875c in ReSource and select "Partial save -> set start" in the "SV" menu, then scroll down to offset $878a and select "Partial save -> set end". Now select "Save .asm -> partial" in the same menu and ReSource will save the routine then. If you thought I typed the routine to get it into this document you now know better. :)

Anyway, now load this routine into your favourite assembler, change it so that it would accept a ptr to an area to check and give it a fitting name like "CalcChecksum" or whatever you prefer. Then you just "incbin" the "TheClue!" file and call the routine with a pointer that points to the start of the protection routine. Adapting my version from above, it would look like:

START   lea     data+32+$58,a0  ; not pc relative to give Codetapper
        bsr     CalcChecksum    ; something he can complain about

data    incbin  RAM:TheClue!

; a0: ptr to area to check
; --
; d4: 32bit checksum value
        moveq   #0,d4
        move.w  #166-1,d5
.loop   move.l  (a2)+,d1
        eor.l   d1,d4
        dbf     d5,.loop

I think this is easy enough to understand, the only thing you might wonder about is the "+32", this is just to skip the hunk header. There are many ways to get the size of the hunk header, usually I just do a "d data" in Asm1/Pro and just check where the code starts, in this case it starts at the 8. longword so the size of the hunk header is 8*4=32 bytes.

If you execute this routine, d4 will contain the value $42483A01 and somehow that value does look familiar, doesn't it? :) As soon as we mess with the protection routine the checksum will be altered which would mean the game might do some undesirable things. :) I actually didn't check what happens if the checksums are not valid, if you feel like it you can try it yourself.

Now, how to deal with this problem? An obvious way would be to check for all occurrences of $42483a01 and $3fc and adapt all the checks accordingly. This would probably be the approach someone super experienced like Codetapper would use. But we are better than that! :) As a rule of thumb, do your "dirty work" with as less modifications as possible. I just had a quick look and could spot 7 checksum routines, that would mean we would have to change at least 7 checks but what if there are checksum checks in other files as well? So, this approach, even though it would work, is not elegant at all because it has too many disadvantages.

  • we need to find EVERY checksum check in each file
  • we would have to alter EVERY file that contains a checksum check

As you can see, this is not only time consuming but also pretty unsafe. What if we miss some checksum? The game could have "hidden checksums", i.e. it could use obfuscated code to check/calculate the checksum without any direct use of the $3fc pointer and/or the original checksum value! You would have to fully analyze the code in each file to be 100% sure you found all checksums as there are endless ways to obfuscate such code. Like f.e. take this one, invented in 2 minutes by yours truely:

        move.l  #$ffffc040,d0	; move.l #-$3fc<<4,d0
        lea     $00002054,a0	; lea $0815<<2,a0
        lea     (a0,d0.l),a0
        ; do a lot of fake code that uses a0 without altering the value
        ; ...
        sub.l   #$ffffdc98,a0	; sub.l	#(-$3fc<<4)+($0815<<2)-$3fc,a0
; call a slightly different checksum routine which does
; "add.w #$58,a0" at the beginning
        bsr     CalcCheckSum2	; d4: checksum
        lsr.l   #1,d4
        ; do a lot of fake code here without altering checksum value
        ; ...
        move.l  #CORRECT_CHECKSUM>>1,d0
        sub.l   d4,d0
        beq.b   .checksum_correct

As you can see, no direct $3fc access or using the original checksum value, so the standard approach of searching for the checksum value would return nothing! As said, possibilities are endless! :) Or would you have guessed that a0=$3fc without looking at the comments? If so, your name is probably Codetapper and I told you already that this tutorial is not for super experienced crackers like you!

Ok, so how can we crack the game then? Easy, we remove the protection call and put it back before the game is started! :) Now, if that sounds confusing, just think a bit about it. The game expects to have an unaltered protection routine and exactly that is what we will feed the game with! You probably guessed it already, we need to code a loader for the game which does the following:

  • load file "TheClue!" and get a ptr to the first hunk (LoadSeg)
  • remove the call to the protection routine
  • restore the original code before the game is started so the checksum tests won't fail

Now, that doesn't sound too complicated, does it? Except for the fact that we don't know in which area of the game we can safely put our patch as there could be more checksum checks. So even with this approach we would have to check the whole game for checksums? That's pretty useless then, isn't it? NO! :) Luckily the code is NOT 100% pc relative, that means there are areas that will always change depending on the memory location the game has been loaded to as AmigaDOS relocates these absolute addresses. Thus, they CAN'T be checked by a simple checksum routine! Make sure you understood the last paragraph, it's essential knowledge! Now you might think "but what if it will just be loaded without LoadSeg within the game?". As we are NOT touching the original gamecode in any way, even that check would always return the correct checksum, our approach simply can't fail as we don't touch the original executable!

Ok, let's code our cute little loader then. The only thing we need to do is to find a location where we can place our patch. Let's have a look. Too bad, the code that follows directly after the protection call is fully pc relative and as it is the code that starts the game, we are doomed? Of course not! :) As the game uses the "Execute" function in dos.library to load files, we will simply patch that very function! :) We just have to compare the filename, if it matches with the one the game loads, we "patch back" the area we have altered within "TheClue!" and simply remove our dos "Execute" patch. Patching a library can be done using a "forbid/store ptr to old routine/set ptr to our new routine/calc new checksum (oh the irony :D)/ permit" combination or by using exec's "SetFunction" routine. As we are lazy, we could use SetFunction but the disadvantage is that it won't work with all libraries on Kickstart 1.3 and guess what, dos.library is one of them. And as we don't want to have a patch that works on OS2.0+ machines only, we need to find a solution for this problem. So let's examine what happens when we just use a normal approach, i.e we will do the following:

  • get a ptr to the original "Execute" routine
  • forbid task switching, i.e. turn multi-tasking off
  • replace it with our patched version
  • call exec's "SumLib" function to calculate the new library checksum
  • enable task switching, i.e. turn multi-tasking on
The code to do that could look like:

	move.l	$4.w,a6
	lea	DOSname(pc),a1
	jsr	-408(a6)			; OldOpenLibrary() (hello Mr.Spiv :D)
	move.l	d0,a1	
	lea	-222+2(a1),a0			; ptr to execute routine
	lea	Patch(pc),a1			; ptr to our patched routine
	move.l	(a0),OldExecute-Patch(a1)	; store ptr to old routine
	move.l	a1,(a0)				; install it
	jsr	-132(a6)			; Forbid()
	jsr	-426(a6)			; SumLibrary()
	jmp	-138(a6)			; Permit()

If you wonder about the -222+2, the +2 is just to skip the "jmp" instruction, i.e. the $4ef9 opcode which is 2 bytes long. That was what I tried first. Apparently it didn't work very well, the Amiga crashes with a "Library checksum failure" alert. It puzzled me for a while but after some trial and error and checking the "exec/libraries.i" include file I found out that the "LIB_CHANGED" bit had to be set in the "LIB_FLAGS" before calling SumLibrary, as usual that wasn't mentioned anywhere. Once I added that, patching the library worked fine, as long as the patch wasn't started on OS versions below 2.0. And at this point I have to thank Mr.Spiv for giving the crucial hint. It turned out the 1.3 version of dos.libray doesn't use a standard jumptable to call the functions. Normally, when you call a library function, the code inside the library would look like:

        jmp     routine  ; if you didn't understand why I did the +2 above
        jmp     routine2 ; you may get the idea now
        jmp     routine3

So if we take the "Execute" function as example, in library versions greater than v34 (i.e. OS2.0+) the system would do the following after your _LVOExecute(a6) call:


so our approach described above works perfectly. Now, for pre-OS 2.0 versions of the dos.library things look totally different. This is what the 1.3 version does when you call Execute:

	moveq	#-27,d0
	bra.w	SomeGenericRoutine

As you can see, our approach will totally fail here because the function is called in a totally different way, no jmp opcode used at all. The only way to deal with that is to add some special code which checks if it's an old library and use different code then. What I did to get it working was the following: I just coded a very small program which did nothing more than opening dos.library and giving me the ptr to this generic routine. Then I just added a mousewait and ran this program on an 1.3 machine equipped with an Action Replay. Yes, this is actually one of the very few occasions where using the "magic button" is justified in my opinion. So once my little program entered the "wait for left mouse" loop, I pressed the magic button to have a look at the code. What I saw was the following:

        movem.l d2-d7/a2-a6,-(a7)
        sub.l   a0,a0
        move.l  a7,d5
        sub.l   #$5dc,d5

Now, this last instruction looked promising because it occupied 6 bytes. A perfect place for our "jsr patch" instruction as that has exactly the same size. I think you can figure out the rest yourself, in the patch I just executed the original code (the "sub.l #$5dc,d5" instruction) and called the real patch then. In case you have troubles understanding it, just check the accompanying source code. You'll find the complete source for the "TheClue!" loader, examine it and try to understand the "how and why". You'll notice the mess in the "PatchLib" routine, I originally made it as a generic library patching routine that could be used similar to "SetFunction" but due to the stupidity of the 1.3 dos.lib it turned into quite a messy routine. You'll also notice that I didn't add any support to remove the patch for 1.3 machines, if you feel like hacking the source a bit, you can add it yourself. :) But you'll find both methods in the source, SetFunction and the old-styled method of patching a library as I thought it could be interesting to see them both. Anyway, it's all for you to explore! :) But now, back to our actual task, what does the patch actually have to do? We need to:

  • compare given filename (which is given in register d1)
  • if we found the correct one, we will "repair" the code, i.e. we put back the "bsr.b protection" opcode
  • lastly we simply remove our "Execute" patch as it's not needed anymore.
Just check this piece of code, it's the core of the patch:

; d1: filename
Patch   movem.l d1/a0,-(a7)
        move.l  VARS+OldExecute(pc),a0
	jsr     (a0)                    ; execute original "execute" :)
        movem.l (a7)+,d1/a0

; check filename
        movem.l d0-a6,-(a7)
        lea     Introname(pc),a1
.loop   cmp.b   #" ",(a0)
        beq.b   .end
        tst.b   (a0)
        beq.b   .end
        cmpm.b  (a0)+,(a1)+
        bne.b   .wrong
        bra.b   .loop

.end    tst.b   (a1)
        bne.b   .wrong

; file found, let's do the magic :)
        move.l  VARS+Hunkstart(pc),a0
        move.w  #$6118,$3e(a0)          ; restore original code

; remove our patch
        move.l  VARS+DOSbase(pc),a1
        move.l  VARS+OldExecute(pc),d0
        lea     -222.w,a0               ; Execute offset
        move.l  $4.w,a6
        jsr     -420(a6)                ; SetFunction

.wrong  movem.l (a7)+,d0-a6

So what exactly does it do? First we execute the original "Execute" routine, in case you wonder why we don't simply call -222(a6), i.e. _LVOExecute, then just think a bit about it and you'll notice we would enter an endless loop if we would do so! :) Once that routine returns we just check the given filename. If it was the introfile ("TheClouDisk1:TCIntro"), we just get a pointer to the first hunk in the "TheClue!" file and simply put back the "bsr.b Protection" opcode at offset $3e. Once we have done that we don't need our patch any longer and thus simply remove it. And that's actually all there is to do! :) Again, if you have problems understanding it, check out the included source code, it uses exactly the approaches I've described in this tutorial.

So, I guess that's all I can think of for the moment, I hope you found the tutorial interesting and could learn something new. It was interesting to write for me as even I did learn something new (the 1.3 dos.library patching stuff). I tried to have something different than the usual "mfm/rnc copylock/novella protection" because I think there are already enough tutorials covering these topics. If you want to test yourself, you can try to use the things you (hopefully) learned in this tutorial to do a 100% crack of Whales Voyage. Even a very talented cracker like N.O.M.A.D. makes mistakes sometimes, i.e. he missed ALL the checksums thus rendering the FLT crack totally useless! I can't remember that I've ever seen a 100% version of that game so you might try to do one yourself! I actually did it already for my own entertainment, you'll have to "reverse" the FLT crack first, i.e. you have to undo the changes N.O.M.A.D. did to the original file! If you read this tutorial carefully, you should know how you could check if you successfully reverted the messed up FLT exe to a clean original executable. :) Another game using checksums is "The Settlers", you could try your luck with that one too.

Now, as the very last thing, I'll reveal how you could have cracked this game without doing all this dos.library patching and stuff. Actually, there is a bug/backdoor in the protection routine, if you place "STR!" (or any other random 4 character word) at offset $52a in the "TheClue!" file, you'll have a fully cracked game! I won't explain why and how that works, it's for you to find out! :) Also, I am pretty sure that just "noping" the call to the protection routine would also yield in a 100% cracked game as I couldn't find anywhere that this area is checked. Yet, both of the things I mentioned wouldn't work for Whales Voyage f.e. so I still think and hope this tutorial was useful for you.

Lastly, I want to send out a special thank to Mr.Spiv for giving the crucial hint why the patch didn't work on 1.3, I would have never looked at the library jumptable! :) Also greetings to all on flashtro, I hope to see some more tutorials soon. :) I'll try to do another one as well, I just don't know in which year that will be. ;)

Have fun, StingRay in August 2007

FileDownload: "The Clue!" (c)1994 Neo
Filesize: 0KB, downloaded 81 times
Powered by the best online Amiga mod player: FLOD

Some more you may like:



Leave a Comment!

: Use this calculator
Your comment will be available for editing for 10 minutes
2007-08-07 02:59

1. Go0se writes

Enjoyable + well written tutorial!

Cheers StingRay.
2007-08-07 05:57

2. StingRay writes

Thanks. :)
2007-08-07 09:00

3. WayneK writes

Great tutorial, nice to see one on a 'new' topic... more please! :)
2007-08-07 09:09

4. mr.spiv writes

Ah.. great one!
2007-08-07 12:34

5. aLpHa oNe writes

2007-08-07 19:15

6. StingRay writes

Thanks guys. :) For some reason I have the certain feeling the next tutorial is not too far away. :)
2007-08-07 19:43

7. Rob writes

Yes, nice work. Very interesting.
2007-08-07 19:45

8. StingRay writes

Feel free to ask any questions here in case you had problems to understand some parts of this tutorial. I'll try to answer then. :)
2007-08-07 22:51

9. mr.spiv writes

Oki.. what's the thing with Codetapper? Didn't get that :D
2007-08-07 23:03

10. StingRay writes

Hehehe, easy to explain, he thinks he's world's best cracker/hd fixer/coder/whatever and everyone else is a bloody newbie for him. He likes to boast how "good and experienced" he is, while in fact he heavily relies on tools done by others for his work. Just check some of his comments here on Flashtro f.e., totally arrogant and written as if he would know everything about everything. I had some arguments with him because I dared to have my own opinion which apparently pissed him off for a reason I don't have to understand. Anyway, I wouldn't mind his boasting if he would actually be as good as he wants to make people believe...
2007-08-08 19:57

11. DLFRSILVER writes

thanks for this very good cracktut, it's a change yes ^^

Why not trying to crack a dongle protected game ?
2007-08-08 20:03

12. StingRay writes

Any special wish for a "how to crack a dongle protected game" tutorial? I remember BAT 2 had a dongle protection if I'm not mistaken, I might do one for this game. :)
2007-08-10 00:52

13. DLFRSILVER writes

i have already done it on the french version, which was not
cracked until 2 years ago.

Just need to nop out the dongle check compare instruction, and everything goes perfect !

Was thinking about Robocop 3 or Dyna Blaster :D
2007-08-10 00:53

14. DLFRSILVER writes

It was a 2 minutes crack for me.
I was so disappointed.....
2007-08-10 12:16

15. Codetapper writes

You must be pretty jealous of my cracking skills to write such a load of crap all through your tutorial Stingray. You can't have cracked much stuff written in C if you think that earlier code was product of a C compiler either. As for your comment about what if you miss a checksum - you could just do what you did on EAB and release a poor quality patch that crashes on the majority of machines, has post after post of bug reports and then throw all your toys out of the cot when someone doesn't bow to your uber-cracking skills. For good measure delete all files from the said site and say what a great loss it is to the community that you couldn't release a decent patch to begin with. I will leave you with some stats: http://www.whdload.de/tops.html
2009-07-04 15:48

16. The Welder writes

In all of my years of cracking, I've never seen such utter nonsense as I've read here. All this patching of library calls and such just to by-pass a checksum routine - ridiculous.

Anyone with a little cracking knowledge wouldn't have used anything like the described technique, they'd have done as I did with The Settlers. A technique that's a million times easier and much less messy too, but does require a little knowledge of the executable file format and relocation tables.

The ideal solution to defeat this type of protection is to simply nop out (or rather replace) the code calling the protection routine, step 1, so that the protection code is never called. In it's place, insert a jmp (or jsr) to a new code hunk that you attach to the end of the executable file (or you can even do it to the start of an executable file too, if you know what you're doing!). This code hunk will replace the jmp/jsr with the original instruction, thus allowing for the checksumming to work perfectly. DONE! Easy as pie.

The only real difficulty in this technique is that the code hunk you add has to have relocation entries to replace the original instruction (but you can even get around this if you use the stack) and you need to add a relocation to the hunk where you modify the instruction. However, if you know the format of executable files and understand relocation tables, it's like a 2min job.

You could even use a technique whereby you modifty the hunk size in the header of the executable, add the code to replace the bytes at the end of the hunk and call it... and it's still easier than all this library patching lunacy!
2009-07-05 10:47

17. cewlout writes

@The Welder:

Just out of curiosity. But what happens when the checksum code is executed more often? If you replace the code in first place next time the checksum-code will be again executed then? Isn't this dangerous?

Also I knew alot of ppl who simply added a memory watchpoint on the modified addresses to see if they get hit to remove checks, is this a bad idea in general?
2009-07-07 15:13

18. The Welder writes


It doesn't matter if the checksum code is executed multiple times or just once. It'll always pass the checksum because the code hasn't been altered!!!

Let's take The Settlers as an example... That has multiple checksum routines, so if you remove the manual protection, when you quit (as an example), the game simply crashes. Okay so here's what you do:-

You can bypass the manual check by just (if I remember rightly) either nopping out an instruction or two, or inserting a jmp. Okay, so this bypasses the protection... but nopping out or putting in that jmp will cause the checksum to fail, so you need to put the ORIGINAL instructions back in after the manual check, (ie so that the checksum routines pass perfectly - however many there are)

Right, so INSTEAD of simply nopping out the call to to manual check, you change it for a JSR to your new code hunk that you've added to the end of the executable file. This new code hunk that you've added to the end of the executable puts back the ORIGINAL instructions (so the checksums will work perfectly - even if checked multiple times).

So, you end up with no manual check and code that ALWAYS passes the checksum routines (even if they're hidden or whatever) because the code HASN'T actually been altered!

Understand now?

As I said earlier, the ONLY real difficulty in this method is you need to know the executable file format and relocation tables as the JSR to your new hunk of code that puts the original code back so that checksum routines will work, will require a relocation entry. But as I said, if you're any reasonable cracker, you should know the executable format and how relocation tables work.
2009-07-08 19:53

19. cewlout writes

@The Welder:

Ah well now I understand. First time it will bypass the check because it has been altered then it jumps to a code which replaces the instruction with the original one jumps back to the game.

And you mean the reloc32 table which needs an entry to correctly set up the JSR and of course the second code-hunk with the replace-function. Just like a virus actually ;-)