Cracking tutorial for advanced #3 - by acetone^drn KEYGENNING GOLDWAVE 4.11 TARGET http://www.goldwave.com TOOLS SoftICE W32Dasm HIEW (preferred hex editor) INTRODUCTION This tutorial will show you how to write a keygen for GoldWave 4.11. It will show you how its keygen algorithm works, and how to translate it to C. Okay, it's late so I'm going to cut to the chase :) The routine which calculates your code is at 42A800. Here's what happens: * Referenced by a CALL at Address: |:0042A932 | :0042A800 55 push ebp :0042A801 8BEC mov ebp, esp :0042A803 51 push ecx :0042A804 53 push ebx :0042A805 56 push esi :0042A806 57 push edi :0042A807 33DB xor ebx, ebx :0042A809 33F6 xor esi, esi :0042A80B 33C0 xor eax, eax :0042A80D 8945FC mov dword ptr [ebp-04], eax :0042A810 8B5508 mov edx, dword ptr [ebp+08] :0042A813 52 push edx This basically does a little bit of initialisation (unimportant for our purposes). :0042A814 E81F640800 call 004B0C38 ; eax = length of first name :0042A819 59 pop ecx :0042A81A 85C0 test eax, eax :0042A81C 7507 jne 0042A825 ; jump if eax != 0 :0042A81E 33C0 xor eax, eax ; clear eax (think about :0042A820 E9D2000000 jmp 0042A8F7 ; jump to end of routine Obviously, this is a simple check to make sure we've entered something for our first name. * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A81C(C) | :0042A825 8B5508 mov edx, dword ptr [ebp+08] :0042A828 03D0 add edx, eax :0042A82A EB07 jmp 0042A833 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A83B(C) | :0042A82C 0FBE0A movsx ecx, byte ptr [edx] :0042A82F 03C8 add ecx, eax :0042A831 03D9 add ebx, ecx * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A82A(U) | :0042A833 4A dec edx :0042A834 8BC8 mov ecx, eax :0042A836 83C0FF add eax, FFFFFFFF :0042A839 85C9 test ecx, ecx :0042A83B 75EF jne 0042A82C Okay, this is the first real bit of the calculation routine. Step through it with SoftICE, get a feel for what's happening. What it does is add together the ASCII values of all the characters in your first name. Each time, it also adds the position number, with the first character having the number 0. Example: A C E T O N E 41 + 43 + 45 + 54 + 4F + 4E + 45 = 1FF 00 + 01 + 02 + 03 + 04 + 05 + 06 = 15 1FF + 15 = 214 This value is then stored in EBX. :0042A83D 8B4508 mov eax, dword ptr [ebp+08] :0042A840 83C019 add eax, 00000019 :0042A843 50 push eax ; push second name to stack :0042A844 E8EF630800 call 004B0C38 ; eax = length of second name :0042A849 59 pop ecx :0042A84A 85C0 test eax, eax :0042A84C 7507 jne 0042A855 ; jump if eax != 0 :0042A84E 33C0 xor eax, eax ; clear eax :0042A850 E9A2000000 jmp 0042A8F7 ; jump to end Another check, this time to see if we've entered a second name. * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A84C(C) | :0042A855 8B5508 mov edx, dword ptr [ebp+08] :0042A858 8D540219 lea edx, dword ptr [edx+eax+19] :0042A85C EB07 jmp 0042A865 A little unimportant initialisation. * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A86D(C) | :0042A85E 0FBE0A movsx ecx, byte ptr [edx] :0042A861 03C8 add ecx, eax :0042A863 03F1 add esi, ecx * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A85C(U) | :0042A865 4A dec edx :0042A866 8BC8 mov ecx, eax :0042A868 83C0FF add eax, FFFFFFFF :0042A86B 85C9 test ecx, ecx :0042A86D 75EF jne 0042A85E In the same way that the routine above calculated a value for our first name, so this routine calculates a value for our second name. :0042A86F 8B4508 mov eax, dword ptr [ebp+08] :0042A872 50 push eax :0042A873 E8C0630800 call 004B0C38 ; eax = length of first name :0042A878 8BF8 mov edi, eax ; edi = eax :0042A87A 8B4508 mov eax, dword ptr [ebp+08] :0042A87D 83C019 add eax, 00000019 :0042A880 59 pop ecx :0042A881 50 push eax :0042A882 E8B1630800 call 004B0C38 ; eax = length of second name :0042A887 03F8 add edi, eax ; edi = edi + eax :0042A889 59 pop ecx :0042A88A 8BC7 mov eax, edi :0042A88C 8BD0 mov edx, eax :0042A88E 8B4508 mov eax, dword ptr [ebp+08] As you can see, the length of both names have been added together and stored in EDX. There are registers with important information at the moment: EBX = first name total ESI = second name total EDX = combined length of names Now for some more calculation: :0042A891 C1E204 shl edx, 04 ; shift edx left by 4 :0042A894 8D1452 lea edx, dword ptr [edx+2*edx] ; edx=3*edx :0042A897 8D1492 lea edx, dword ptr [edx+4*edx] ; edx=5*edx :0042A89A 8D1492 lea edx, dword ptr [edx+4*edx] ; edx=5*edx :0042A89D 8D1492 lea edx, dword ptr [edx+4*edx] ; edx=5*edx :0042A8A0 03DA add ebx, edx ; ebx = ebx + edx This code shifts edx left by 4, multiplies edx by 177 (=3*5*5*5), and adds it to ebx (our first name total, remember). We continue... :0042A8A2 8B55FC mov edx, dword ptr [ebp-04] :0042A8A5 8BCB mov ecx, ebx :0042A8A7 C1E104 shl ecx, 04 :0042A8AA 8D0C49 lea ecx, dword ptr [ecx+2*ecx] :0042A8AD 8D0C89 lea ecx, dword ptr [ecx+4*ecx] :0042A8B0 8D0C89 lea ecx, dword ptr [ecx+4*ecx] :0042A8B3 8D0C89 lea ecx, dword ptr [ecx+4*ecx] :0042A8B6 03F1 add esi, ecx This sets ECX to the value of EBX and repeats the process, this time adding it to esi (our second name total). :0042A8B8 8BDE mov ebx, esi :0042A8BA 8D741032 lea esi, dword ptr [eax+edx+32] :0042A8BE 85DB test ebx, ebx :0042A8C0 7425 je 0042A8E7 Not sure why it does this bit; never mind :) * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0042A8E5(C) | :0042A8C2 8BC3 mov eax, ebx :0042A8C4 33D2 xor edx, edx :0042A8C6 B91A000000 mov ecx, 0000001A :0042A8CB F7F1 div ecx ; eax = eax / ecx ; edx = eax % ecx :0042A8CD 80C241 add dl, 41 ; edx = edx + 41 :0042A8D0 8BC3 mov eax, ebx :0042A8D2 8816 mov byte ptr [esi], dl ; esi points to our ; correct serial; ; this means that dl ; is the ASCII value ; of a char of the ; correct serial :0042A8D4 33D2 xor edx, edx :0042A8D6 B91A000000 mov ecx, 0000001A :0042A8DB 46 inc esi :0042A8DC F7F1 div ecx :0042A8DE FF45FC inc [ebp-04] :0042A8E1 89C3 mov ebx, eax :0042A8E3 85DB test ebx, ebx :0042A8E5 75DB jne 0042A8C2 This code continually divides EAX by 1A. Each time, 41 is added to the remainder to give a character of the correct serial. This continues until we cannot divide any more. The rest of the code is unimportant; we have our serial! Fully-commented C code for a keygen follows. Note that I've removed some unnecessary intermediate steps (moving values from one variable to another, for example): ---{code start}--- #include #include #include int main() { /* initialise variables */ char firstname[25]; char secondname[25]; char code[15]; int eax, ebx, ecx, edx, esi = 0; int loopvar; /* temp loop variable */ /* print message and instructions*/ printf("\nGoldWave 4.11 keymaker by Acetone^DRN\n" ); /* prompt and accept user input */ printf("Enter first name: "); gets(firstname); printf("Enter second name: "); gets(secondname); /* make sure they've entered something for both names */ if (strlen(firstname) == 0 || strlen(secondname) == 0) { printf("\nYou need to enter something for both names!"); getch(); printf("\n"); return(0); } /* make sure they haven't entered names that are too long */ if (strlen(firstname) > 24 || strlen(secondname) > 24) { printf("\r\nMaximum 24 characters per name!"); getch(); printf("\r\n"); return(0); } /* calculate value of first name */ /* notice that we convert each letter to upper-case */ /* GoldWave only accepts upper-case names */ for (loopvar = 0 ; loopvar < strlen(firstname) ; loopvar++) ebx = ebx + toupper(firstname[loopvar]) + loopvar; /* calculate value of second name */ for (loopvar = 0 ; loopvar < strlen(secondname) ; loopvar++) esi = esi + toupper(secondname[loopvar]) + loopvar; /* add name lengths together */ edx = strlen(firstname) + strlen(secondname); edx = strlen(firstname) + strlen(secondname); /* first set of calculations */ edx = edx << 4; edx = edx * 0x177; ebx = ebx + edx; ecx = ebx; /* second set of calculations */ ecx = ecx << 4; ecx = ecx * 0x177; esi = esi + ecx; ebx = esi; /* final calculation loop */ eax = ebx; for (loopvar = 0 ; eax > 0 ; loopvar++) // loop while eax is not zero { edx = eax % 0x1A; /* set edx to remainder of eax */ eax = eax / 0x1A; /* divide eax by 0x1A */ code[loopvar] = edx + 0x41; /* set current code char to edx + 0x41 */ } /* print code */ printf("Password: %s", code); /* wait for a keypress then quit */ getch(); printf("\r\n"); return(0); } ---{code end}--- Well, that's all for now. I hope that's been some help to you :) -Acetone^DRN