This KeygenMe I’ve got personally from the author (MaxX0r). Thank you for such a nice gift and congrats for a good job!
The difficulity level is 3 (according to Crackmes.de).
It doesn’t contain any advanced crypto, but is nicely obfuscated, self-modifying and containing some defensive features. Due to this properties, it have pretty high detection ratio on VirusTotal. But I ensure you, it is not a malware (just a false positive)! If you still have doubts, you can read thought the code (I will try to describe it clearly in my tutorial).
Author sets several achievement levels (see full list).
Here I would like to present my solution for GOLD, that is:
* create a working keygen
* remove the nag screen
KeyGen source: http://dumpz.org/1222943/
+ the version with Nag removed: http://hasherezade.net/crackmes/KeygenMe%20V7_noNag.zip
Tutorial 1 – removing nag screen
Due to the fact, that I would like to make a detailed tutorial, that is easy to follow for beginners, I divided it in 2 parts. This one is dedicated to removing Nag screen. In the next part, I will describe keygenning. If you wish to see explanation of obfuscation techniques only, you can go directly to the end of the article.
First, I loaded the KeygenMe into ImmunityDebugger:
and searched for “All referenced text strings” (left mouse button click, then: Search for -> All referenced text strings)
It could possibly show as the place, where the “Success” message is displayed. But, no luck this time – no such thing is on the list. Taking a closer look, we notice, that neither the Nag message is present. For sure they are encrypted/obfuscated somehow!
By the way, I spotted some other interesting strings: ntdll.dll, wcsnmp, memset, wscsncpy, comctl32.dll, InitCommonControls, SeDebugPrivilege. It seems, the application loads some functions dynamically. We will not go in details right now, but lets keep it in mind.
Let’s first focus on finding the place, where the Nag and SuccessMsg are stored.
IDA graphs are going to be helpful, so I loaded the same file now to IDA.
Graph of start function have a weird shape, which suggest that some transitions between code chunks are obfuscated.
Also, there is some long piece of code on the stage, which seems to load some obfuscated string (WindowName). It moves a lot of bytes into consecutive variables (probably forming some buffer) . Then calls a function and performs some decoding with it’s help- I given to the called function a name _decode
The body of _decode function is simple. However, it also contain some obfuscation – by breaking standards of argument passing. Usually ECX register is used as a counter, ESI – as a source and EDI as destination. But not here, as you can see…
Let’s see Xrefs to this function – maybe it will help in finding Nag and SuccessMessage:
As we see it is called from 3 functions:
- start – as we see above, it decodes WindowName
Let’s take a closer look at the 2 remaining calls.
sub_401856: Function _decode is called in several places. However it decodes some small (max 5-bytes long) chunks… But we are searching for the strings, so let’s skip it for now… (anyways this function looks interesting. It refers to function like GetDlgItemTextW – seems to be fetching user input and then processing it. Accidentally, we found the key verification function! So, from now I will refer sub_401856 as KeyVerification)
Let’s move on:
sub_402551: looks much more promising. It have two paths of execution, one of them is decoding some lengthy buffer (probably a string) + refer to MessageBoxW.
It is referred from the start – so, seems to be the Nag rather than the SuccessMsg.
As we see, in this case the reference doesn’t mean a direct call. The address is pushed on the stack. After that, some other addresses are also pushed, and then there is RET. It is some complex version of calling via PUSH-to-RET. The function that is called from here is in reality sub_4013B0:
The function takes 2 parameters. It above case, one is the address 4029F6 and the other is the handle to CreateWindowExW. The address of our interest: sub_402551(the potential Nag) is not among them. To see how it is called, we must first understand how the sub_4013B0 works.
Inside we see the heap allocation and changing access rights to allocated space. Seems, some code is going to be written.
Also, two functions are called by the handlers, that are dynamicaly filled somewhere else:
Some dynamic analysis will be required (and I prefer doing it in ImmunityDebugger). So I loaded it in Immunity, set breakpoint at 4013B0 and run. The mysterious handlers got filled, and now we see that
- dword_40300C -> ntdll.memcpy
- dword_403000 -> ntdll.memset
Let’s see what they are used for. Here is dump of parameters:
memcpy: |dest = 001F7268 |src = USER32.CreateWindowExW \n = 5 memset: |s = USER32.CreateWindowExW |c = E9 -> JMP \n = 1 memset: |dest = USER32.7685EC7D |src = 0012FEB0 \n = 4 memset: |s = 001F726D |c = E9 -> JMP \n = 1 memcpy: |dest = 001F726E |src = 0012FEB0 \n = 4
Do you see the “code stealing”? First, 5 bytes from the beginning of CreateWindowExW is copied into allocated space. It is overwriten by the jump (E9 = opcode of JMP) to the address, stored on the stack (at 12FEB0). Then, another JMP is writen – this time into the allocated space. Let’s have a look how the CreateWindowExW looks after the modification:
Do you recognize the address of the jump? It’s sub_402551(the potential Nag)! So, finally we found how it is called – whenever CreateWindowExW is called, it jumps to our procedure first.
Let’s see what is written into the allocated space:
001F7268 8BFF MOV EDI,EDI 001F726A 55 PUSH EBP 001F726B 8BEC MOV EBP,ESP 001F726D E9 0F7A6676 JMP USER32.7685EC81
It is the stolen prolog and redirection to the rest of the code of CreateWindowExW. Ok, now we know, that original CreateWindowExW can be now called by refering to the address 1F7268.
Coming back to the 4013B0 (from now I will refer is as: StealCode)
I also set the breakpoint on the return, and follow where the navigation goes next:
004029F6 MOV DWORD PTR SS:[EBP-34],EAX 004029F9 MOV EAX,DWORD PTR SS:[EBP-34] 004029FC MOV DWORD PTR DS:,EAX 00402A01 PUSH KeygenMe.004017BE 00402A06 PUSH DWORD PTR DS:[<&USER32.CharUpperW>] 00402A0C PUSH KeygenMe.00402A17 00402A11 PUSH KeygenMe.004013B0; StealCode 00402A16 RETN
Another “code stealing” is performed. Now the affected procedure is CharUpperW. I don’t think it is necessary to go again in details, just set a breakpoint at the end of StealCode and see what was overwritten:
At the beginning of CharUpperW the redirection has been placed:
7686E981 JMP KeygenMe.004017BE
The procedure at 4017BE takes as a parameter a buffer of characters. It contains a big switch, which is substituting some characters by the others, by the defined pattern. I named it MixCharacters. So now we know, that CharUpperW leads to calling MixCharacters.
After the second “code stealing”, navigation goes to:
00402A17 MOV DWORD PTR SS:[EBP-38],EAX
(in the procedure named start by IDA). It leads to the chunk that is decoding WindowName, which we already saw in the previous part of the research.
Then, the CreateWindowEx is called (as we found previously – it is hooked, and leads to execution of sub_402551(the potential Nag). And then the message dispatching loop is executed.
Let’s set a breakpoint at call CreateWindowExW. It’s parameters are redirected to 402551. Now we can notice, that the parameter, deciding which path should be followed, is in reality the WindowWidth*!
* to be explicit: CreateWindow creates not Windows only, but a variety of controls, like labels, buttons, etc.
To sum up:
- if the control width is different than 0x78 = 120 -> Execute original CreateWindowEx.
- if the window width == 120 -> Execute the Nag.
Knowing this, we can remove a nag window by simply patching this check (at 40255E), and changing conditional jump to unconditional.
Obfuscation and defensive technics
The thing I enjoyed the most in this KeygenMe, was its obfuscation and set of defensive techniques (similar techniques are used by malware, that’s why AV systems picked on this).
I noted following:
- dynamically loaded imports
(Handles to some functions were dynamically loaded and stored in variables. Then, calls were made via this variables – to make static analysis more difficult)
Using loaded function (example):
- self-modifying code
Inside the key verification function we can find some points of code, that ends with Infinite loops (opcodes: EB FE)
It would not make any sense… However, during program execution, this places are modified, and they are converted to jumps to the continuation of the code!
- calling functions in non-obvious way, i.e. complex “push-retn”
- “stolen code”, import hooking
- beginning of the imported function is stolen (removed, and copied inside the KeygenMe space)
- it is substituted by the call to “a proxy function” (belonging to a KeygenMe)
- original code of imported function is called after the “proxy function” finished execution
Let’s see all this elements on the example of the KeygemMe:
User32.dll -> CharUpperW (original):
User32.dll -> CharUpperW (modified):
stolen code + jump to rest of the function:
Function inside the KeygenMe, calling the stolen code via saved pointer (refered on the graph as: Application.myFunction ):
- time-based anti-stepping protection:
RDTSC is called and it’s result is saved in a variable. In another place, RDTSC is called second time, and the result is compared with the saved one.
If the time difference is > 70000h, the process of generating key is distorted: