Another tutorial another day. This app was sent to me as a request by Din0saur so gday :)

Goto Help/About and User Key

Program will ask you for your name. So give it your name. But before clicking on Ok jump into softice and set a breakpoint on hmemcpy "bpx hmemcpy". Then click ok, sice will popup so now keep pressing untill you get to the aipict.exe process - then follow it  through past the RET'S. You should have a call somewhere around the screen your on. Remove all breakpoints (bc *) and trace through using F10 untill you return from a call and land on this code:
---------------------------
004C21A7 loc_4C21A7:                             ; CODE XREF: sub_4C20BC+D0j
004C21A7                 lea     eax, [ebp-4]
004C21AA                 mov     edx, offset aEnterExactlyAs ; "Enter EXACTLY as provided via email (or"...
004C21AF                 call    sub_403BBC
004C21B4                 mov     eax, offset dword_50FE24
004C21B9                 call    sub_403B24
004C21BE                 mov     ecx, offset dword_50FE24
004C21C3                 mov     edx, [ebp-4]
004C21C6                 mov     eax, offset unk_4C2440
004C21CB                 call    sub_4405D4
004C21D0                 test    al, al    <- You should land here
004C21D2                 jnz     short loc_4C21E4 <- dont worry this will jump
---------------------------

 We are at the start of our journey. Lets follow:

---------------------------
004C21E4 loc_4C21E4:                             ; CODE XREF: sub_4C20BC+116j
004C21E4                 mov     eax, ds:dword_50FE24 <- Mov our name into EAX
004C21E9                 call    sub_403DA0   <- Function used to get name length
004C21EE                 cmp     eax, 0Ch     <- EAX contains name length. Is it 12 chars long?
004C21F1                 jl      loc_4C23A0   <- If less then BADNAME
---------------------------

Im breaking this tutorial up into smaller peices at the request of some people who particularly didnt understand the last because it was in huge blocks ;). In the small code above we can clearly see a name length comparision. The name must be at LEAST 12 characters, otherwise its a bad name.
Lets continue past the badASSjump:

--------------------------- 
004C21F7                 lea     eax, [ebp-154h]
004C21FD                 mov     edx, ds:dword_50FE24 <- name is moved into EDX, non crutial cause we are making a keygen
004C2203                 mov     ecx, 0FFh
004C2208                 call    sub_403D7C           <- This will put our name length in 1 byte b4 our name
004C220D                 lea     edx, [ebp-154h]
004C2213                 lea     eax, [ebp-51h]
004C2216                 mov     cl, 40h
004C2218                 call    sub_402B40
004C221D                 xor     edx, edx
004C221F                 xor     ecx, ecx
004C2221                 mov     cl, [ebp-51h]       <- Name length mov into CL
004C2224                 dec     ecx                 <- Name length subtract 1
004C2225                 test    ecx, ecx            <- Make sure everythign is running smoothly which it will be
004C2227                 jle     short loc_4C223D    <- Skip Name algo - we dont want this to happen and it wont
--------------------------- 

Let me breifly explain why we are subtracting 1 from our name length. The last character in most respects SHOULD be a number. This number is a result of calculation of all other characters EXCEPT the last one. This is how the program determines if you have entered a correct name. Lets check it out:
--------------------------- 
004C2229                 lea     eax, [ebp-50h]       <- Move out name into EAX
004C222C 
004C222C loc_4C222C:                             ; CODE XREF: sub_4C20BC+17Fj
004C222C                 movzx   esi, byte ptr [eax]  <- Get character and put in ESI
004C222F                 movzx   edi, byte ptr [eax]  <- Get character and put in EDI
004C2232                 imul    esi, edi             <- Multiply both characters together and store in ESI
004C2235                 add     edx, esi             <- Add Result into EDX
004C2237                 shr     edx, 1               <- Shift Left EDX by 1
004C2239                 inc     eax                  <- Increase name so EAX points to next character
004C223A                 dec     ecx                  <- Decrease ECX (ecx contains how many characters to calculate)
004C223B                 jnz     short loc_4C222C     <- Loop untill all characters are done EXCEPT last one of course :P
004C223D 
004C223D loc_4C223D:                             ; CODE XREF: sub_4C20BC+16Bj
004C223D                 and     edx, 7               <- ands 7 bytes leaving only 1 byte left in EDX
004C2240                 add     edx, 31h             <- add 31h to EDX which will make it a number (btw 31h = '1')
004C2243                 xor     eax, eax             <- Cleanup EAX
004C2245                 mov     al, [ebp-51h]        <- Move that name length into AL
004C2248                 cmp     dl, [ebp+eax-51h]    <- Compair DL with the FINAL character in our name
004C224C                 jnz     loc_4C23A0           <- If they aint equal then BADNAME
--------------------------- 

Ahh the algo here is very easy, i think iv covered it in the comments above. At 4C2248 the result in DL (edx if u want) must be the same as the last character in your name. If it isnt change it now :). When you have changed it thats all, your name is now valid and accepted, Onto the serial:

--------------------------- 
004C2252                 mov     byte ptr [ebp-9], 1   <- Dont worry about the code from here to 004C227A
004C2256                 xor     eax, eax              <- Its not important to us
004C2258                 mov     [ebp-10h], eax
004C225B 
004C225B loc_4C225B:                             ; CODE XREF: sub_4C20BC+300j
004C225B                 cmp     dword ptr [ebp-10h], 4
004C225F                 jle     short loc_4C227A
004C2261                 call    sub_402C9C
004C2266                 fmul    ds:flt_4C23FC
004C226C                 call    sub_402A94
004C2271                 cmp     eax, 1Eh
004C2274                 jg      loc_4C23D2
004C227A 
004C227A loc_4C227A:                             ; CODE XREF: sub_4C20BC+1A3j
004C227A                 lea     eax, [ebp-8]        <- Enter your name message moved into EAX
004C227D                 call    sub_403B24   
004C2282                 lea     ecx, [ebp-8]
004C2285                 mov     edx, [ebp-4]
004C2288                 mov     eax, offset unk_4C246C
004C228D                 call    sub_4405D4          <- Display EnTER SERIAL DIALOG
004C2292                 test    al, al
004C2294                 jnz     short loc_4C22A6    <- all is ok and this will jump
004C2296                 mov     eax, [ebx+29Ch]
004C229C                 xor     edx, edx
004C229E                 mov     [eax+0Ch], edx
004C22A1                 jmp     loc_4C23D2
004C22A6 
004C22A6 loc_4C22A6:                             ; CODE XREF: sub_4C20BC+1D8j
004C22A6                 mov     eax, [ebp-8]  <- Move our SERIAL into EAX
004C22A9                 call    sub_403DA0    <- Do the get length function again, eax returns with length
004C22AE                 cmp     eax, 4        <- Is our serial at LEAST 4 characters?
004C22B1                 jl      loc_4C23A0    <- If not then BADSERIAL
--------------------------- 

Here we see that our serial must be at LEAST 4 characters long. Very simple lets go on:

--------------------------- 
004C22B7                 lea     eax, [ebp-154h]
004C22BD                 mov     edx, [ebp-8]  <- Serial moved into EDX
004C22C0                 mov     ecx, 0FFh
004C22C5                 call    sub_403D7C    <- This will put our serial length in 1 byte b4 our serial
004C22CA                 lea     edx, [ebp-154h]
004C22D0                 lea     eax, [ebp-51h]
004C22D3                 mov     cl, 40h
004C22D5                 call    sub_402B40
004C22DA                 xor     edx, edx
004C22DC                 xor     ecx, ecx
004C22DE                 mov     cl, [ebp-51h]  <- move serial length into CL
004C22E1                 dec     ecx            <- subtrace 1 from serial length (ooh this again :))
004C22E2                 test    ecx, ecx       <- Make sure nothing went wrong
004C22E4                 jle     short loc_4C22FA  <- Fuck somethign went wrong if this jumps
004C22E6                 lea     eax, [ebp-50h]    <- Move serial into EAX
004C22E9 
004C22E9 loc_4C22E9:                             ; CODE XREF: sub_4C20BC+23Cj
004C22E9                 movzx   esi, byte ptr [eax]  <- Get character from SERIAL. EXACT same as name algo
004C22EC                 movzx   edi, byte ptr [eax]  <- Get same character
004C22EF                 imul    esi, edi             <- Multiply them 
004C22F2                 add     edx, esi             <- add result to EDX
004C22F4                 shr     edx, 1               <- shift left EDX by 1
004C22F6                 inc     eax                  <- Increase position in serial by one
004C22F7                 dec     ecx                  <- Decrease how many characters left to do
004C22F8                 jnz     short loc_4C22E9     <- Jump untill all characters are complete
004C22FA 
004C22FA loc_4C22FA:                             ; CODE XREF: sub_4C20BC+228j
004C22FA                 and     edx, 7              <- Same as name one ;)
004C22FD                 add     edx, 31h            <- Add 31h to EDX
004C2300                 xor     eax, eax            <- Clean up crap
004C2302                 mov     al, [ebp-51h]       <- move serial length into AL 
004C2305                 cmp     dl, [ebp+eax-51h]   <- is DL the same character as our LAST SERIAL character?
004C2309                 jnz     loc_4C23A0          <- If not then bad serial
--------------------------- 

Thats it, at this stage once you fix your last character in your serial with the one DL contains - your program will accept both name and serial. So we can see the serial isnt calculated from the name at all - its calculated from itself as is the name. So if we want to make a keygen all we have to do is do the name shit - tell the user to enter a VALID name that you created from his name. And for the serial you can make a ramdom number larger than 4 characters long.
I choose to calculate the ramdom number from the name ;)
Check out the algo.asm which contains the calculation function i've created. You will need to insert it into your own keygen template tho, shouldnt be hard to figure out how if you understand ASM.


