Funny crackme
Well, it’s Saturday night and I still don’t have internet connection. However, I found a few crackmes on a flash drive. Here I’ll write my solution to “Harry Potter Crackme by Shalamandra” since I don’t have anything better to do. Now that you’re reading this is probably Monday but anyway. This crackme should not take you more than 10 minutes since it’s just a tiny application with no special protection. The algorithm seems pretty simple… It goes like this:
1) Print some stuff on the console
2) Read a string
3) Do some rearrangements
4) Compare it with an existing one using strcmp()
5) If they contain the same string, print the congrats message else terminate
Of course you can just patch the final jump of step 5 which you can see here (from IDA Pro):
.text:00401723 mov [esp+88h+var_84], eax
.text:00401727 mov [esp+88h+var_88], edx
.text:0040172A call strcmp
.text:0040172F test eax, eax
.text:00401731 jnz short loc_401749
And loc_41749 is the location of the function which prints out the error message which you can see below:
But this is not allowed if you read the provided NFO file. The author explicitely states:
Rules: Find the correct serial. No patching allowed.
Which I found it nice since this is a really easy one and allowing patching will just made it a completely lame crackme. So, let’s have a look at the known string passed on strcmp(). This can be found easily by setting two breakpoints at the two arguments passed by the stack to the strcmp() library routine at addresses 0x00401723 and 0x00401727 (I did this using OllyDbg). The known string is this:
EAX=0022FF50, (ASCII "I am Lord Voldemort")
Which is stored in a character array on the stack. Now that we know this we can start reversing this funny rearrangement algorithm. It’s extremely easy to spot and reverse it since it’s composed by exactly 38 (19 x 2) MOV instructions and the above string has length of 19 bytes not including the NULL termination. Anyway, here is the substitution:
.text:00401694 movzx eax, [ebp+var_3B]
.text:00401698 mov [ebp+var_68], al
.text:0040169B movzx eax, [ebp+var_45]
.text:0040169F mov [ebp+var_67], al
.text:004016A2 movzx eax, [ebp+var_43]
.text:004016A6 mov [ebp+var_66], al
.text:004016A9 movzx eax, [ebp+var_44]
.text:004016AD mov [ebp+var_65], al
.text:004016B0 movzx eax, [ebp+var_36]
.text:004016B4 mov [ebp+var_64], al
.text:004016B7 movzx eax, [ebp+var_3F]
.text:004016BB mov [ebp+var_63], al
.text:004016BE movzx eax, [ebp+var_47]
.text:004016C2 mov [ebp+var_62], al
.text:004016C5 movzx eax, [ebp+var_42]
.text:004016C9 mov [ebp+var_61], al
.text:004016CC movzx eax, [ebp+var_39]
.text:004016D0 mov [ebp+var_60], al
.text:004016D3 movzx eax, [ebp+var_3D]
.text:004016D7 mov [ebp+var_5F], al
.text:004016DA movzx eax, [ebp+var_41]
.text:004016DE mov [ebp+var_5E], al
.text:004016E1 movzx eax, [ebp+var_40]
.text:004016E5 mov [ebp+var_5D], al
.text:004016E8 movzx eax, [ebp+var_38]
.text:004016EC mov [ebp+var_5C], al
.text:004016EF movzx eax, [ebp+var_3A]
.text:004016F3 mov [ebp+var_5B], al
.text:004016F6 movzx eax, [ebp+var_37]
.text:004016FA mov [ebp+var_5A], al
.text:004016FD movzx eax, [ebp+var_46]
.text:00401701 mov [ebp+var_59], al
.text:00401704 movzx eax, [ebp+var_3E]
.text:00401708 mov [ebp+var_58], al
.text:0040170B movzx eax, [ebp+var_3C]
.text:0040170F mov [ebp+var_57], al
.text:00401712 movzx eax, [ebp+var_48]
.text:00401716 mov [ebp+var_56], al
.text:00401719 mov [ebp+var_55], 0
It performs NULL termination on the last instruction. Anyway, I know that most of you will find this boring and to be honest if I had internet connection I’ll probably found it boring too but right now I had nothing better to do than writing this. Anyway, the substitution goes like this:
Original Position New Position --------------------------------------- 0 18 1 6 2 15 3 1 4 3 5 2 6 7 7 10 8 11 9 5 10 16 11 9 12 17 13 0 14 13 15 8 16 12 17 14 18 4
So, if you like that source code reconstruction ideas when doing crackmes I believe the above source code should be looking something like this:
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { char *usr_str, str[20] = {"I am Lord Voldemort"}; printf("Print the cool ASCII art\nEnter the serial: \n"); gets(usr_str); // Yeah... an overflow... char *tmp_buf = strdup(usr_str); // and a missing return value check... usr_str[0] = tmp_buf[13]; usr_str[1] = tmp_buf[3]; usr_str[2] = tmp_buf[5]; usr_str[3] = tmp_buf[4]; usr_str[4] = tmp_buf[18]; usr_str[5] = tmp_buf[9]; usr_str[6] = tmp_buf[1]; usr_str[7] = tmp_buf[6]; usr_str[8] = tmp_buf[15]; usr_str[9] = tmp_buf[11]; usr_str[10] = tmp_buf[7]; usr_str[11] = tmp_buf[8]; usr_str[12] = tmp_buf[16]; usr_str[13] = tmp_buf[14]; usr_str[14] = tmp_buf[17]; usr_str[15] = tmp_buf[2]; usr_str[16] = tmp_buf[10]; usr_str[17] = tmp_buf[12]; usr_str[18] = tmp_buf[0]; usr_str[19] = 0; if (!strcmp(usr_str, str)) printf("You're awesome!\n"); else printf("Ultra fail!\n"); free(tmp_buf); return 0; }
This is a completely crappy C code but it’s an abstract demonstration of the crackme (which was written in C++ by the way). Now, that you have everything just find the serial. :P
Here is a screenshot from the crackme:
Nice one to spend a couple of minutes. :)
Heh I did this one a couple days ago. It was nothing special. I did like the big logo at the top though.
Rik
April 14, 2009 at 05:50