Tools:
SoftIce windows version 1.9
Ultraedit 32
Target is available from: GAMES DOMAIN.
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 download.com 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.
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.
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
etc
etc
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 landLook 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.
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!
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
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.
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