Cracking Windows Serial Protections and CRC checks

Sink Sub by Anders Wihlborg




SoftIce windows version 1.9
Ultraedit 32
Target is available from:

Most of the new games and application are written for windows. This lesson will deal with a protection scheme that you'll find on alot of windows shareware programs, though most of them have gone for timelimits. The serial protection schemes are not generally hard to crack, depending on what you wanna get out of it. If you want to make a serial generator you will have to study the programs mathematical functions, but if you simply wish to register it you dont really need to dig that deep to succeed. Dont get me wrong here it is a good idea to study the mathematical function, becuase you'll learn alot about encryption (at least more than if you skipped it).

There are basically two variants of this protection. one where the regcode is based on the username. The main reason for this is that every user will have his/her own special code (unless they have the same name). The other variant is a predefined code ie the reg code consists of 8 chars and the first five characters must be 23456, the remianing three chars can be any number or character.

I have chosen a game for windows, Sink Sub. Available from and other shareware sites. This is a simple (but quite fun) arcade game. The first thing we'll do is to run sink sub and look for clues. A nag screen pops up in the beginning reminding us of registering the software. It also tells us that we can "Evaluate" sink sub for 30 days. Here we have two buttons one is OK and the otherone is Register. We press ok for now. Lets look in the help file. Here we can read that it besides the timelimit also have disabled some levels. If we pay for our license we can play 50 levels and get the highest rank. Its also says under registering that we will receive a code based on our name after we have paid our license, that will unlock the crippled features.

Before we proceed we must know some basics about debugging windows. In dos we had interrupts that we put breakpoints on, in windows we have API function wich we can breakpoint on. This means that we'll have to study the Windows API reference to know what we can breakpoint on.If you have any compiler for windows programming like Borlands C++ or Microsoft Visual C++ you probably already have it. If you dont It's available from the net AND from microsofts Homepage.

Lets Register this Game:

As you can see when you choose register you are given two dialog boxes. One for your name and one for your regcode. When we press ok the text we entered in these boxes are passed to windows by some API function. A quick glimpse in the API Reference we find that Getdlgitemtext(A) and getwindowtext(A) can be used for that purpose. The (A) is used for 32Bit programs. Sink Sub is 16Bit. OK let enter Softice and put a breakpoint on Getdlgitemtext. If this doesn't work we will try getwindow text, should that fail too we could try HmemCpy. Just study the API Reference all you questions will be answered.

Bpx getdlgitemtext

As you read in the API REF some parameters are passed to getdlgitemtext one of them is the adress of the buffer where the text are passed. Enter some words in the Name Box and some numbers in the Regcode box. Now when Softice breaks we will be in the GetDlgItemText function to get out of it we press f11.

6A65                   push 0065
16                     push ss
8D46D4                 lea ax, [bp-2C]		;Username Stored Here
50                     push ax
6A28                   push 0028
9AFFFF0000             call USER.GETDLGITEMTEXT
57                     push di			;Ice pops up Here!!
6A66                   push 0066
16                     push ss
8D46C0                 lea ax, [bp-40]		;Reg code Stored Here
50                     push ax
6A14                   push 0014
9AFFFF0000             call USER.GETDLGITEMTEXT
16                     push ss
68FD09                 push 09FD
16                     push ss
68B002                 push 02B0
16                     push ss
8D46D4                 lea ax, [bp-2C]
50                     push ax
16                     push ss
68FE56                 push 56FE

As you see you'll need to scroll up a bit to see the parameter passed to GetDlgItemText. Now dump the adress where the regcode is stored.

D bp-40

You should see your code. The normal approach would be to breakpoint on that adress and see what's done with it and look for the real serail number that the computer calculated for us. That approach is what I call Serialnumber fishing. We could try that approach. Here's what happens.

Our code is copied from ds:7B40 to ds:7A9C Our code is changed from numbers to letters by a routine wich writes the new calculated code at ds:7A9C The length is calculated at least five times. The new code consisting of letters are changed to a new number

I personally got bored to death using this method. You'll grow old and ugly before you'll get to the compare where the real serial number is displayed. There are at least four diffrent codes made from our input wich is beeing transfered all over the town and the length of every code is beeing calcualted at least three times. I'm kinda lazy and eager to crack this program. when I have cracked it I can relax and study the protection and break it down to pieaces, but until then I just want to overview the scheme to get a hum of what is going on. I think that the author did this to confuse the cracker and make him bored. Guess what he succeeded. what we see here is the two locks on the front door, lets see if the backdoor is open.

Disable all breakpoints and you'll be staring at messagebox telling you that you have entered an invalid serial number. Aha that's the programmers misstake (as you are about to see). Lets put a breakpoint on the API function MESSAGEBOX. Enter some new values in the boxes and press ok. Softice pops up in the API function MESSAGEBOX step out of it and scroll up abit 'til you see this.

56                     push si
16                     push ss
68BF11                 push 11BF	;Registration Failed.....
16                     push ss
683E12                 push 123E	
6A10                   push 0010
9AFFFF0000             call USER.MESSAGEBOX
EB1A                   jmp 382D

If you dump ss:11BF you'll see the message the Messagebox told us. As you can see there is alot of messagebox functions. Here is the whole routine:

9AFFFF0000             call USER.DIALOGBOX
0BC0                   or ax, ax
7466                   je 382D
833E4A5600             cmp word ptr [564A], 0000 ;A Flag
7412                   je 37E0			 ; if correct code not  
56                     push si			 ; entered jump to beggar 
16                     push ss			 ; off
68DD10                 push 10DD
16                     push ss
681E11                 push 111E		;Registration Successfull
6A40                   push 0040
9AFFFF0000             call USER.MESSAGEBOX
EB4D                   jmp 382D
6A09                   push 0009
E8DFDE                 call 16C4
83C402                 add sp, 0002
833E485600             cmp word ptr [5648], 0000
7412                   je 3801
56                     push si
16                     push ss
683811                 push 1138
16                     push ss
68A911                 push 11A9
6A10                   push 0010
9AFFFF0000             call USER.MESSAGEBOX
EB2C                   jmp 382D
56                     push si
16                     push ss
68BF11                 push 11BF
16                     push ss
683E12                 push 123E
6A10                   push 0010
9AFFFF0000             call USER.MESSAGEBOX
EB1A                   jmp 382D  			;Here's where you 							 land
Look at this. A flag is compared with 0. If the value at [564A] is zero we will get alot of evil messsages. Alright Lets see where this flag is set.


We will land here:
		       lea ax, [bp-48]	;Our code
50                     push ax
16                     push ss
8D46A4                 lea ax, [bp-5C]	;correct code
50                     push ax
9AFFFF0000             call USER.LSTRCMPI ;who could have figured?
F7D8                   neg ax		  ; returns zero if match
1BC0                   sbb ax, ax
40                     inc ax
A34A56                 mov [564A], ax
833E4A5600             cmp word ptr [564A], 0000
7403                   je 1D50
E99400                 jmp 1DE4

Look what we found! An echo of the correct Code (HIP HIp HURRAY). Isn't this odd. A programmer that tries so hard to confuse the cracker by coping and altering our input string and then he use A simple LSTRCMPI funcion to determine if our strings are correct. I Must admit I never tought he be that Stupid. It could perhaps be that He never thought we would try a bpx LSTRCMPI. Well Well you learn as long as you live. Lets try to use the correct code as regcode. I as surprise as you, it doesn't work. Hmmn!

Let us put a breakpoint on the line above call USER.LSTRCMPI. Run anew and see what [bp-48] is.

D bp-48

Strange it's our fake code, but we entered the correct code. Ok lets change the Neg AX and SBB AX to NOP's. I know it's not a good idea to use NOP's but we are just doing it to check if we get registered. There's probably some mirror checks so lets keep our BPMB ss:564A. As you'll discover there are six mirros check, just change the NEG AX and SBB AX,AX where needed and continue execution. Look we got registered. So lets change the exe file.

When you try to run the patched file you'll get an evil message that claims one of sspro files has been damaged. Where did he get that from??!??. Oh well it seems that there is a patch check as well that has to be cracked. Man this programmer must be paranoid. Oh well lets go to work.

BPX on MessageBox. Here is where you'll land:
55                     push bp
8BEC                   mov bp, sp
FF7604                 push word ptr [bp+04]
16                     push ss
684460                 push 6044
16                     push ss
68824C                 push 4C82
6A10                   push 0010
9AFFFF0000             call USER.MESSAGEBOX
C606446000             mov byte ptr [6044], 00 ;Here's where are (after F11)
5D                     pop bp
C3                     ret

So this was a small routine and it must be called from somewhere. We trace further and proceed with ret.

56                     push si
E8CD0D                 call 1431	;????
83C402                 add sp, 0002
0BC0                   or ax, ax
7538                   jne 06A3		;well if ax is non zero we skipp the
16                     push ss		;error routine
687903                 push 0379
E84EB0                 call B6C0
83C404                 add sp, 0004
6A00                   push 0000
E82AB0                 call B6A4	;display error message
83C402                 add sp, 0002

As you see we have a JNZ after a call 1431. If ax is zero we get the error message. Lets take a look at the call 1431. The first conditional jump is right after a call, very suspious.

E85A1E                 call 32B3
0BC0                   or ax, ax
7504                   jne 1461		;ax non zero and we are good guys
33C0                   xor ax, ax
EB79                   jmp 14DA		; this jump takes us out of the 					 routine witout setting AX to 0001

The JNZ 1461 make us leave the routine with ax set to 0001. This is good, lets invert that jump, change it to a JMP 1461. And let the program run. Wow it worked we didn't get the error message and we are registered.

Ok now I am Relaxed,now I can go for a correct serial number and see why it didn't work. I'll spare you unnecessairly code. What I did what that I put a breakpoint on bp-48 which was the adress where our input was stored for the LSTRCMPI. I found out That it got that code from a file in my windows directory called queparam.inf. Looking at that file with a texteditor I saw the first change from my input to letters (the first altering with the input code). So I simply erased that code in queparam.inf. Changed back sspro.exe to an uncracked file and tried again to register it with the serial number fount at bp-5C. It worked fine.

A note for newbies that has never cracked/programmed in windows before!

In the above example we breakpointed on the API function MessageBox(A). Sometimes another function is used, Dialogbox. It is important that you study the API functions used for programming, so you know what doors you should knock on.

This is how GetDlgItemText looks like in the API reference:

The GetDlgItemText function retrieves the title or text associated with a control in a dialog box. 

UINT GetDlgItemText(

    HWND hDlg,	// handle of dialog box
    int nIDDlgItem,	// identifier of control
    LPTSTR lpString,	// address of buffer for text
    int nMaxCount 	// maximum size of string

All the variables used (hDlg, nIDDlgItem,lpString, nMaxCount) are passed in reverese order before the actual function is called. This parameters are pusched onto the Stack. As you see the lpString is passed in the middle and it truly was as we just saw in the beginning. This parameters are passed in reverse order wich means that HWND hDlg is the last push before the call to GetDlgItemText. After you have cracked some of this schemes it will be clear to you.

Greetings to +fravia and the HCU
I'm preparing a lesson for cheating
in windows Until then, Happy cracking!