By zoltan - [ECLIPSE]
Hello every one, and welcome to my first public tutorial on how to make keygenerators. With this tutorial i am going to show you how to make a keygen for a program called CAD Viewer v3.2. You can grabb it from the following location:
http://www.guthcad.com.au/viewer.htm
PART ONE: Checking the serial
After we installed the program we can start off by running the program, then Enter a name/serial in the registration field's. Next go into softice and set a bpx on GetDlgItemTextA and press the OK button. Softice pops up, F12 to return to the caller and we should be landing here:
: bpx getdlgitemtexta : F12 (pret)OK trace pass where the serial is getting pushed (:0054cb90) and set a bpm on esp. Now hit F5 and we should be landing here::0054cb6b call [USER32!GetDlgItemTextA] :0054cb71 push 3f <- we are here :0054cb73 lea eax,[ebp-0194] :0054cb79 push eax :0054cb7a push 000001ac :0054cb7f mov eax,[ebp+08] :0054cb82 push eax :0054cb83 call [USER32!GetDlgItemTextA] :0054cb89 lea eax,[ebp-0194] <- load effective adress of serial number string into eax :0054cb8f push eax <- push it on the stack :0054cb90 lea eax,[ebp-01d4] <- load effective adress of name string into eax :0054cb96 push eax <- push it on the stack
: bpm esp
:0054cd8f mov eax,[ebp+0c] <- mov serial string offset into eax :0054cd92 push eax <- push it on the stack :0054cd93 call 0054cfe9 <- call a functiondo same as above, trace pass where the serial string is being pushed and put a bpm on esp. Next we land here:
:bpm esp
:0054cff9 mov eax,[ebp+08] :0054cffc movsx eax,byte ptr [eax] <- mov first number of serial into eax :0054cfff test eax,eax <- test :0054d001 jz 0054d178 <- if it's equal to zero, then just to quit :) :0054d007 mov eax,[ebp+08] :0054d00a push eax <- push the serial string on the stack again :0054d00b call 0059da60 <- this call is calculating the lenght of the string :0054d010 add esp,04 :0054d013 mov [ebp-08],eax <- return value from the call is in eax, witch is the string length :0054d016 mov dword ptr [ebp-0c],00000000 <- clear this register :0054d01d mov dword ptr [ebp-10],00000000 <- clear this register :0054d024 jmp 0054d02c <- jumpAll this algorithm does is check each char of the serial string if they are numbers or not, if it finds that one or more of the chars are not numbers it removes them from the string. So it looks like we can tagg the serial up the arse, Anyway [ebp+0c] points to the new string and [ebp-10] holds the lenght of our new string. Lets move on ...:0054d029 inc dword ptr [ebp-0c] <- counter :0054d02c mov eax,[ebp-08] <- lenght of the serial string :0054d02f cmp [ebp-0c],eax <- compare counter with the lenght :0054d032 jge 0054d078 <- if it's greater of equal then jump out of loop :0054d038 mov eax,[ebp-0c] :0054d03b mov ecx,[ebp+08] :0054d03e movsx eax,byte ptr [ecx+eax] :0054d042 cmp eax,30 :0054d045 jl 0054d073 :0054d04b mov eax,[ebp-0c] :0054d04e mov ecx,[ebp+08] :0054d051 movsx eax,byte ptr [ecx+eax] :0054d055 cmp eax,39 :0054d058 jg 0054d073 :0054d05e mov eax,[ebp-0c] :0054d061 mov ecx,[ebp+08] :0054d064 mov al,[ecx+eax] :0054d067 mov ecx,[ebp-10] :0054d06a mov edx,[ebp+0c] :0054d06d mov [edx+ecx],al :0054d070 inc dword ptr [ebp-10] :0054d073 jmp 0054d029 <- jump
:0054d078 mov eax,[ebp-10] <- lenght :0054d07b mov ecx,[ebp+0c] <- point to new string :0054d07e mov byte ptr [ecx+eax],00 :0054d082 mov eax,[ebp+0c] :0054d085 push eax <- push serial string offset on stack :0054d086 call 0054e0dd <- hmm ...let's trace in hereI am not going to go deeper into the (go away baad cracker) algorithm because it's not important here. return from the call and we are back here:A few lines down inside the call...
:0054e0e6 mov eax,[ebp+08] :0054e0e9 push eax :0054e0ea call 0059da60 <- get lenght of serial string :0054e0ef add esp,04 :0054e0f2 cmp eax,0e <- compare it to 14 :0054e0f5 jae 0054e100 <- if it's above or equal, jump to (go away baad cracker) algorithm start. :0054e0fb jmp 0054e181 <- else jump to end of this call
:0054d08e mov eax,[ebp+0c] <- our serial string :0054d091 push eax :0054d092 call 0059da60 <- get lenght of serial, and put it in eax :0054d097 add esp,04 :0054d09a mov [ebp-10],eax :0054d09d cmp dword ptr [ebp-10],0d <- if lenght == 13 :0054d0a1 jz 0054d0ac <- then jump good boy :0054d0a7 jmp 0054d178 <- else beggar of baad cracker! :0054d0ac mov eax,[ebp+0c] :0054d0af movsx eax,byte ptr [eax+01] <- mov second number of serial into eax :0054d0b3 cmp eax,31 <- compare it to 1 :0054d0b6 jz 0054d0d1 <- jump good boy :0054d0bc mov eax,[ebp+0c] :0054d0bf movsx eax,byte ptr [eax+02] <- mov third number of serial into eax :0054d0c3 cmp eax,33 <- compare it to 3 :0054d0c6 jz 0054d0d1 <- jump good boy :0054d0cc jmp 0054d178 <- jump to beggar off lame cracker!
Alright then, so now we know that the serial needs to be at least 13 chars long and the second number of the serial needs to be equal to 1 or the third char needs to be equal to 3 ..more tagging, eheh :) let's move on ..
Ok so let's use the third char.
:bc* :bpx 0054d0c6 :F5
We enter a serial (use this: 1234555667890). Next we press the ok button and we land in sice again:
:0054d0c3 cmp eax,33 :0054d0c6 jz 0054d0d1 <- ok we take this jump now, since our third char is equal to 3 :0054d0cc jmp 0054d178 :0054d0d1 mov eax,[ebp+0c] <- our serial string :0054d0d4 movsx eax,byte ptr [eax+0a] <- mov the 11'th number of the serial into eax :0054d0d8 lea eax,[eax*4+eax-00f0] :0054d0df lea eax,[eax*4+eax] :0054d0e2 lea eax,[eax*4+eax] :0054d0e5 mov ecx,[ebp+0c] :0054d0e8 movsx ecx,byte ptr [ecx+09] <- mov the 10'th number of the serial into ecx :0054d0ec lea ecx,[ecx*4+ecx-00f0] :0054d0f3 lea ecx,[ecx*4+ecx] :0054d0f6 lea ecx,[ecx*4+ecx] :0054d0f9 lea ecx,[ecx*4+ecx] :0054d0fc shl ecx,04 :0054d0ff lea eax,[eax*8+ecx]Alright then, our checksum is finished and stored away in ebp-04. Did you understand what it did ? our checksum became:eax is now: dec=0000078000, dec stands for decimal.
:0054d102 mov ecx,[ebp+0c] :0054d105 movsx ecx,byte ptr [ecx+08] <- mov the 9'th number of the serial into ecx :0054d109 sub ecx,30 :0054d10c mov edx,ecx :0054d10e shl ecx,05 :0054d111 sub ecx,edx :0054d113 lea ecx,[ecx*4+edx] :0054d116 lea ecx,[ecx*4+ecx] :0054d119 lea ecx,[ecx*4+ecx] :0054d11c shl ecx,05 :0054d11f add eax,ecx
eax is now: dec=0000678000
:0054d121 mov ecx,[ebp+0c] :0054d124 movsx ecx,byte ptr [ecx+0c] <- mov the last number of the serial into ecx :0054d128 lea ecx,[ecx*4+ecx-00f0] :0054d12f lea eax,[ecx*2+eax]
eax is now: dec=0000678000 note the bold one ..it's the last number of our serial
:0054d132 mov ecx,[ebp+0c] :0054d135 movsx ecx,byte ptr [ecx+07] <- mov the 8'th number of the serial into ecx :0054d139 sub ecx,30 :0054d13c mov edx,ecx :0054d13e shl ecx,06 :0054d141 add ecx,edx :0054d143 lea ecx,[ecx*2+ecx] :0054d146 lea ecx,[ecx*4+edx] :0054d149 lea ecx,[ecx*4+edx] :0054d14c lea ecx,[ecx*4+ecx] :0054d14f shl ecx,06 :0054d152 add eax,ecx
eax is now: dec=0006678000
:0054d154 mov ecx,[ebp+0c] :0054d157 movsx ecx,byte ptr [ecx+0b] <- mov the 12'th number of the serial into ecx :0054d15b lea ecx,[ecx*4-00c0] :0054d162 lea ecx,[ecx*4+ecx] :0054d165 lea ecx,[ecx*4+ecx] :0054d168 add eax,ecx
eax is now: dec=0006678900
:0054d16a mov ecx,[ebp+0c] :0054d16d movsx ecx,byte ptr [ecx] <- mov the first number of the serial into ecx :0054d170 sub ecx,30 :0054d173 add eax,ecx
eax is now: dec=0006678901
:0054d175 mov [ebp-04],eax <- mov checksum into ebp-04 :0054d178 mov eax,[ebp-04] <- err ... :0054d17b jmp 0054d180 <- errrr ... this programer is drunk :/ :0054d180 pop edi :0054d181 pop esi :0054d182 pop ebx :0054d183 leave :0054d184 ret
dec=0006678901 ||||||| ||||||\_ the first number in our serial |||||\__ 13'th ||||\___ 12'th |||\____ 11'th ||\_____ 10'th |\______ 9'th \_______ 8'thOk let's moove on ...F12 out of the call and we and up here:
:0054cd93 call 0054cfe9 <- where we returned from :0054cd98 add esp,08 :0054cd9b mov [ebp-04],eax <- mov our checksum into ebp-04 :0054cd9e cmp dword ptr [ebp-04],00 <- compare it to 00This is the beggar of i was talking about before, eax was set to zero inside the call either if the serial string was greater or equal to 14 or if the second or third number in the serial was not equal to 1 or 3.
:0054cda2 jnz 0054cdbc <- jump to good boy :0054cda8 call 0054d185 :0054cdad mov dword ptr [ebp-010c],ffffffff :0054cdb7 jmp 0054ce20 <- else beggar off :0054cdbc mov eax,[ebp+08] <- AH ...finaly our namestring :0054cdbf push eax <- push it on the stack :0054cdc0 mov eax,[006ccc20] <- hmm ..a checksum value witch is: dec=2041 write it down.. :0054cdc5 push eax <- push it on the stack :0054cdc6 call 0054cc7e <- call namestring manipulation routinePART TWO: Where the real algorithm begins ...
Let's trace that call:
:.... :0054cc87 mov dword ptr [ebp-10],00000001 :0054cc8e mov dword ptr [ebp-14],00000001 :0054cc95 mov eax,[ebp+08] <- our magic value :0054cc98 mov [ebp-0c],eax <- move it into ebp-0c, let's call it checksum :0054cc9b mov eax,[ebp+0c] <- the namestring :0054cc9e push eax :0054cc9f call 005a6f60 <- strcopy (copy a string from one location to another) :0054cca4 add esp,04 :0054cca7 push eax <- the new location of the namestring :0054cca8 call 005db460 <- strlwr (convert all the char's in the name to lower case) :0054ccad add esp,04 :0054ccb0 mov [ebp-08],eax <- our new namestring witch has haad all it's char's converted :0054ccb3 mov eax,[ebp-08] <\ to lowercase :0054ccb6 push eax :0054ccb7 call 0059da60 <- get lenght of the name string :0054ccbc add esp,04 :0054ccbf mov [ebp-04],eax <- eax holds the lenght of the name string :0054ccc2 mov dword ptr [ebp-10],00000000 :0054ccc9 jmp 0054ccd1 <- jump to loop startHere is the main loop:
:0054ccce inc dword ptr [ebp-10] <- a counter witch was set to zero above :0054ccd1 mov eax,[ebp-10] :0054ccd4 cmp [ebp-04],eax <- compare the counter value to the lenght of the name :0054ccd7 jle 0054cd40 <- jump if lower or equal :0054ccdd mov eax,[ebp-10] :0054cce0 mov ecx,[ebp-08] <- our namestring :0054cce3 movsx eax,byte ptr [ecx+eax] <- move char from namestring into eax :0054cce7 mov [ebp-18],eax <- put it in ebp-18 :0054ccea cmp dword ptr [ebp-18],61 <- comapare it to 'a' :0054ccee jl 0054ccfe <- jump if lower :0054ccf4 cmp dword ptr [ebp-18],7a <- else compare it to 'z' :0054ccf8 jle 0054cd12 <- jump if lower or equal :0054ccfe cmp dword ptr [ebp-18],30 <- or compare it to '0' :0054cd02 jl 0054cd3b <- jump if lower :0054cd08 cmp dword ptr [ebp-18],39 <- or else compare it to '9' :0054cd0c jg 0054cd3b <- jump if greater :0054cd12 mov eax,[ebp-18] <- move current char into eax :0054cd15 imul eax,[ebp-14] <- multiply it with ebp-14 (witch was set to 1 before the loop) :0054cd19 add [ebp-0c],eax <- add it to ebp-0c, checksum :0054cd1c mov eax,[ebp-14] <- mov value in ebp-14 into eax :0054cd1f lea eax,[eax*4+eax] <- multiply it with 5 :0054cd22 add eax,eax <- multiply it with 2 :0054cd24 mov [ebp-14],eax <- mov eax into ebp-14 :0054cd27 cmp dword ptr [ebp-14],000186a0 <- compare ebp-14 to dec=100000 :0054cd2e jle 0054cd3b <- jump if lower or equal :0054cd34 mov dword ptr [ebp-14],00000001 <- else ebp-14 = 1 :0054cd3b jmp 0054ccce <- jump start of loop to get next letter of name
end of loop ..
:0054cd40 cmp dword ptr [ebp-08],00 <- compare offset witch ebp-08 (our namestring) points to with zero. :0054cd44 jz 0054cd56 <- jump if zero, beggar off :0054cd4a mov eax,[ebp-08] <- else mov it to eax :0054cd4d push eax <- push it on the stack :0054cd4e call 0059bd70 <- call some unimportant call :0054cd53 add esp,04 :0054cd56 cmp dword ptr [ebp-0c],0098967f <- compare our checksum to dec=9999999 :0054cd5d jle 0054cd6f <- jump if lower or equal end of function :0054cd63 sub dword ptr [ebp-0c],00989680 <- else sub checksum with dec=10000000 :0054cd6a jmp 0054cd56 <- jump to check again :0054cd6f mov eax,[ebp-0c] <- mov checksum into eax :0054cd72 jmp 0054cd77 <- err ..o well :) :0054cd77 pop edi :0054cd78 pop esi :0054cd79 pop ebx :0054cd7a leave :0054cd7b ret <- return ...
Now this should be so hard to uderstand would it ? :) Return from the call and we land here:
:0054cdc6 call 0054cc7e <- where we returned from :0054cdcb add esp,08 :0054cdce mov [ebp-0108],eax <- mov eax (checksum) into ebp-108 :0054cdd4 mov eax,[ebp-0108] <- mov it back to eax. err .. :p :0054cdda cmp [ebp-04],eax <- compare it with the checksum generated from our serial string. :0054cddd jz 0054cded <- jump if same :0054cde3 jmp 0054cda8 <- else beggar off
There we are finished, now ill show you my keygen source witch i have coded in C.
int a,i,len1; unsigned char name[100],code_string[100]; unsigned char table1[30]="x433434xxxxxx"; unsigned long checksum1=0; unsigned long checksum2=1; unsigned long checksum3=2041; len1=strlen(name); strlwr(name); if(len1>=5){ for(i=0;i=0x30&&name[i]<=0x39)||(name[i]>=0x41&&name[i]<=0x7A)){ checksum1=name[i]; checksum3+=checksum1*checksum2; checksum2*=5; checksum2+=checksum2; if(checksum2>=100001){ checksum2=1; } } } if(checksum3>=9999999){ checksum3-=10000000; } sprintf(code_string,"%06lu",checksum3); table1[0]=(a=code_string[6]); table1[7]=(a=code_string[0]); table1[8]=(a=code_string[1]); table1[9]=(a=code_string[2]); table1[10]=(a=code_string[3]); table1[11]=(a=code_string[4]); table1[12]=(a=code_string[5]); SetWindowText(hwndCode,table1); } else{ SetWindowText(hwndCode,"Name must be at least least 5 char(s)"); }
That's all folks, hope you enjoyed this tutorial as much as i did writing it :)