Keygen Injection
by Kwazy Webbit

Good day people, Kwazy Webbit here.
It's been ages now since I wrote my last essay, and people have been pushing hard for me to finish this one. It is published in my Webbithole. May it be the first of many. You are of course all welcome to contribute to this site by sending me your essays, or links to other great RE essays you've found online that I don't yet have.

Other important news: the RE groups DREAD and ID have ceased to exist. A great loss to the cracking and coding community, but I feel certain a similar group will appear in the near future. Although so far, I haven't seen a group I would like to join. We'll see what happens, for the time being I'm happy enough without being in a group.

Time to get down to business. This isnt my autobiography after all. You're here to learn some new RE stuff.


This essay will teach you a technique I've first developed while writing my essay on cracking PaneKiller. A lot of people have come up to me recently, and told me they really enjoyed it. This technique is what I call "keygen injection".
(I called it "Kwazy Webbit style" in the other essay, but that seems arrogant and immature afterwards. Hence, I changed the name.)
Basically, what it does is the following : Sounds pretty leet, huh? Well.. Read on is all I can say.

Practical uses

As a cracker, I'm sure you already know what a keygen is. It is used for name/serial protections. It is a program that lets you enter your name in an editbox, and when you press the button the program starts calculating. It calculates the registration code that matches the entered name. (Either by brute-force or by a reversed hashing algorithm). It then enters the code in another editbox. The general idea is, as you see, fairly simple. But the calculations that go on behind the scenes differ with (almost) every target program. Some protections take quite some time and effort to completely reverse. Just think of the endless deadlistings we've all seen from time to time. It is not uncommon for a program to endlessly hash the username into a code, which is then compared with the entered registration code.
To get a valid serial for these protections is (needless to say) piss-easy. All you have to do, is find out where it compares the two codes and use a debugger to 'fish' the serial. (If you do not understand that, I suggest you read my essay 'Cracking Like Kwazy' or one of the other million available cracking essays on the subject)
To create a keygen for this type of protection however, can take a lot of effort. You have to copy the entire username-hashing routine into your keygen, and then only the trivial task of displaying the matching reg code remains.
With the technique I'm about to show you, you will be able to skip the first part. (Yup, the username-hashing..)
This will save you a lot of time and effort, simply by understanding how programs work.

Getting started

Alright, sounds nice. How do I do it?

Well, we start with serial-fishing. I'm assuming we all know how that is done. Now you've already found the memory location where it compares the serials. After that, there is usually a conditional jump. One way leads to the "Wrong Code" messagebox, and the other to the "Thank you" messagebox. You all know the routine. Now what if we changed the location that jump points to? What if we made it point to our own code at a certain location? We could run our own keygen-code, instead of displaying that "Wrong Code" messagebox, and after that just do whatever the program would have normally done.
This is all fairly abstract, maybe an example will clear it up :
Original code:

CMP EAX, EBX            ; EAX=our serial  |  EBX=correct serial
JNZ WrongCode           ; Not the same? Then display "Wrong Code"
..                      ; This is where the "Thank You" stuff is.

Code after changes:

CMP EAX, EBX            ; EAX=our serial  |  EBX=correct serial
JNZ KeyGen              ; Not the same? Then run the built-in keygen.
..                      ; This is where the "Thank You" stuff is.
..                      ; All the other code of the program.
Keygen:                 ; We place our keygen at a convenient location.
..                      ; Display the RIGHT serial.
JMP WrongCode           ; Continue the program as normal.
                        ; (We wouldn't want the program to find out
                        ; we were messing with it, now would we? =)

Of course we haven't made that built-in keygen yet, we'll get to that later. What is important now, is that you understand how you can easily intercept the jump to the "Wrong Code" box, and use it to your own advantage. There is a difficulty in doing this. For example, you have to make sure you dont run into any problems with stack and you have to preserve certain registers. Don't worry, you won't have to simply think up what will have to be done. You can simply copy what the program would have done if it were to get a wrong serial. I'll give you another (more concrete) example to illustrate :
:00401269 39058B104000            cmp dword ptr [0040108B], eax   ;our code == correct code?
:0040126F 7516                    jne 00401287                    ;jump if not equal
:00401271 6A00                    push 00000000                   ;push MB_OK
:00401273 6866104000              push 00401066                   ;push lpGoodWork
:00401278 685A104000              push 0040105A                   ;push lpYouDidIt
:0040127D FF7508                  push [ebp+08]                   ;push hWin
:00401280 E869020000              call 004014EE                   ;call MessageBoxA
:00401285 EB14                    jmp 0040129B                    ;jump past the "bad code" messagebox
:00401287 6A00                    push 00000000                   ;push MB_OK
:00401289 687D104000              push 0040107D                   ;push lpBadCracker
:0040128E 6871104000              push 00401071                   ;push lpYouSuck
:00401293 FF7508                  push [ebp+08]                   ;push hWin
:00401296 E853020000              call 004014EE                   ;call MessageBoxA
:0040129B E97D010000              jmp 0040141D
:0040141D FF7514                  push [ebp+14]                   ;push lParam
:00401420 FF7510                  push [ebp+10]                   ;push wParam
:00401423 FF750C                  push [ebp+0C]                   ;push uMsg
:00401426 FF7508                  push [ebp+08]                   ;push hWin
:00401429 E89C000000              call 004014CA                   ;call DefWindowProcA
:0040142E C9                      leave                           ;
:0040142F C21000                  ret 0010                        ;return from the WndProc
This (very simplistic) code works as follows:
It checks if the code we entered is correct. If so, It displays a MessageBox with a text "registered" or something to that effect.
If not, it displays a similar MessageBox, with a "bad code" like text.
That it displays a messagebox is not interesting to us at this point. What IS interesting however is the fact that AFTER the "bad code"-MessageBox, we see:
:0040129B E97D010000              jmp 0040141D
As we can see, it jumps to the end of the WndProc and calls the DefWindowProcA function, while keeping ESP just the way it is (no POPs, PUSHes or other funny business)

The hell you say! It pushes 4 things onto the stack!

Well, DefWindowProcA is defined as being
LRESULT DefWindowProc(
    HWND  hWnd,             // handle of window
    UINT  Msg,              // message identifier
    WPARAM  wParam,         // first message parameter
    LPARAM  lParam          // second message parameter
So, they're just parameters to the DefWindowProcA function. Also, notice that none of the parameters are dependant on registers (no PUSH EAX or anything like that).
So we can just redirect the
:0040129B E97D010000              jmp 0040141D
to point to our keygen routine.
And, as long as we preserve ESP and jump back to 0040141D afterwards, We can do whatever we want.


Well.. within limits.


Hands-on experience

I assume you understand the basic principle now. The next step is seeing this technique in action. Get the example target first. The zip file contains these files: This program was made to be without (m)any complications.. You will not find many targets in 'the real world' this easy, but I found it would be the best way to illustrate this technique.
Best to learn it clean, and then start dealing with complications.

As said, I made a program with 3 different protections..
They range from perfect for our needs (type 1), to not well suited for it (type 3). I'll show how to use this technique on all the protections.. Starting with the easiest one, going up to number 3.

Protection 1 - Plain and simple

Lets take a look at the first protection (open it up in wdasm or run through a debugger like Softice).
Its code starts at 401069h.
(I'm sorry, but this section will have a lot of deadlistings. I normally dislike essays that lean on them too much, but I saw no proper alternative in this case)

As you (hopefully) can see, it first calls GetDlgItemTextA to get the Name you entered out of the editbox.
:00401069 6A14                    push 00000014                         ;push 20 (14h)
:0040106B 8D45EC                  lea eax, dword ptr [ebp-14]           ;load address of buffer into eax
:0040106E 50                      push eax                              ;push the address of the buffer
:0040106F 6A64                    push 00000064                         ;push 100 (64h)
:00401071 FF7508                  push [ebp+08]                         ;push dword at[ebp+08]
                                                                        ;(in the wndproc, thats where the hWnd is stored)
* Reference To: USER32.GetDlgItemTextA, Ord:0102h                       ;Now that the parameters are all pushed
                                                                        ;neatly onto the stack, the program can call
:00401074 E85B020000              Call 004012D4                         ;the GetDlgItemTextA function to make it all happen.
Use win32.hlp for this kind of stuff, if you don't already know them from memory. Here's the definition of GetDlgItemTextA:
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
After that code, whatever was typed into the editbox, is now in memory at location [ebp-14]. Run the program through a debugger and check this yourself. GetDlgItemTextA returns the amount of characters it has gotten in eax. The program uses this for a quick check, and fills in the name 'lamer' if nothing was entered:
:00401079 85C0                    test eax, eax                         ;no characters gotten?
:0040107B 7473                    je 004010F0                           ;go and fill in 'lamer' into the editbox
The program now completed its first step in the registration routine. Getting the user's name. What's next? That varies from program to program.. They all basically do the exact same stuff.. But the way they do it, and the order is different occasionally.
In this case, the next part is:
:0040107D 8D55EC                  lea edx, dword ptr [ebp-14]           ;load address where name is stored into eax
:00401080 52                      push edx                              ;push that address
:00401081 E8FD010000              call 00401283                         ;call an internal function
Basically, this is a function that has as its parameter our name.
This could be almost anything.. It could be a routine that converts the name to uppercase, it might be a hashing algorithm, it could even be a simple function to return the length of the name. There's no way to know without looking in the function, and studying its code in a deadlisting...

Urgh, do we really NEED to know what it does?



For this technique I'm about to show you, you won't actually need to know what the program is doing up to where it compares the two codes.

Wow, I actually didn't expect that.

So let's just step over it in a debugger, and peek at what it returns just for the sake of being able to make an educated guess. :)
It seems to leave the string unchanged.
(to which it had access too, dont forget the ADDRESS of it was pushed, so it could have modified the contents of that as well)
It returns (in EAX of course) a mysterious number... Could perhaps be the hashed username. Again, this is pure speculation. It might just as well some random number that is never used again.

Lets just keep going. Next we see this:
:00401086 50                      push eax                              ;The mysterious number gets pushed to the stack

* Possible StringData Ref from Data Obj ->"%lu"
:00401087 6809304000              push 00403009                         ;a pointer to the string "%lu" is pushed
:0040108C 8D45E3                  lea eax, dword ptr [ebp-20]           ;load the address of ebp-20 into eax
:0040108F 50                      push eax                              ;push that address

* Reference To: USER32.wsprintfA, Ord:02A5h
:00401090 E827020000              Call 004012BC                         ;call wsprintf
To understand what this does, you will need to understand the wsprintf function. Wsprintf is a function used for making it very easy to print out numbers, characters and strings, all in one text. To do this, it uses something known as a format-control string. In short, it is a string that has special notations for letting you print out numbers as well (converting them to ascii automatically for you). For example, "%i" means the first parameter should be assumed to be a signed integer, and printed out in decimal. Here's the official definition of the function:
int wsprintf(
    LPTSTR lpOut,           // pointer to buffer for output 
    LPCTSTR lpFmt,          // pointer to format-control string 
    ...                     // optional arguments
Say for example, I want to print out a value called num as a decimal and a hexadecimal number. I would use a call similar to this:
wsprintf(lpBuffer,"decimal: %i , hexadecimal: %x",num,num);
You get the idea right? If not, you should read up on some win32 coding, there are plenty of resources available.
Whats important here, is that this function call is basically:
With the buffer located at [EBP-20]. In short, after this call the 32bit integer will be printed out as text at [EBP-20].
I guess its gonna do something with that return value after all.. :)
Back to the deadlisting:
:00401095 6A14                    push 00000014                  ;nMaxCount
:00401097 8D45EC                  lea eax, dword ptr [ebp-14]
:0040109A 50                      push eax                       ;lpString
:0040109B 6A65                    push 00000065                  ;nIDDlgItem
:0040109D FF7508                  push [ebp+08]                  ;hDlg

* Reference To: USER32.GetDlgItemTextA, Ord:0102h
:004010A0 E82F020000              Call 004012D4
I guess I've already explained this function, so I'll just quickly translate to C source to clarify:
So, the text that was in the editbox who's ID was 101 is now stored at [EBP-14] (with a maximum size of 20 characters).
A quick check using:
:004010A5 85C0                    test eax, eax
:004010A7 745B                    je 00401104
verifies that some text was actually gotten from editbox 101, and if there is the program can continue at 4010A9h (the next instruction).
The program now has our name. It also has the serial number we entered. It now has all the elements it needs to check if our serial name is correct.
Lets see where it goes from here..
:004010A9 8D45E3                  lea eax, dword ptr [ebp-20]
:004010AC 50                      push eax
:004010AD 8D45EC                  lea eax, dword ptr [ebp-14]
:004010B0 50                      push eax

* Reference To: KERNEL32.lstrcmpA, Ord:02D6h
:004010B1 E83C020000              Call 004012F2
Looking up what this function does in win32.hlp gives us the following definition:

The lstrcmp function compares two character strings. The comparison is case sensitive.
If the strings are equal, the return value is zero.

Lets look at the parameters it gets first. If you'll remember, EBP-14 holds our entered registration number, and EBP-20 is where the username hash was stored. It just compares if the two are equal.

Oh Come on. No real protection is that simple!

The same cracking method applies to larger, more chaotic protections.. This is a simple example to show how the technique itself works.
After the lstrcmp is 'ye olde eax test' (You've probably seen it a million times):
:004010B6 85C0                    test eax, eax         ;eax=0? (are the strings equal?)
:004010B8 0F8519000000            jne 004010D7          ;if not, show BAD CRACKER messagebox
Finally, we've reached the point where we finished analysis of this protection.. Now we can start the actual cracking of the target.
After this, we can use the regular methods again..
Now, lets combine all three at once... Patching the .exe so we can have both the ease of serialfishing and the flexibility of a keygenerator.
Lets start this example from the serial-fishing point of view, as it is most similar.
To get a valid serial for our name, we would use a debugger and go all the way to the lstrcmp, and simply look at the text at EBP-20 to see what our serial should have been.
Now lets use the programs structure against itself. The JNE is a definite weakness for example:
:004010B6 85C0                    test eax, eax         ;if eax is not 0, you entered the wrong code
:004010B8 0F8519000000            jne 004010D7          ;<- an easy to manipulate jump
Good, lets look at where some free space is inside the .exe file.

I wont overwrite the 'bad cracker' messagebox this time, like i did in my previous essay.
I've realised there isnt always enough space, which generally leads to bad cracking habits.
You well end up messing around too much inside the .exe possibly damaging it in the process.
I've decided to explain it properly this time, so you won't run into trouble.

Time to open up the file in HIEW for a look in the PE header (F8). Pressing (F6) brings up the object table with its properties.
You can use any program you want to to view the PE header.. I just normally use HIEW. Regardless what you use, you will find the object table to be as follows:


A PE-file (Portable Executable) consists of several objects. Each has its own location, size and flags.
One is for the data (and has read/write flags), the other for the code (with the executable flag).. Etc.
This shouldnt be a PE document, if you need info on the PE file format, there are lots of essays released already. PE.pdf is in the RE section of my site, in case you need to read up on some things.
The '.text' object is where the rest of the code is too, so its a nice place to put our keygenerator.. You can put the keygenerator into any object you want to, dont get me wrong. However since we have to pick one anyway, this one already has the executable flag that is needed to execute the code.. We might as well use it.
IF it has enough room that is.. Lets check it out:


It has a VirtSize of 2F8h , which is the size of the actual code.. And it has a PhysSize of 400h, which is the code filled up to the nearest multiple of 200h (or the file alignment for the nitpickers ;)
That gives us a total of 400h-2F8h=108h bytes of unused padding inside the '.text' object. (264 bytes in decimal)
You gotta love the PE format for leaving us reversers with all that space.
Let's also have a quick look at where we can begin to edit..
The Offset (the start of the object in file) is 400h.. The original code takes up 2F8h bytes, we can start at offset 400h+2F8h=6F8h in file. Lets round that off to a nice (and easy to remember) 700h.
Thats the location where our keygenerator will be placed. We also need one more thing, we need to know the Virtual Address of that location. Luckily, its all perfectly easy to find in the PE header. The Image Base (the address at which the program itself is loaded into memory) of the program is 400000h. The RVA (Virtual Address Relative to the Image Base) of the '.text' object is 1000h.
Another simple calculation brings us to conclude that the '.text' object will be at 400000h+1000h=401000h in memory. The keygen will thus be located at 401000h+300h=401300h (we rounded the 2F8h up to 300h remember?)
We now have everything we need:

File Offset
Virtual Address
700h100h bytes401300h

Let's figure out what we want to put inside the program.
:004010B6 85C0                    test eax, eax         ;if eax is not 0, you entered the wrong code
:004010B8 0F8519000000            jne 004010D7          ;<- an easy to manipulate jump
This is where we left off. You may also recall that the serial we need is stored at EBP-20 as a string. (If you dont believe this go to this location in softice and type 'd ebp-20' to be sure what is stored there ;)
What remains is making the code that will put the string at ebp-20 into the registration code editbox. If you've done some win32 coding, you will probably already know several ways to do this.. I'll show you a simple one.
If we look at the imported functions in this program, we can see the function SetDlgItemTextA. Looks interesting, right?
It should, the definition is:
BOOL SetDlgItemText(
    HWND hDlg,              // handle of dialog box
    int nIDDlgItem,         // identifier of control
    LPCTSTR lpString        // text to set

Great, buddy.. and where am I supposed to find all these parameters?!

To find the rest of the parameters, let's look at the call to GetDlgItemTextA to get our registration number. We need to do the opposite of it now, which of course, takes mostly the same parameters..
:00401095 6A14                    push 00000014                  ;nMaxCount
:00401097 8D45EC                  lea eax, dword ptr [ebp-14]
:0040109A 50                      push eax                       ;lpString
:0040109B 6A65                    push 00000065                  ;nIDDlgItem
:0040109D FF7508                  push [ebp+08]                  ;hDlg

* Reference To: USER32.GetDlgItemTextA, Ord:0102h
:004010A0 E82F020000              Call 004012D4
There, you see? The hDlg and the nIDDlgItem are already stored there.. Life is sweet.
Lets put some temporary code down with the things we know:
lea eax, dword ptr [ebp-20]        ;load address of the string into eax
push eax                           ;push lpString   (points to the right serial)
push 65                            ;push nIDDlgItem (the ID of the registration code editbox)
push [ebp+8]                       ;push hDlg       (the handle of the dialog)
call SetDlgItemTextA               ;<-- We dont know where this is yet...
Let's quickly look up where SetDlgItemTextA is, so we can call it and move on to the patching.
Open up the program in W32Dasm, and look at the imported functions. Locate USER32.SetDlgItemTextA and double-click on it. It will take you to a call to that function.. The program already knows how to call it, lets just follow its example. One of the calls to SetDlgItemTextA is:
* Reference To: USER32.SetDlgItemTextA, Ord:0228h
:004010FA E8E7010000              Call 004012E6
Ok, the function is located at Virtual Address 4012E6
Neat. Still no good to us in a hexeditor though, for that we need to find out its location in the .exe file.. Go to 4012E6 in W32Dasm. There are several ways to do this, one is by standing on the call and pressing the 'call' button. The we should see this:
* Reference To: USER32.SetDlgItemTextA, Ord:0228h
:004012E6 FF2524204000            Jmp dword ptr [00402024]
You may be wondering why this is a jump, and why you are not in the SetDlgItemTextA function. Well, this is known as a jump table. The address of the REAL function is stored by windows at [402024], which is where this jumps to. Why this method is used, is not relevant now, this essay is big enough as it is.
What IS relevant however, is that we want the file offset of this place, instead of the virtual address 4012E6.
If it isnt selected already, select the line by doubleclicking on it. You will now see on the bottom of your screen, in the W32Dasm status bar:

Line:580 Pg 12 and 13 of 15 Code Data @:004012E6 @Offset 000006E6 in File:InjectMe.exe

That means the Virtual Address is 4012E6 and the File Offset is 6E6
Now we have all we need.. Lets take one last look at the total keygenerator we're going to inject:
lea eax, dword ptr [ebp-20]        ;load address of the string into eax
push eax                           ;push lpString   (points to the right serial)
push 65                            ;push nIDDlgItem (the ID of the registration code editbox)
push [ebp+8]                       ;push hDlg       (the handle of the dialog)
call 6E6                           ;Call SetDlgItemTextA
Open up InjectMe.exe in HIEW, go to ASM mode at location .401300 or 700 in the file. (depending on whether you're viewing the locations as virtual addresses or file offsets, respectively. You can toggle between the two modes with Alt+F1). Once there, press F3 followed by F2 and enter the code.
Keep in mind, the syntax of HIEW is slightly different than that of W32Dasm, so the code will need to be entered like this:
lea eax, d,[ebp-20]
push eax
push 65
push d,[ebp+8]
call 6E6
Press F9 to make the changes permanent when you're done.
Now that we have our keygenerator in place, all that remains is making sure it gets called.
:004010B6 85C0                    test eax, eax         ;if eax is not 0, you entered the wrong code
:004010B8 0F8519000000            jne 004010D7          ;<- an easy to manipulate jump
Thats the jump we're going to 'hook'. We need that to jump to our keygenerator code, which we stored at offset 700h in the .exe file.
Back to HIEW, we go to edit the ASM at .4010B8 / 4B8 and make it do:
jne 700
Now it should jump to our keygenerator when a wrong serial is entered...

Do not execute the program at this point. It is unstable!

We need to do one last thing. We need to jump back and resume the program after we've run our keygenerator.
Lets see, what would have happened if we hadnt intervened with the normal course of the program... It would have jumped to 4010D7, which is File Offset 4D7 (You may want to check this yourself, go ahead. I'm in no hurry ;)
So let's just jump back there and pretend nothing has happened. Go to HIEW and edit the ASM at the end of our keygen at .40130E / 70E :
jmp 4D7
Ok, lets see what would happen now IF we were to run the program.
Seems like we left nothing out, lets do a test run.. And start the now modified InjectMe.exe
Try entering your name again, and press the 'Type 1' button. Just like you would using a keygenerator.


It should be working like predicted. We have now successfully installed a keygen right into this program.
And WITHOUT taking a lot of time to reverse the hashing algorithm. We've effectively used the program against itself.

Let's make one small change for the perfectionists out there. The Messagebox is still showing, lets remove that.
Two ways to do this are: