Seifer's Short Tutorials -- http://www.seifer666.com ===================== Cruehead's Crackme 3 ===================== Download location : http://surf.to/crackmes Protection : keyfile Level [1..10] : 2 (EASY) Tools needed : Soft Ice 3.x or better =============== 1)Introduction =============== It is the first keyfile crackme i tried to crack/keygen, and i needed some keyfile tutorial for my site, that's the reason why i write this shit today... ========================== 2)An useful definition... ========================== The crackme will check if the keyfile exists once it is executed. For this, it will simply use the WinAPI CreateFileA, described as following in the Win32 Programmer's Reference : HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDistribution, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to copy ); Okay, my goal isn't to insist on this definition or to explain you how work the function's parameters. Let's just have a look at the possible returned value : If the function fails, the return value is INVALID_HANDLE_VALUE (i.e -1d or FFFFFFFFh). So, if the file searched by the crackme doesn't exist, eax will contain FFFFFFFF, and the proggie will jump to the bad message, here we go with a stupid example : ---------------------------------------------8<------------------------------------------------- push 00000000 push FILE_ATTRIBUTE_NORMAL push OPEN_EXISTING push 00000000 push 00000000 push GENERIC_READ | GENERIC_WRITE push 00402018 ;points to "C:\Mytext.txt" Call Kernel32!CreateFileA cmp eax, FFFFFFFF jz bad_message_box_label .... ---------------------------------------------8<-------------------------------------------------- So, if the file C:\Mytext.txt doesn't exist, eax will contain the value of INVALID_HANDLE_VALUE, FFFFFFFF, and the prog will jump to the bad message. Keep this example in memory, it will be useful for the crackme. =========================== 3)The asm source code snip =========================== Here we go with the crackme. I disassembled the file to show you what checks does the proggie. To break under Soft Ice, i put a bpx on CreateFileA, and i arrive at the following code location : :00401016 6A00 push 00000000 ;parameteres of :00401018 6880000000 push 00000080 ;CreateFileA :0040101D 6A03 push 00000003 ; :0040101F 6A00 push 00000000 ; :00401021 6A03 push 00000003 ; :00401023 68000000C0 push C0000000 ; * Possible StringData Ref from Data Obj ->"CRACKME3.KEY" | :00401028 68D7204000 push 004020D7 ;here we get the name of the file to create * Reference To: KERNEL32.CreateFileA, Ord:0000h | :0040102D E876040000 Call 004014A8 ;calls the api :00401032 83F8FF cmp eax, FFFFFFFF ;does the file exist ? :00401035 750C jne 00401043 ;yah, jumps to other checks... So i create a file which i name Crackme3.key in the same directory than the crackme, and i write inside : Seifer is lame, i.e 14 bytes... I restart the same operation, this time i arrive to another check : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401035(C) | :00401043 A3F5204000 mov dword ptr [004020F5], eax :00401048 B812000000 mov eax, 00000012 :0040104D BB08204000 mov ebx, 00402008 :00401052 6A00 push 00000000 :00401054 68A0214000 push 004021A0 ;pointer to the size of the file :00401059 50 push eax :0040105A 53 push ebx :0040105B FF35F5204000 push dword ptr [004020F5] * Reference To: KERNEL32.ReadFile, Ord:0000h | :00401061 E830040000 Call 00401496 ;calls ReadFile :00401066 833DA021400012 cmp dword ptr [004021A0], 00000012 ;compares the size of the file to 12h = 18d :0040106D 75C8 jne 00401037 ;jumps to bad message if it's false So, the file has to contain 18 bytes, let's modify my keyfile... I write this time Seifer is lame heh, and restart the operation, i arrive at : :0040106F 6808204000 push 00402008 ;buffer of the file :00401074 E898020000 call 00401311 ;let's get inside Inside the mysterious call : * Referenced by a CALL at Address: |:00401074 | :00401311 33C9 xor ecx, ecx ;prepares ecx and eax :00401313 33C0 xor eax, eax ;to get some values :00401315 8B742404 mov esi, dword ptr [esp+04] ;esi points to the buffer :00401319 B341 mov bl, 41 ;constant = 65d * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00401333(C) | :0040131B 8A06 mov al, byte ptr [esi] ;moves byte of the file at esi position :0040131D 32C3 xor al, bl ;xors it with the constant :0040131F 8806 mov byte ptr [esi], al ;replaces it in the buffer :00401321 46 inc esi ;next byte :00401322 FEC3 inc bl ;constant is increased by 1 :00401324 0105F9204000 add dword ptr [004020F9], eax ;adds the xored byte to this memory location (null at beginning) :0040132A 3C00 cmp al, 00 ;if eax is null :0040132C 7407 je 00401335 ;exits the routine :0040132E FEC1 inc cl ;counts the number of xored bytes :00401330 80FB4F cmp bl, 4F ;4E is the last possible constant = 79d :00401333 75E6 jne 0040131B ;loops again if bl is less than 4F * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0040132C(C) | :00401335 890D49214000 mov dword ptr [00402149], ecx ;this memory location contains the number of xored bytes :0040133B C3 ret ;returns the call After the mysterious call : :00401079 8135F920400078563412 xor dword ptr [004020F9], 12345678 ;the sum of the xored bytes is xored with 12345678h :00401083 83C404 add esp, 00000004 ;prepares esp for a push :) :00401086 6808204000 push 00402008 ;buffer of the file :0040108B E8AC020000 call 0040133C ;another mysterious call ;) Inside the other mysterious call : * Referenced by a CALL at Address: |:0040108B | :0040133C 8B742404 mov esi, dword ptr [esp+04] ;esi points to the first byte of buffer :00401340 83C60E add esi, 0000000E ;points to the 14th byte of buffer now :00401343 8B06 mov eax, dword ptr [esi] ;eax contains last 4 bytes of the file in little endian mode :00401345 C3 ret ;returns After the mysterious call : :00401090 83C404 add esp, 00000004 ;prepares esp :00401093 3B05F9204000 cmp eax, dword ptr [004020F9] ;last 4 bytes of the file have to be = to the sum in little endian :00401099 0F94C0 sete al ;if equal, al is set to 1 :0040109C 50 push eax :0040109D 84C0 test al, al ;if eax = 0 :0040109F 7496 je 00401037 ;jumps to bad message * Possible StringData Ref from Data Obj ->"CrackMe v3.0 " ;else, good message | :004010A1 680E214000 push 0040210E :004010A6 E89B020000 call 00401346 :004010AB 83C404 add esp, 00000004 ================================= 4)Let's build some valid keyfile ================================= I want the keyfile to contain only my name : Seifer. Length of "Seifer" is 6, so the 6 first bytes of the file have to contain the result of the xor of each ascii code of my name with the constants which are associated... S e i f e r 53 65 69 66 65 72 xor 41 42 43 44 45 46 =================================== 12 27 2A 22 20 34 So the 6 first bytes of my keyfile are : 12, 27, 2A, 22, 20, 34 Let's look at the 4 last bytes of the keyfile, which have to form a little-endian dword containing the sum of the ascii codes of the chars of my name, xored with 12345678h : Sum = 53 + 65 + 69 + 66 + 65 + 72 = 25Eh Sum xor 12345678h = 12345426h, so the 4 last bytes of my keyfile have to be : 26, 54, 34, 12. But what are the 8 bytes between my xored name and the final dword ?? We have to indicate the proggie that my name is finished, or it wont congratulate me, so the 7th byte xored with the associated constant has to be equal to zero. This constant is 47h, and 47 xor 47 = 0, so the value for this byte is 47h. Just let's replace the other bytes with null bytes, that won't change anything... A working keyfile is finally : 12 27 2A 22 20 34 47 00 00 00 00 00 '*" 4G.......&T 00 00 26 54 34 12 4. Run the crackme, a messagebox appears : Cracked by Seifer! ==================================== 4)Coding your own keyfile generator ==================================== Finally, let's code a pretty keyfile generator in C++ :). --------------------------------------------8<--------------------------------------------------- #include #include #include using namespace std; int main() { cout << "Seifer Lame DOS Keygens : " << endl << "CrueHead Crackme 3 Keyfile Generator : " << endl; cout << "Enter your name : "; char name[14]; cin >> name; unsigned len = strlen(name); unsigned i; if(len == 0) { cout << "You gotta enter something !!"; cin.get(); cin.get(); return 0; } if(len >= 14) { cout << "You gotta enter less than 14 chars !!"; cin.get(); cin.get(); return 0; } unsigned char cypher[14] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E}; unsigned char buffer[18] = ""; ofstream keyfile("Crackme3.key"); if(!keyfile) { cerr << "The keyfile couldn't be created !"; return -1; } for(i = 0; i < len; ++i) { buffer[i] = unsigned char(name[i] ^ cypher[i]); } buffer[len] = cypher[len]; unsigned long sum = 0; for(i = 0; i < len; ++i) sum += name[i]; sum ^= 0x12345678; for(i = 0; i < 4; ++i) { buffer[14+i] = unsigned char(sum % 0x100); sum /= 0x100; } for(i = 0; i < 18; ++i) keyfile << buffer[i]; keyfile.close(); cout << "\nKeyfile successfully generated !!"; cin.get();cin.get(); return 0; } -----------------------------------------------8<------------------------------------------------ Pretty simple source code, if you have any question, ask me :). ================ 5)Last thoughts ================ Here come the greetings part, it might be long : French dudes : tHE Analyst : doh, i discovered cracking with your tuts, and i'll thank you for this forever MagicRaph : come on you gay, i wanna fuck you TaMaMBolo : i'll always be faster than you in +o setting :) eP-180 : hey, what about paying you a dance ? StatMan : HeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHeHHe - Seifer(c) Jack : imul eax, eax, 02 is an xor :) GanjaMan : I wanna smoke you forever promethee : 170 chars for your crackme's serial... It will help me to spend winter nights :) Armanoid : nice supplier, continue like this my friend vrom : you love sex right ;) ? goto www.citedusexe.com, nice site :p Tex| : when do we meet ?? Lucifer48 : why did u leave ? where will i read leeto tuts now ;) ? TSCube : come on, let's keygen some nice crackme again Other dudes : Warez Pup, DnNuke, Falcon, Mercution, BiSHoP, ManKind, r!sc, dark wolf, Acid_Cool_178, Volatility, VisionZ, FatBoyJoe, [yAtEs], Grugq (je boude:), SantMat, amante, Cellular, vylent, BMonkey, MindPhaze, Fenorez, Blind Angel, BoomBox, kanabis, Eternal Bliss, Boon, aremus, Blaze, Bladey, KaKtuZ, xor, Sushi, LordOfLa, Lazarus, karlitoXZ, Crudd, C_DKnight, AbsoluteB, norika, morrinth, Tresn`i, Dawai, alpine, JB007,... and all I have forgotten. seifer666@caramail.com ICQ : #61545376 Seifer[HellForge]