This is a tutorial explaining how to crack Hellforge Crackme II by LaZaRuS. I cracked it using w32dasm and SoftIce, because a combination of a debugger and a assembler is normally the fastest method. The tutorial is divided into two parts. The first one shows how to crack it in a dirty way, it only takes three minutes to do it, but after doing it you have learnt nothing. So there is a second part where it is explained how the serial is generated from the user name. Finally the source code in C for a serial generator is given. First of all I must apologize for my bad English, since it is not my mother tongue. THE DIRTY WAY Well, the first thing to do is to run the program and try to register it. If you do so you get a window with two inputs, one for the username and one for the serial, and a button to confirm them. Let's introduce any username and any serial and click the button. A messagebox appears saying "Wrong Code". Ok, we suppose the strings are not encripted, so run w32dasm and search for this string. We go to the following part of the program (the comments are for the second part of this tutorial) : :0042685D 51 push ecx :0042685E 51 push ecx :0042685F 51 push ecx :00426860 51 push ecx :00426861 51 push ecx :00426862 53 push ebx :00426863 56 push esi :00426864 57 push edi :00426865 8BD8 mov ebx, eax :00426867 33C0 xor eax, eax :00426869 55 push ebp :0042686A 68CC694200 push 004269CC :0042686F 64FF30 push dword ptr fs:[eax] :00426872 648920 mov dword ptr fs:[eax], esp :00426875 33C0 xor eax, eax :00426877 A390864200 mov dword ptr [00428690], eax ;ACC=0 :0042687C 8D55FC lea edx, dword ptr [ebp-04] :0042687F 8B83B0010000 mov eax, dword ptr [ebx+000001B0] :00426885 E8C6B3FEFF call 00411C50 :0042688A 8B45FC mov eax, dword ptr [ebp-04] :0042688D E896CCFDFF call 00403528 :00426892 A394864200 mov dword ptr [00428694], eax :00426897 A194864200 mov eax, dword ptr [00428694] :0042689C E86FEDFDFF call 00405610 :004268A1 83F804 cmp eax, 00000004 :004268A4 7D1B jge 004268C1 ;LESS THAN 4 CHARACTERS END :004268A6 6A00 push 00000000 * Possible StringData Ref from Code Obj ->"Sorry" | :004268A8 B9DC694200 mov ecx, 004269DC * Possible StringData Ref from Code Obj ->"Wrong Code" | :004268AD BAE4694200 mov edx, 004269E4 :004268B2 A124864200 mov eax, dword ptr [00428624] :004268B7 E84CB3FFFF call 00421C08 :004268BC E9E8000000 jmp 004269A9 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004268A4(C) | :004268C1 8D55FC lea edx, dword ptr [ebp-04] :004268C4 8B83B0010000 mov eax, dword ptr [ebx+000001B0] :004268CA E881B3FEFF call 00411C50 :004268CF 8B45FC mov eax, dword ptr [ebp-04] :004268D2 0FB600 movzx eax, byte ptr [eax] :004268D5 8BF0 mov esi, eax ;ACC=1st CHARACTER :004268D7 C1E602 shl esi, 02 ;ACC=4*ACC :004268DA 8D3476 lea esi, dword ptr [esi+2*esi] ;ACC=3*ACC :004268DD 8D55F8 lea edx, dword ptr [ebp-08] :004268E0 8B83B0010000 mov eax, dword ptr [ebx+000001B0] :004268E6 E865B3FEFF call 00411C50 :004268EB 8B45F8 mov eax, dword ptr [ebp-08] :004268EE 0FB64001 movzx eax, byte ptr [eax+01] :004268F2 8D0480 lea eax, dword ptr [eax+4*eax] :004268F5 8D0480 lea eax, dword ptr [eax+4*eax] :004268F8 03F0 add esi, eax ;ACC=ACC+25*2nd CHARACTER :004268FA 8D55F4 lea edx, dword ptr [ebp-0C] :004268FD 8B83B0010000 mov eax, dword ptr [ebx+000001B0] :00426903 E848B3FEFF call 00411C50 :00426908 8B45F4 mov eax, dword ptr [ebp-0C] :0042690B 0FB64002 movzx eax, byte ptr [eax+02] :0042690F 03C0 add eax, eax :00426911 03F0 add esi, eax ;ACC=ACC+2*3rd CHARACTER :00426913 8D55F0 lea edx, dword ptr [ebp-10] :00426916 8B83B0010000 mov eax, dword ptr [ebx+000001B0] :0042691C E82FB3FEFF call 00411C50 :00426921 8B45F0 mov eax, dword ptr [ebp-10] :00426924 0FB64003 movzx eax, byte ptr [eax+03] :00426928 6BC00B imul eax, 0000000B :0042692B 03F0 add esi, eax ;ACC=ACC+11*4th CHARACTER :0042692D 893590864200 mov dword ptr [00428690], esi :00426933 A194864200 mov eax, dword ptr [00428694] :00426938 E8D3ECFDFF call 00405610 :0042693D 8B1590864200 mov edx, dword ptr [00428690] :00426943 0FAF1590864200 imul edx, dword ptr [00428690] ;ACC=ACC*ACC*NUMBER OF CHARACTERS :0042694A F7EA imul edx :0042694C A390864200 mov dword ptr [00428690], eax :00426951 8D55EC lea edx, dword ptr [ebp-14] :00426954 A190864200 mov eax, dword ptr [00428690] :00426959 E806EBFDFF call 00405464 ;CONVERT TO ACC DECIMAL :0042695E 8B45EC mov eax, dword ptr [ebp-14] :00426961 50 push eax :00426962 8D55FC lea edx, dword ptr [ebp-04] :00426965 8B83B4010000 mov eax, dword ptr [ebx+000001B4] :0042696B E8E0B2FEFF call 00411C50 :00426970 8B55FC mov edx, dword ptr [ebp-04] :00426973 58 pop eax :00426974 E8FBCAFDFF call 00403474 ;COMPARE SERIALS (GIVEN SERIAL==ACC) :00426979 7518 jne 00426993 ;IF NOT EQUAL END :0042697B 6A00 push 00000000 ;ELSE CONGRATULATIONS * Possible StringData Ref from Code Obj ->"Congratulations" | :0042697D B9F0694200 mov ecx, 004269F0 * Possible StringData Ref from Code Obj ->"You did it" | :00426982 BA006A4200 mov edx, 00426A00 :00426987 A124864200 mov eax, dword ptr [00428624] :0042698C E877B2FFFF call 00421C08 :00426991 EB16 jmp 004269A9 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00426979(C) | :00426993 6A00 push 00000000 * Possible StringData Ref from Code Obj ->"Sorry" | :00426995 B9DC694200 mov ecx, 004269DC * Possible StringData Ref from Code Obj ->"Wrong Code" | :0042699A BAE4694200 mov edx, 004269E4 :0042699F A124864200 mov eax, dword ptr [00428624] :004269A4 E85FB2FFFF call 00421C08 In 42697d we can see our goal, the correct serial message. So we have to arrive there. Who can stop us? Only two jumps, one at 4268a4 and other 426979. If the first jump is not done we'll arrive at the "Wrong Code" message box, so this jump must be done. On the contrary if the second jump is taken we'll arrive to the "Wrong Code" message box, so this one shouldn't be done. Ok, we write down the file offsets of these memory positions, run an hexeditor and change jge for jmp, and jne for nop. Ok, it's cracked. Three minutes. Any serial number will do the job. But, as I said before, patching a crackme is stupid. Crackmes are written in order to others learn cracking it, and we have learnt nothing. So let's understand the program. THE RIGHT WAY This time we'll use SoftIce since string manipulations are easier to follow with a debugger. Well, although we don't know how the rutine works, we know it begins at 42685d, so let's put a bpx there. We introduce a name and a serial and click the button. SotIce breaks. We trace pressing F8 until we arrive at 426897, where our username address is loaded into eax. If we do "d eax" we'll see it in the data window. The next line calls a function which counts the number of characters of the username introduced. If it's <4 then show the "Wrong Code" message, other case go on. Now we know what the jge at 4268a4 does. At 4268c1 the string manipulation begins. At 4268d2 the first character is loaded into eax, after some manipulations it is added to the accumulator which is at 428690. The same for the second character at 4268ee but with different manipulations. The 3rd one at 42690b and the fourth one at 426924, again with different manipulations each one. When we arrive at 42692d we have in the accumulator (memory address 428690): ACC=12*(1st character)+25*(2nd character)+2*(3rd character)+11*(4th character) Finally when we arrive at 426954 we have: ACC=ACC*ACC*Number of characters of the username Then some transformation with this value (contained in eax) is done at 426974 and the result is compared with our serial if it is equal we get the "You did it" message, if not we get the "Wrong code" messagebox. Which is this transformation ? If we try to trace it we'll see we arrive at new calls, trace them and again new calls, and again ... Too much time. Let's think a little. We put a bpx at this function and run the program with different usernames. The result is a string which only contains numbers, any character. Simple coincidence ? Perhaps the tansformation is simply the decimal value of the hex. contained in eax. Take a calculator to test it and ... Bingo!, it is. Now we have everything to do the serial generator. Here is the code in C: /*HF CRACKME SERIAL GENERATOR BY ELT */ #include #include main() { char user[20]; long acc=0,len=0; clrscr(); /*user input*/ puts("ElT HF crackme serial generator 99.03.28"); puts("User name:"); gets(user); /*Generates the sum*/ acc=user[0]*12+25*user[1]+2*user[2]+0x0b*user[3]; while(user[len]) len++; acc=acc*acc*len; /*displays it in decimal*/ printf("\nYour serial is: %ld",acc); }