Pages

Sunday, June 8, 2014

KGM2 CrackMe Analysis

Hello folks,

In our last post, we saw the interesting Hardcrypt crackme, we did some analyses and ended up writing a keygen for it. Today we are going to do the same for another easy CrackMe, but this time, a bit trickier.

Today's CrackMe named KGM2, written by Kirjava (yes, the guy we mentioned in our last article), you can find the CrackMe in the reference section in the end of this post.

Now let's start by opening KGM2, and getting a simple idea on its functionalities, and the way the CrackMe behaves with our input.



As we can see, I entered (hello) as a username and (world) as a serial, clicked the Check button, nothing happened, that might be a length problem, maybe the application accepts a specific length input? After trying other combinations with different lengths, nothing special happened again, now let's get our hands dirty a bit and start our reversing process.

First, as always let's load it into PEiD, it seems a normal executable with only one section (.text section). Now load it into our lovely immunity dbg and start the journey.
After running it within a debugger, we start by checking for strings in the process's memory, but as we can see in the screenshot below, nothing special in here:



Now, let's be a bit more tougher, by looking into the functions the CrackMe calls:



Looks like a very usual Win32 API functions, and we can notice some famous Windows API functions like CreateWindowExA ,GetDlgItemTextA, MessageBoxA,VirtualProtect (Self-Modifying code?), etc...
If you know a bit about Windows Messaging system structure, function GetDlgItemTextA() should ring a bell, this function is the one that gets your input from a created Win32 windows process, and saving it into a buffer in memory. Perfect, we are seeing two calls to the previous mentioned function, which is really expected since we have only 2 input fields in the CrackMe. Let's start tracing one of them:



As we can see, the first call is for getting the username input field, saving it into the buffer 0x004016A4, while the second GetDlgItemTextA() call is for getting the serial input field, saving it into the buffer 0x004018A4. Let's check our work by placing a breakpoint after the serial input function, on line 0x00401392, run our application, writing our input, and here we go, the debugger paused at our breakpoint, if we dumped the 0x004016A4 and 0x004018A4, we must be able to see our input. From now on, we are going to stepover in order to understand what encryption/hashing code our inputs are passing by during their way to the final check.

Let's also assume, that the serial is saved into a buffer pointed to by the variable (serial), and the username by the variable (name), so that we can point, access and alter their values whenever we need without mentioning stack and/or other CPU registers.

We can see in the code between the two GetDlgItemTextA() calls, that it simply saves the length of our username into memory address 0x004016E0, and checks if it's lower than 0xC (12), so that if we entered a username with 12 or more characters, the program won't even get our serial, and will finish the program silently (how did we know that? this is a very easy tracing you can do on your own). So far so good, after getting the serial input field, it checks if the serial is 0xC bytes, which means that our serial must be exactly 12 bytes, otherwise it (again) finishes silently. It then makes another check on the length of the username field, if it's below 8, it will finish silently. So we now know that the username length must be bigger than or equal to 8 and less than 12 digits, and the serial must be exactly 12 digits.



It now jumps to the address highlighted in the above screenshot (0x004013A6), this chunk does nothing more than getting the last character in our username, multiplying it by the length and saving it back into the first character, in a C-notation it can be written that way:

name[0]=name[strlen(name)-1]*strlen(name);

In the end of that block, we can see a jump to the address 0x004013EE, but wait, this jump is already situated at the address 0x004013ED, and the opcode of the jump is EB FF, so that if we executed that jump ,we would pad on the opcode 0xFF , this is the opcode for a CALL instruction, let's dump the address 0x004013EE:



As we expected, the jump wasn't the real instruction to be executed, this is a debugging obfuscation technique in order to confuse the debugger, the real jump is done to a routine that starts on address pointed to by register EAX, which is 0x00401251.



Now, I won't be going through each of this routine's instruction, this should be too easy for anyone knowing assembly, I will only highlight what the whole routine does, it simply changes the value of each byte of the username buffer using this simple loop:
temp=0;
for(i=0;i<8;i++)
{
    if(i==0)
    {
        temp=len(name)*len(name);
        temp=temp*4;
        temp=temp^len(name);
        temp=temp*name[i];
        name[i]=temp;
    }
    else
    {
       temp=name[i-1];
       name[i]=name[i]^temp;
    }
    name[i]=name[i]%0x1A;
}

Just the last part of this routine might be interesting, starting from address 0x004012DA to 0x004012FB, this routine changes something at address 0x0040104C, if you dumped that address after this loop, you are going to find a very fancy thing, I won't be saying it.

In the end of the 0x00401251 routine, we can find on address 0x0040130A a jump to the address 0x0040130B, the same obfuscation trick, if we dump'd the jump address:


A call to pointer at EBX, which will be a call to 0x00401166, Here we are going to find a new routine:



Again, I won't be explaining each instruction apart, this long routine is simply doing so:

name[8]='-';
name[9]=name[7];
name[9]^=(len(name)*name[6]);
name[9]%=0x0A;
name[10]=name[8-name[9]];
name[9]+=0x30;
name[10]^=name[9];
name[10]%=0x0A;
name[10]+=0x30;
name[11]=name[4];
name[11]^=name[3];
name[11]%=0x0A;
name[11]+=0x30;

So far so good, at the end of that routine, we can find another jump that uses the same trick as the two jumps before, it calls the routine at the address 0x004010BF:





This is the main checking routine, it's checking the first 8 bytes of the name (altered version of the username input), adding the value 0x41 to them, and comparing them with the first 8 bytes of the serial, after that it compares the 4 bytes (those bytes generated by the routine 0x00401166), with the last 4 bytes of our serial, and if all checks succeeded, it creates a new thread that starts its execution at address 0x004010A6, with parameter 0x0040104C (remember? this is the interesting loop we talked about earlier), we can notice that this thread only calls MessageBox that congratulates us for our good work.

Now, that we analyzed every bit of our program, we can write a very simple keygen for it:
http://pastebin.com/SRqBXnUN

We can now try our generator on username (redseees), with the output serial :




In the end, there are some functions used and questions we didn't discuss, I'm leaving that to the reader so he can notice and practice more on assembler language, some logical questions might be why the author of the CrackMe used VirtualProtect() and VirtualAlloc(), why he's creating threads rather than normal sequential execution flow?

If you have any question or want to know the answers of the last questions, you can drop me a message on secmania{at}hotmail{dot}com.

References:
---------------
-KGM2 by Kirjava CrackMe :
[http://crackmes.de/users/kirjava/kgm2/]

1 comment: