How To KeyGen Password Keeper 5.6

Allright lets start. This is my first tutorial... I am sorry for misspellings, grammar mistakes and everything else that is wrong. I hope in this text are not so much mistakes but they would explain my english grade. :)
Okidok Password Keeper is very easy to keygen and so a good example to write a tutorial about it. The onliest thing you will need to follow this tutorial is SoftIce.
Ok lets start Password Keeper .... it appears a nag "UNREGISTERED USER". I hope we could change this :D We open the register dialog box (menu: Help/Register...) and insert something in the three edit fields. I entered Apus, TCA and as serial 305419896 (0x12345678). After pushing "OK" a stupid message box "An invalid software .. bla bla bla" appears.
Now it is time for SoftIce .... we set a breakpoint on hmemcpy (SI: bpx hmemcpy) and push "OK" again. SI breaks three times. (It is not important for PasswordKeeper but nevertheless a nice hint: trace in the hmemcpy function until you reached "repz movsd" clear the bpx on hmemcpy and set it on the instruction before "repz movsd". The advantage is you can now look (SI: d ds:si) what string is copied).
Back to Password Keeper: After a little bit tracing we noticed that the message box appears on the call 40a130 at offset 412878

0041285E push edi ................. Pointer to the organisation string
0041285F push esi ................. Pointer to the name string
00412860 call 00417B80 ............ Calculate the serial
00412865 add esp, 00000008
00412868 cmp ebx, eax ............. Comparison of the two serials
0041286A pop edi
0041286B je 0041288A .............. Jump if serials are equal
0041286D push 0000EACF
00412872 push 00001388
00412877 push ebp
00412878 call 0040A130 ............ message box

Logically the last cmp before the MessageBox decided wether the serial is right or wrong. Btw I found my serial (0x12345678) in ebx. Hehe it seems that the value in eax is then the right serial but we want a keygen so we take a deeper look at the call 417b80.

00417B80 mov eax, dword ptr [esp+04]
00417B84 push esi
00417B85 mov esi, dword ptr [0042CADC] ... start value of the serial 0x0abcdef0
00417B8B push eax ........................ pointer to the name string
00417B8C or esi, 00000378 ................ esi --> 0x0abcdff8
00417B92 call 00416750 ................... calculate number for the name string
00417B97 mov ecx, dword ptr [esp+10]
00417B9B add esi, eax .................... add the number from the name string to esi
00417B9D push ecx ........................ pointer to the organisation string
00417B9E call 00416750 ................... calculate number for the organisation string
00417BA3 add esp, 00000008
00417BA6 add eax, esi .................... add esi (serial until this moment) to eax (number for the organisation string)
00417BA8 pop esi
00417BA9 ret


Lets dismantle this function ... the dword in 42cadc (417b85) seems to be the constant value 0xabcdef0 this value is "ored" with 0x378 (417b8c). Result is 0x0abcdff8. This value is something like a start value for the final serial. The program adds afterwards the return value from the call 416750 (at offset 417b92 and 417b9e) to this value. The call 416750 is first executed with the name string as parameter and then with the organisation string.
Ok what did we know about the key routine until now:
- the start value of the serial is 0x0abcdfff8
- it adds an value for both strings which is generated in the call 416750
- we have to take a deeper look at the call 416750 :D

00416750 push ecx
00416751 push ebx
00416752 mov ebx, dword ptr [esp+0C]
00416756 push esi
00416757 xor esi, esi
00416759 push ebx
0041675A mov dword ptr [esp+0C], esi
* Reference To: KERNEL32.lstrlenA, Ord:0308h
0041675E Call dword ptr [004210A8] ................ get string length --> returns length in eax
00416764 test ebx, ebx
00416766 je 004167B7
00416768 test eax, eax
0041676A je 004167B7
0041676C xor edx, edx
0041676E test eax, eax
00416770 jle 004167B7
00416772 push ebp
00416773 push edi
00416774 mov esi, 0042629C ........................ pointer to string which is used in the calculation
00416779 mov edi, 00000001
0041677E sub esi, ebx ............................. subtract the two pointer --> result is a delta offset
00416780 mov ecx, ebx ............................. ecx pointer to string
00416782 sub edi, ebx ............................. subtract ebx from edi ... later it use edi to get the number of runs (416793)
* Referenced by a (U)nconditional or (C)onditional Jump at Address: 004167AD(C)
00416784 movsx ebx, byte ptr [esi+ecx] ............ get a byte from data string2 (first run - first byte, second run ...)
00416788 movsx ebp, byte ptr [eax+edx+00426264] ... get a byte from data string1 (length+run - first byte...)
00416790 imul ebx, ebp ............................ multiply the two bytes, result to ebx
00416793 lea ebp, dword ptr [edi+ecx] ............. get the curent run + 1
00416796 imul ebx, ebp ............................ multiply ebx with this value
00416799 movsx ebp, byte ptr [ecx] ................ get the byte from our string (first run - first byte ...)
0041679C imul ebx, ebp............................. multiply ebx with this byte
0041679F mov ebp, dword ptr [esp+10] .............. restore the serial
004167A3 add ebp, ebx ............................. add ebx to serial
004167A5 inc edx................................... increase the run variable
004167A6 inc ecx .................................. ""
004167A7 cmp edx, eax ............................. eax = string lenth;
004167A9 mov dword ptr [esp+10], ebp .............. save serial
004167AD jl 00416784 .............................. jump until string length has reached
004167AF mov eax, ebp ............................. put serial in eax before the program leave the function

Allright what we see is that the program first get the string length. This value is stored the complete time in eax. Another thing that we noticed is that the program used two strings for the calculation:
char string1[] = "#serB&nz|mfM1/5(!sd$Mq.{s]+sFjtKpzSdtzoXqmb^Al@dv:s?x/";
char string2[] = "|b!pz*ls;rn|lf$vi^Axpe)rx5aic&9/2m5lsi4@0dmZw94cmqpfhw";
After some checks it calculate the delta offset at 41677e from string2 (see above) and our string. At offset 416782 PassKeeper subtracts from edi (edi = 1) the offset from our string. The program did this because it multiplied the serial every time when offset 416793 is reached with the current run value (1,2,3..) and to get this number it adds at offset 416793 to edi the offset to our string, which is increased frequently. (example: edi = 1 - offset; ebp = offset+edi --> ebp = 1)
Lets go on. At offset 416784 the program gets a byte from string2: first time it is reached first byte, second time ... and so. This happens because of the increase of ecx at 4167a6. This byte is multiplied with the byte from string1 (offset 416788). The byte from string1 is catched the same way only here the length of the string (eax) is added to the offset.
At least to this result of the multiplcation is the current byte of our string multiplied (offset 41679c) uff :P
Allright lets summarize:
- it repeats until edx and the length of the string are equal
- every time the serial is multiplied with the number of runs (1,2,3,4,5...)
- every time the serial is multiplied with a byte from ser2 (first, second, third....)
- every time the serial is multiplied with a byte from ser1 (first+length, second+length,...)
- every time the serial is multiplied with the byte from our string (first, second, third...)
I think thats are enough information to start coding the keygen routine. I have code it in C and it works fine ... I hope =)

char string1[] = "#serB&nz|mfM1/5(!sd$Mq.{s]+sFjtKpzSdtzoXqmb^Al@dv:s?x/";
char string2[] = "|b!pz*ls;rn|lf$vi^Axpe)rx5aic&9/2m5lsi4@0dmZw94cmqpfhw";
DWORD Serial = 0x0abcdff8;
for(i = 0;i < strlen(Name);i++)Serial += string1[i+strlen(Name)] * string2[i] * Name[i] * (i+1);
for(i = 0;i < strlen(Org);i++)Serial += string1[i+strlen(Org)] * string2[i] * Org[i] * (i+1);


The tutorial ends now, if you have any question contact me realapus@gmx.de and again sorry for all grammar mistakes I am afraid of scrolling up ....

- Apus -

greetz flyz out to all I know :D