winzip 8.1 keygen tut

so first i have to excuse for my bad english, but i hope you understand/learn anyway something.

tools needed:
- softice
- a c-compiler (i use lcc-win32)
- a little knowledge of the c language
- w32dasm or ida

ok i hope you have read phalanx's winzip 8.1 tutorial, its excellent especially if you haven't that much experience with softice.

in phalanx tut we got a valid serial for our name out of the memory. now we want to code a keygen, so we need to know where our valid serial was generated. since the valid serial was generated out of our name we know that the serial must be computed between the call to GetDlgitemTextA which gets our name & the compare between valid & fake serial.

from phalanx tut we know that the serialcheck begins at offset 0040B65C


:0040BD26   call 0040B65C       ; Check the registration code 
:0040BD2B   test al, al
:0040BD2D   jz 0040BD7C         ; JUMP! The registration code string is invalid.

so load wintip32.exe with softice symbol loader, press load & ignore the warning.
you break at the programs entrypoint & now set a breakpoint at adress 40B65C "bpx 40B65C" & exit softice with F5/Ctrl-D/X.
softice will pop up 3 times before winzip is runing, this is because the 3!! serial checks on winzip startup to test if you are registred or not. ok once you are in winzip go to the registration dialog enter name & fake serial
i use:

name:   noesis
serial: 12345678

press OK and we break at adress 40B65C :) direct at the beginning of the serial checking routine.
now lets trace trough the code & try to understand whats happening:

:0040B65C 55                      push ebp
:0040B65D 8BEC                    mov ebp, esp
:0040B65F 81EC0C020000            sub esp, 0000020C
:0040B665 8065FF00                and byte ptr [ebp-01], 00
:0040B669 803D90C74C0000          cmp byte ptr [004CC790], 00  --> test if name = 0
:0040B670 53                      push ebx		       
:0040B671 56                      push esi		       --> push name on stack
:0040B672 57                      push edi		       --> push fake serial on stack
:0040B673 0F84FB000000            je 0040B774                  --> if name = 0 jmp to not valid
:0040B679 8D45E8                  lea eax, dword ptr [ebp-18]
:0040B67C 50                      push eax		       |
:0040B67D 68A8E74B00              push 004BE7A8                |
:0040B682 E85862FFFF              call 004018DF                }-- generate string MuradMeraly (blacklisted name??)
:0040B687 8D45E8                  lea eax, dword ptr [ebp-18]  |
:0040B68A 50                      push eax
:0040B68B E8D07A0800              call 00493160                --> do weired things with the string MuradMeraly
:0040B690 83C40C                  add esp, 0000000C
:0040B693 83F814                  cmp eax, 00000014
:0040B696 7211                    jb 0040B6A9
:0040B698 BF20C74A00              mov edi, 004AC720
:0040B69D 6A21                    push 00000021
:0040B69F 57                      push edi
:0040B6A0 E8C5F60000              call 0041AD6A
:0040B6A5 59                      pop ecx
:0040B6A6 59                      pop ecx
:0040B6A7 EB05                    jmp 0040B6AE                
:0040B6A9 BF20C74A00              mov edi, 004AC720
:0040B6AE 8D85F4FDFFFF            lea eax, dword ptr [ebp+FFFFFDF4]
:0040B6B4 BB90C74C00              mov ebx, 004CC790
:0040B6B9 50                      push eax
:0040B6BA 53                      push ebx
:0040B6BB E850030000              call 0040BA10
:0040B6C0 8D85F4FDFFFF            lea eax, dword ptr [ebp+FFFFFDF4]
:0040B6C6 50                      push eax                     --> eax = noesis
:0040B6C7 E8947A0800              call 00493160                --> get namelenth
:0040B6CC BEC8000000              mov esi, 000000C8            --> esi = C8 (= 200decimal)
:0040B6D1 83C40C                  add esp, 0000000C            
:0040B6D4 3BC6                    cmp eax, esi                 --> compare 6 (namelength) with  200 (maxnamelenth?)
:0040B6D6 720A                    jb 0040B6E2                  --> if namelenth < 200 go on
:0040B6D8 6A23                    push 00000023
:0040B6DA 57                      push edi
:0040B6DB E88AF60000              call 0041AD6A
:0040B6E0 59                      pop ecx
:0040B6E1 59                      pop ecx
:0040B6E2 8D85F4FDFFFF            lea eax, dword ptr [ebp+FFFFFDF4]  --> eax = noesis
:0040B6E8 50                      push eax                           --> push on stack
:0040B6E9 8D45E8                  lea eax, dword ptr [ebp-18]        --> eax = MuradMeraly
:0040B6EC 50                      push eax                           --> push on stack
:0040B6ED E8AE2D0900              call 0049E4A0                      --> check if entered name = MuradMeraly
:0040B6F2 59                      pop ecx                           
:0040B6F3 85C0                    test eax, eax                      --> if name = MuradMeraly 
:0040B6F5 59                      pop ecx
:0040B6F6 7504                    jne 0040B6FC                       --> dont jump
:0040B6F8 C645FF01                mov [ebp-01], 01
:0040B6FC 8D45E8                  lea eax, dword ptr [ebp-18]        --> eax = MuradMeraly
:0040B6FF 50                      push eax                           --> push on stack
:0040B700 68B8E74B00              push 004BE7B8
:0040B705 E8D561FFFF              call 004018DF                      --> generate string bcom (???)
:0040B70A 8D45E8                  lea eax, dword ptr [ebp-18]        --> eax = bcom 
:0040B70D 50                      push eax                           --> push on stack
:0040B70E E84D7A0800              call 00493160                      --> do some stuff with bcom
:0040B713 83C40C                  add esp, 0000000C
:0040B716 83F814                  cmp eax, 00000014
:0040B719 720A                    jb 0040B725
:0040B71B 6A27                    push 00000027
:0040B71D 57                      push edi
:0040B71E E847F60000              call 0041AD6A
:0040B723 59                      pop ecx
:0040B724 59                      pop ecx
:0040B725 8D45E8                  lea eax, dword ptr [ebp-18]      --> eax = bcom
:0040B728 50                      push eax                   --> push on stack
:0040B729 53                      push ebx                   --> ebx = noesis / push on stack
:0040B72A E8712D0900              call 0049E4A0              --> compare is input name (noesis) = bcom
:0040B72F 59                      pop ecx
:0040B730 85C0                    test eax, eax              --> if its not the same
:0040B732 59                      pop ecx
:0040B733 750E                    jne 0040B743               --> jump
:0040B735 FF15F0C14A00            Call dword ptr [004AC1F0]  
:0040B73B A801                    test al, 01
:0040B73D 7404                    je 0040B743
:0040B73F C645FF01                mov [ebp-01], 01
:0040B743 6A14                    push 00000014
:0040B745 8D45E8                  lea eax, dword ptr [ebp-18] --> eax = bcom
:0040B748 6A00                    push 00000000               --> push 0 on stack
:0040B74A 50                      push eax                    --> ppush bcom on stack
:0040B74B E850800800              call 004937A0               --> do some stuff with bcom....
:0040B750 56                      push esi
:0040B751 8D85F4FDFFFF            lea eax, dword ptr [ebp+FFFFFDF4] --> eax = noesis !!
:0040B757 6A00                    push 00000000               -->push 0 on stack
:0040B759 50                      push eax                    --> push noesis on stack
:0040B75A E841800800              call 004937A0               --> do soeme stuff with noesis 
:0040B75F 83C418                  add esp, 00000018           
:0040B762 807DFF00                cmp byte ptr [ebp-01], 00
:0040B766 7413                    je 0040B77B
:0040B768 E8D7080000              call 0040C044
:0040B76D 80258DBD4C0000          and byte ptr [004CBD8D], 00
:0040B774 32C0                    xor al, al
:0040B776 E9F5000000              jmp 0040B870
:0040B77B 8D85BCFEFFFF            lea eax, dword ptr [ebp+FFFFFEBC] 
:0040B781 50                      push eax              
:0040B782 53                      push ebx                 -> ebx = noesis push on stack
:0040B783 E8ED000000              call 0040B875            -> do some stuff with noesis :))
:0040B788 8D85BCFEFFFF            lea eax, dword ptr [ebp+FFFFFEBC] 
:0040B78E 50                      push eax                 -> check value of eax here
						              type "d eax" whooha looks like a winzip serial :)
						              
ok so much code so little info but now it seems that we have found the call to the serial-generation.
we also know tha our name is compared to "MuradMeraly" & "bcom" berhaps this are blacklisted names?
also our entered name length is comapred with C8 (200 decimal) this is perhaps the length of longest valid name you could enter...


lets do on with searching the serial algo.						              
				
:0040B781 50                      push eax              
:0040B782 53                      push ebx                 -> ebx = noesis push on stack
:0040B783 E8ED000000              call 0040B875            -> do some stuff with noesis :))



now let's take al look what happens at 40B875 and it seems here we have the algo:



:0040B875 55                      push ebp
:0040B876 8BEC                    mov ebp, esp
:0040B878 8B4D08                  mov ecx, dword ptr [ebp+08] --> ecx = noesis
:0040B87B 53                      push ebx
:0040B87C 56                      push esi
:0040B87D 57                      push edi
:0040B87E 8A11                    mov dl, byte ptr [ecx] -> get first char of name in dl
:0040B880 33DB                    xor ebx, ebx  -> ebx = 0
:0040B882 33C0                    xor eax, eax  -> eax = 0
:0040B884 8BF1                    mov esi, ecx  -> esi = noesis
:0040B886 33FF                    xor edi, edi  -> edi 0 //edi is used as an counter here

loop begin

:0040B888 84D2                    test dl, dl   -> if dl = 0 
:0040B88A 7410                    je 0040B89C   ->  all chars of name were processed & jump
:0040B88C 660FB6D2                movzx dx, dl  -> dl = dx 
:0040B890 0FAFD7                  imul edx, edi -> edx = edx * edi 

// edx is the current char of name and edi is the inde of the char in our case  n = 0// o = 1// e = 22 etc...

:0040B893 03DA                    add ebx, edx  -> add edx to ebx
:0040B895 8A5601                  mov dl, byte ptr [esi+01]  -> get next char of name
:0040B898 47                      inc edi        -> increase counter
:0040B899 46                      inc esi
:0040B89A EBEC                    jmp 0040B888   -> next turn

loop end 

so far its simple. every char of our name is multiplied with it's index (0,1,2,3,4,...) and was then added to ebx

for noesis we get:

n -> 6E * 0 = 0      || ebx = ebx + 0 = 0
o -> 6F * 1 = 6F     || ebx = ebx + 6F = 6F
e -> 65 * 2 = CA     || ebx = ebx + CA = 6F + CA = 139
s -> 73 * 3 = 159    || ebx = ebx + 159 = 139 + 159 = 292
i -> 69 * 4 = 1A4    || ebx = ebx + 1A4 = 292 + 1A4 = 436
s -> 73 * 5 = 23F    || ebx = ebx + 23F = 436 + 23F = 675

ok now we know how the first value will be calculated but sadly theres anotherone, an the calculation is little bit more complicated:

:0040B89C C6058BC74C0001          mov byte ptr [004CC78B], 01
:0040B8A3 8BF1                    mov esi, ecx               ;esi = ecx = noesis
:0040B8A5 8A09                    mov cl, byte ptr [ecx]     ; get first char of name in cl
:0040B8A7 84C9                    test cl, cl                ; if cl = 0
:0040B8A9 7419                    je 0040B8C4                ; all chars of name are processed so jump out of loop
:0040B8AB 660FB6C9                movzx cx, cl               ; cx = cl
:0040B8AF 6821100000              push 00001021              ; push 1021 on stack...we see later whats that for
:0040B8B4 51                      push ecx                     
:0040B8B5 50                      push eax
:0040B8B6 E829000000              call 0040B8E4              ; do some really weired things with the char
:0040B8BB 8A4E01                  mov cl, byte ptr [esi+01]  ; get next char
:0040B8BE 83C40C                  add esp, 0000000C           
:0040B8C1 46                      inc esi
:0040B8C2 EBE3                    jmp 0040B8A7               ; next turn
:0040B8C4 83C063                  add eax, 00000063          ; add 63 to the value...



alright we see a similar loop like the one before but this time all the calculations are made in an call so lets take a look at it...

call:

:0040B8E4 55                      push ebp
:0040B8E5 8BEC                    mov ebp, esp
:0040B8E7 8B4508                  mov eax, dword ptr [ebp+08]
:0040B8EA 56                      push esi
:0040B8EB 33C9                    xor ecx, ecx
:0040B8ED 6A08                    push 00000008     		--> push 08 on stack
:0040B8EF 8A6D0C                  mov ch, byte ptr [ebp+0C]  	--> move the char in the HIGH bit of cx 
so we dont get the value 0000006E for the char n...ecx is 00006E00 here!!!

:0040B8F2 5A                      pop edx  			-> pop 08 from stack edx is used as counter 

loop begin
:0040B8F3 8BF0                    mov esi, eax                 --> esi = eax
:0040B8F5 33F1                    xor esi, ecx                 --> esi = esi xor ecx
:0040B8F7 66F7C60080              test si, 8000 		--> if si < 8000
:0040B8FC 7407                    je 0040B905  			 --> jump
:0040B8FE 03C0                    add eax, eax 			 --> eax = eax + eax
:0040B900 334510                  xor eax, dword ptr [ebp+10]    --> eax = eax XOR 1021 (remeber the push 1021 before the call)
:0040B903 EB02                    jmp 0040B907
:0040B905 D1E0                    shl eax, 1  		--> shift bits of eax 1 position left thats equal to eax = eax * 2
:0040B907 D1E1                    shl ecx, 1  		-->  shift bits of ecx 1 position left thats equal to ecx = ecx * 2
:0040B909 4A                      dec edx     		--> edx = edx - 1
:0040B90A 75E7                    jne 0040B8F3 		--> if edx not zero next turn
loop end

:0040B90C 5E                      pop esi
:0040B90D 5D                      pop ebp
:0040B90E C3                      ret
end call:

so we see its a little bit mor complicated here :( and i don't really know how to explain whats exactly going on but if you trace several times throug the code i will become more clear...
so what do we know now:

the first algo (which was easy) and its value wich was stored in ebx

the second algo which takes each character and and each character was processed in a loop wich was everytime repeated 8 times. the value we need for the serial is stored in eax

so here's the rest of the serial calculation:


:0040B8C7 0FB7CB                  movzx ecx, bx  -> move the LOW 16 bit of register ebx (our 1st value) to ecx
:0040B8CA 0FB7C0                  movzx eax, ax  -> move the LOW 16 bit of register eax (our second value) to eax
:0040B8CD 51                      push ecx        
:0040B8CE 50                      push eax
:0040B8CF 68CCE74B00              push 004BE7CC
:0040B8D4 FF750C                  push [ebp+0C]
:0040B8D7 E828780800              call 00493104  -> call which pastes the 2 values together...
:0040B8DC 83C410                  add esp, 00000010
:0040B8DF 5F                      pop edi
:0040B8E0 5E                      pop esi
:0040B8E1 5B                      pop ebx
:0040B8E2 5D                      pop ebp
:0040B8E3 C3                      ret

so what we need to know is that not the komplete value of the registers were ised to build the serial, there are just the 16 LOWER bits of each register used so if EBX = 12345678  and EAX = ABCDEFG
ecx becomes = 5678 an eax becomes DEFG

the call at 40b87d pastes the values together "EAX"+"ECX" so we get DEFG1234

in our case with the name noesis we get

value1 ebx = 00000675 lower 16bit = 0675
value2 eax = FF84387A lower 16bit = 387A

so the valid serial for noesis would be 387A0675

so now the difficult part ;) to translate all this in c-code...to make a proper keygen...

first i must say that im relativly new to coding so do not expect very good code ;)
so if anybody would improve the code fell free to mail me your suggestions...or simply do it :)

here's the source of my very basic keygen:




################## end of code  ###############################

#include <stdio.h>
#include <conio.h>  //for getche()
//vars

char name[100];
char serial[9];

unsigned int value1 = 0;
unsigned int value2 = 0;

unsigned int esi = 0;  //i named the variables like the registers...
unsigned int eax = 0;  //
unsigned int ecx = 0;

int z = 0;

int main (void)
{
	printf("....crc32's winzip 8.1 keygen....\n\n");
	printf("name: ");
	gets(name);                 //get name


	//generating value 1

	for (int i = 0; name[i] != 0; i++)
	{
		value1 = value1 + (name[i] * i);
	};



	//generating value2...

	for (int x = 0; name[x] != 0; x++)  //do while name[x] is not 00
	{
		ecx = (name[x] << 8);   	//mov ch, byte ptr [ebp+0C] --> move the char in the HIGH bit of cx
									//same as "shl ecx,8"

		for (z = 0; z < 8; z++)   	//call at :0040B8B6 z ist the counter...prcesses 8 times per char of the name
		{
			esi = eax;              //mov esi, eax
			esi = esi ^ ecx;        //xor esi, ecx
									//test si, 8000
			if ((esi & 0xFFFF) >= 0x8000)
			{
				eax = eax + eax;	//add eax, eax
				eax = eax ^ 0x1021;	//xor eax, dword ptr [ebp+10] ebp+10 is everytime 1021
			}
			else
			{
				eax = eax << 1;		//shl eax, 1
			};

			ecx = ecx << 1;			//shl ecx, 1

		};

	};

	value2 = eax + 0x63;   // add eax,63

	//building serial out of the values

	value2 = value2 & 0xFFFF;           //we only need the low 16bit of the value2
	sprintf(serial, "%0.4X%0.4X", value2, value1);  //paste values together


	//printing the serial on screen...

	printf("serial: %s \n\n", serial);


	printf("press any key to exit....");
	getche();   //waits for keystroke....

	return 0;
}

################## end of code  ###############################


so that's all. if there any questions/problems/mistakes in my source tut http://www.yellen.ch/neosis/ is the place to be...


crc남


						              
						              Body><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>