December 1998
"Winzip V7 KeyGen"
Win '95 PROGRAM 
Win Code Reversing
 Essay No. 1
by  Borna Janes
 
 
Code Reversing For Beginners 
Program Details 
Program Name: winzip70.exe 
Program Type: Win'95 unzipper 
Program Location: Here 
Program Size: 943 K 
 
 
Tools Used: 
Softice 3.2 - Debugger 
W32Dasm V8.9 - Disassembler
Rating
Easy ( X )  Medium (   )  Hard (    )  Pro (    )
There is a crack, a crack in everything. That's how the light gets in.

How to make Winzip V7 KeyGen
Written by Borna Janes
 
 

 
 
 
 
About this protection system
 

When Winzip is unregistred, on each startup it shows a nag screen that remind us to register program.
We can register WInzip by pressing ' Enter Registration Code' button.
Then we must enter:

Name
Registration #

On successful registration the program saves registration informations into :

 HKEY\Current_User\Software\Nico Mak Computing\Winzip\WinIni

Name                    "Borna Janes"
SN                         "FBAA149F" or "70684782"
Win32_version  "6.3-7.0"
 
 
 
 
The Essay
 

Program generates two valid serial numbers.

First serial contians numbers and letters (HEX format), and second serial contains only numbers (DECIMAL format).
 
Each serial number is generated with two calculation routines.
First calc routine generates first four characters and second one generates second four characters of serial.
That means that serials has eight characters!
 
Let's start...
 
When you run Winzip, you'll see nag screen that pops up.
Press ' Enter Registration Code' button and enter your handle and any random serial number.
For example here is what entered:
 
Name:                 Borna Janes
Registration  #:   998899
 
 
Press CTRL-D to pop up Softice and type bpx GetDlgItemTextA, then hit CTRL-D again to leave Softice.
 
Press 'OK' button.
Softice now breaks on GetDlgItemTextA function, hit  ' F11' to return to Winzip code and 'BD 0' for disable breakpoint .
You can now see this section of code:
 
:00408014 FF150C844600       Call dword ptr [0046840C]
:0040801A 53                 push ebx                         ;We are here
:0040801B E879160200         call 00429699
:00408020 59                 pop ecx                          ;ECX = Name
:00408021 53                 push ebx
:00408022 E89B160200         call 004296C2
:00408027 59                 pop ecx
:00408028 BE58D94700         mov esi, 0047D958
:0040802D 6A0B               push 0000000B
:0040802F 56                 push esi
:00408030 68810C0000         push 00000C81
:00408035 57                 push edi
:00408036 FF150C844600       Call dword ptr [0046840C]
:0040803C 56                 push esi
:0040803D E857160200         call 00429699
:00408042 59                 pop ecx                         ;ECX = fake serial
:00408043 56                 push esi
:00408044 E879160200         call 004296C2
:00408049 803D28D9470000     cmp byte ptr [0047D928], 00     ;Check lenth of name
:00408050 59                 pop ecx                         ;ECX = fake serial
:00408051 745F               je 004080B2                     ;If 0 then display error
:00408053 803D58D9470000     cmp byte ptr [0047D958], 00     ;Check lenth of serial
:0040805A 7456               je 004080B2                     ;If 0 then display error
:0040805C E8EAFAFFFF         call 00407B4B                   ;Create and compare serials
:00408061 85C0               test eax, eax                   ;EAX 0 = Wrong serial,   EAX 1 = Good serial
:00408063 744D               je 004080B2                     ;If wrong serial display error
:00408065 53                 push ebx
:00408066 BBB80C4700         mov ebx, 00470CB8
 
How we can see there are two calls to GetDlgItemTextA function.
One for name and one for serial. After that calls program puts locations of name and serial in ECX.
There are also two compare functions at 00408049 and 00408053.
They checks lenth of name and serial. If there is no name or serial then display error message.
For us is only important call at 0040805C witch create real and compare fake and real serial.
If number is wrong then EAX = 0 if number is good then EAX = 1.
If you anywhere inside the call at 40805C see XOR EAX,EAX it's bad because it indicates that serial is wrong!
Now press 'F10'until you step on 0040805C then press 'T' to trace the code inside the call.
 
You'll now see this piece of code:
 
 
:00407B4B 55                 push ebp
:00407B4C 8BEC               mov ebp, esp
:00407B4E 81EC08020000       sub esp, 00000208
:00407B54 53                 push ebx
:00407B55 56                 push esi
:00407B56 33F6               xor esi, esi                     ;ESI = 0
:00407B58 803D28D9470000     cmp byte ptr [0047D928], 00      ;Check lenth of name
:00407B5F 57                 push edi
:00407B60 0F84A1000000       je 00407C07                      ;If 0 then display error
:00407B66 8D45EC             lea eax, dword ptr [ebp-14]      ;Memory location for next string
:00407B69 50                 push eax
:00407B6A 6860F44600         push 0046F460
:00407B6F E84F9CFFFF         call 004017C3                    ;Save "MuradMeraly"  to EAX
:00407B74 59                 pop ecx
:00407B75 8D85F8FDFFFF       lea eax, dword ptr [ebp+FFFFFDF8];Memory location for next string
:00407B7B 59                 pop ecx                          ;ECX= "MuradMeraly"
:00407B7C BF28D94700         mov edi, 0047D928                ;EDI = Name
:00407B81 50                 push eax
:00407B82 57                 push edi
:00407B83 E8A9020000         call 00407E31                    ;Make second copy of name
:00407B88 59                 pop ecx
:00407B89 8D85F8FDFFFF       lea eax, dword ptr [ebp+FFFFFDF8]
:00407B8F 59                 pop ecx                          ;ECX = Second copy of name
:00407B90 50                 push eax
:00407B91 8D45EC             lea eax, dword ptr [ebp-14]      ;EAX = "MuradMeraly"
:00407B94 50                 push eax
:00407B95 E866FD0400         call 00457900                    ;Compare "MuradMeraly" and second copy of name
:00407B9A 59                 pop ecx                          ;If they are the same then EAX = 0, else EAX = 1
:00407B9B 59                 pop ecx
:00407B9C 6A01               push 00000001
:00407B9E 85C0               test eax, eax                    ;Check EAX
:00407BA0 5B                 pop ebx
:00407BA1 7502               jne 00407BA5                     ;If EAX= 0 then then then ESI = 1
:00407BA3 8BF3               mov esi, ebx
:00407BA5 8D45EC             lea eax, dword ptr [ebp-14]
 
What progarm does program do here?
First program makes second copy of name without spaces, numbers... (only with letters)
You can see second copy  of name by typeing "D ECX" when you standing on 407B91
You can also see "MuradMeraly" string at 407B91 by typing "D EAX"
 
If you don't know "D" command display(dump) memory location,
in our case we dump memory location witch is situated in eax (ecx)
 
Then program compare "MuradMeraly" with second copy of name.
If you are "MuradMeraly" then EAX = 0, if you're not then EAX = 1.
If EAX = 0(if you are Murad Meraly) then program sets ESI to 1, else ESI = 0.
:00407BA8 50                 push eax
:00407BA9 6870F44600         push 0046F470
:00407BAE E8109CFFFF         call 004017C3
:00407BB3 59                 pop ecx
:00407BB4 8D45EC             lea eax, dword ptr [ebp-14]
:00407BB7 59                 pop ecx
:00407BB8 50                 push eax
:00407BB9 57                 push edi
:00407BBA E841FD0400         call 00457900
:00407BBF 59                 pop ecx
:00407BC0 85C0               test eax, eax
:00407BC2 59                 pop ecx
:00407BC3 750C               jne 00407BD1
:00407BC5 FF15C4814600       Call dword ptr [004681C4]
:00407BCB 84C3               test bl, al
:00407BCD 7402               je 00407BD1
:00407BCF 8BF3               mov esi, ebx
:00407BD1 6A14               push 00000014
:00407BD3 8D45EC             lea eax, dword ptr [ebp-14]
:00407BD6 6A00               push 00000000
:00407BD8 50                 push eax
:00407BD9 E872E50400         call 00456150
:00407BDE 83C40C             add esp, 0000000C
:00407BE1 8D85F8FDFFFF       lea eax, dword ptr [ebp+FFFFFDF8]
:00407BE7 68C8000000         push 000000C8
:00407BEC 6A00               push 00000000
:00407BEE 50                 push eax
:00407BEF E85CE50400         call 00456150
:00407BF4 83C40C             add esp, 0000000C
:00407BF7 85F6               test esi, esi                         ;Check ESI
:00407BF9 7413               je 00407C0E                           ;If ESI = 0 then skip next few lines
:00407BFB E89C060000         call 0040829C
:00407C00 83257CB0470000     and dword ptr [0047B07C], 00000000
:00407C07 33C0               xor eax, eax                          ;EAX = 0
:00407C09 E9B3000000         jmp 00407CC1                          ;Jump to end of the routine
 
If ESI = 1 (if you are Murad Meraly) then set EAX to 0 (if you remember it indicates bad serial),
jump to the end of the routine, and display error message!
If ESI = 0 (if you are not Murad Meraly) then skip next few lines and jump to 407C0E
Why Murad Meraly can't register Winzip?
Murad Meraly is first cracker who sucessfuly cracked WinZip and he is in the Nico Mak Computing blacklist
Now here is the most important part of code.
Program here generates two valid serial numbers:
:00407C0E 8D85C0FEFFFF       lea eax, dword ptr [ebp+FFFFFEC0]     ;Memory location for first serial
:00407C14 50                 push eax
:00407C15 57                 push edi
:00407C16 E8AB000000         call 00407CC6                         ;Generate first serial
:00407C1B 59                 pop ecx
:00407C1C BE58D94700         mov esi, 0047D958
:00407C21 59                 pop ecx                               ;ECX = First serial
 
Type "D ECX" here to see first valid serial number
 
:00407C22 8D85C0FEFFFF       lea eax, dword ptr [ebp+FFFFFEC0]
:00407C28 56                 push esi
:00407C29 50                 push eax
:00407C2A E8D1FC0400         call 00457900                         ;Compare first serial with *fake* serial
:00407C2F F7D8               neg eax
:00407C31 1BC0               sbb eax, eax
:00407C33 59                 pop ecx
:00407C34 40                 inc eax
:00407C35 59                 pop ecx
:00407C36 A37CB04700         mov dword ptr [0047B07C], eax         ;Save registration result  1 = Good serial
:00407C3B 7569               jne 00407CA6                          ;into memory                  2 = Bad serial
:00407C3D 8D85C0FEFFFF       lea eax, dword ptr [ebp+FFFFFEC0]     ;Memory location for second serial
:00407C43 50                 push eax
:00407C44 57                 push edi
:00407C45 E820010000         call 00407D6A                         ;Generate second serial
:00407C4A 59                 pop ecx
:00407C4B 8D85C0FEFFFF       lea eax, dword ptr [ebp+FFFFFEC0]
:00407C51 59                 pop ecx                               ;ECX = Second serial
Type "D ECX" here to see second valid serial number
:00407C52 56                 push esi
:00407C53 50                 push eax
:00407C54 E8A7FC0400         call 00457900                         ;Compare second serial with *fake* serial
:00407C59 F7D8               neg eax
:00407C5B 1BC0               sbb eax, eax
:00407C5D 59                 pop ecx
:00407C5E 40                 inc eax
:00407C5F 59                 pop ecx
:00407C60 A37CB04700         mov dword ptr [0047B07C], eax         ;Save registration result  1 = Good serial
:00407C65 753F               jne 00407CA6                          ;into memory                  2 = Bad serial
 
Now we can see that program generates two valid serial numbers, and compare it with our *fake* serial!
First valid serial number contain letters and numbers (HEX format),
and second serial contain only numbers (DECIMAL format).
If our serial is same as one of two valid serial numbers, then program set eax to 1.
If our serial is not same as any of two valid serials then eax is 0.
Program also save registration result (EAX) into memory.
After this only is important call at 407CB4 witch clear the part of memory where correct serial was saved!
If we want to make KeyGen we must trace the code inside calls witch generates correct serials!
(If you are not going to make KeyGen, you have two correct serials and you can register Winzip with one of them)
Press "F10" until you get to 407C16 CALL 407CC6 , here program generates first serial.
Now type "T" to trace the code inside the call
 
 
First valid serial number 
 
 
You'll now see this part of code:
 
Looking at the following generation routine we can see that it include two calculation routines
 
:00407CC6 55                    push ebp
:00407CC7 8BEC                  mov ebp, esp
:00407CC9 51                    push ecx
:00407CCA 8B4D08                mov ecx, dword ptr [ebp+08]        ;ECX = Name
:00407CCD 8365FC00              and dword ptr [ebp-04], 00000000   ;Clear memory for first
:00407CD1 53                    push ebx                           ;four characters of serial
:00407CD2 56                    push esi
:00407CD3 8A11                  mov dl, byte ptr [ecx]             ;EDX(DL) = First character of name
:00407CD5 57                    push edi                           ;EDI = Name
:00407CD6 33C0                  xor eax, eax                       ;EAX = 0
:00407CD8 8BF1                  mov esi, ecx                       ;ESI = Name
:00407CDA 33FF                  xor edi, edi                       ;EDI = 0
:00407CDC 84D2                  test dl, dl                        ;Check EDX(DL)
:00407CDE 7413                  je 00407CF3                        ;If end of name then exit calculation routine
:00407CE0 660FB6D2              movzx dx, dl                       ;EDX(DX) = EDX(DL)
:00407CE4 8BDF                  mov ebx, edi                       ;EBX = EDI
:00407CE6 0FAFDA                imul ebx, edx                      ;EBX = EBX * EDI
:00407CE9 015DFC                add dword ptr [ebp-04], ebx        ;Add EBX to [EBP-04]
:00407CEC 8A5601                mov dl, byte ptr [esi+01]          ;Next character to EDX(DL)
:00407CEF 47                    inc edi                            ;EDI = EDI + 1
:00407CF0 46                    inc esi                            ;ESI = ESI + 1
:00407CF1 EBE9                  jmp 00407CDC                       ;Loop this [lenth of name] times
 
Here is the end of first calculation routine.
We can see that program takes character from name (EDX) and multiply it with EBX witch is growing up by one
every next character (starting with zero).
Every time when program get the result of multiplying it adds it to [EBP-04]
Here is exemple: My handle is "Borna Janes"; EBX is 0
                              1. char of name is "B"(42h) program multiplys it with EBX witch is 0;  EBX grows by 1 -- EBX is 1
                                   Result of multiply is 0, program saves it to [EBP-04]
                              2. char of name is "o"(6Fh) program multiplys it with EBX witch is 1;  EBX grows by 1 -- EBX is 2
                                   Result of multiply is 6F, program saves it to [EBP-04]
                              3. char of name is "r"(72h) program multiplys it with EBX witch is 2;  EBX grows by 1 -- EBX is 3
                                  Result of multiply is E4, program saves it to [EBP-04]
                               .....and so on!
When calculation routine ends, when there is no more characters to multiply type "D EBP-04" and you'll see the sum of
all multiplys in data window. Thats second four characters of serial but in REVERSE FORM !!
In my case sum is "9F 14" but my serial ends with "149F".
 
 
Let's take a look how program generates first four characters of serial
 
Here is second calculation routine:
 
 
:00407CF3 C705ECD3470001000000  mov dword ptr [0047D3EC], 00000001
:00407CFD 8BF1                  mov esi, ecx                        ;ESI = Name
:00407CFF 8A09                  mov cl, byte ptr [ecx]              ;ECX(CL) = First character of name
:00407D01 84C9                  test cl, cl                         ;Check ECDX(CL)
:00407D03 7419                  je 00407D1E                         ;If end of name then exit calculation routine
:00407D05 660FB6C9              movzx cx, cl                        ;ECX(CX) = ECX(CL)
:00407D09 6821100000            push 00001021                       ;Save "1021" onto the stack
:00407D0E 51                    push ecx                            ;Save ECX
:00407D0F 50                    push eax                            ;Save EAX
:00407D10 E82A000000            call 00407D3F                       ;Call calculation subroutine
:00407D15 8A4E01                mov cl, byte ptr [esi+01]           ;Next character to ECX(CL)
:00407D18 83C40C                add esp, 0000000C                   ;ESP = ESP - 0C
:00407D1B 46                    inc esi                             ;ESI = ESI + 1
:00407D1C EBE3                  jmp 00407D01                        ;Loop this [lenth of name] times
 
Here is the end of second calculation routine.
 
What can we see here?
1. Program takes one character user name and saves it on the stack(ECX).
2. Program saves "1021" onto the stack.
3. Program calls calculation subroutine, and result of calculation adds in EAX.
 
Program loops this calculation routine  for every character of name.
When the routine ends sum of calculations is in EAX.
This number is very close with our second four chars of serial.
You'll see later how program make from number in EAX, our second piece of serial.
Now let's see what program do in calculation routine called at 407D10 call 407D3F!
Here is the code:
:00407D3F 55                      push ebp                          ;Save EBP

:00407D40 8BEC                    mov ebp, esp                      ;EBP = ESP
:00407D42 8B4508                  mov eax, dword ptr [ebp+08]       ;Load EAX from the stack (EAX stays same)
:00407D45 56                      push esi                          ;ESI = Name
:00407D46 33C9                    xor ecx, ecx                      ;ECX = 0
:00407D48 6A08                    push 00000008                     ;Save "00000008" onto stack

:00407D4A 8A6D0C                  mov ch, byte ptr [ebp+0C]         ;CH = Next char of name; ECX = Char + "00"
:00407D4D 5A                      pop edx                           ;Loads "8"  from stack and puts it to EDX
:00407D4E 8BF1                    mov esi, ecx                      ;ESI = ECX

:00407D50 33F0                    xor esi, eax                      ;ESI =  ESI XOR EAX
:00407D52 66F7C60080              test si, 8000                     ;Check SI (first four chars of ESI)
:00407D57 7407                    je 00407D60                       ;If less then 8000 then jump to 407D60
:00407D59 03C0                    add eax, eax                      ;EAX = EAX + EAX
:00407D5B 334510                  xor eax, dword ptr [ebp+10]       ;EAX = EAX XOR "1021"
:00407D5E EB02                    jmp 00407D62                      ;Jump to 407D62
:00407D60 D1E0                    shl eax, 1                        ;Shift EAX left by one bit
:00407D62 D1E1                    shl ecx, 1                        ;Shift ECX left by one bit

:00407D64 4A                      dec edx                           ;EDX = EDX - 1
:00407D65 75E7                    jne 00407D4E                      ;Loop this until EDX = 0 (eight times)
:00407D67 5E                      pop esi
:00407D68 5D                      pop ebp
:00407D69 C3                      ret
What program do here?
It takes char from user name and puts it to CH (ECX = Char + "00")
Then puts number eight to EDX, and loop this function eight times:
 
1. ESI = ECX ( first time it's char of name + "00")
2. Xor ESI with EAX
3. Check is SI (first four chars of ESI) less then 8000
4. If yes then jump to  8
5. Adds EAX to EAX (EAX = EAX * 2)
6. Xor EAX with 1021
7. Jump to 9
8. Shift EAX left by one bit, it's same as EAX = EAX * 2
9. Shift ECX left by one bit, it's same as ECX = ECX * 2
Result of this subroutine routine is located in EAX!
 
Ok, that was calculation subroutine called from main calc routine at 407D10 call 407D3F!
How I already say when main calc routine ends result of all calculation is located in EAX!
You are probably thinking that our second piece of serial is EAX, ok it's very close but it's not!
Where the hell are our second piece of serial?
Let's see...
 
Here is continue of code cuted at 407D1C:
 
:00407D1E 0FB74DFC              movzx ecx, word ptr [ebp-04]        ;ECX = First piece of our serial
:00407D22 83C063                add eax, 00000063                   ;EAX = EAX + 63
:00407D25 51                    push ecx                            ;Save ECX
:00407D26 0FB7C0                movzx eax, ax                       ;EAX = AX; EAX = First four char of EAX
:00407D29 50                    push eax                            ;Save EAX
 
We'll stop here for a moment!
Now take a look at EAX after adding "63", IT'S SECOND PIECE OF SERIAL!
Also take a look at ECX, that is FIRST PIECE OF SERIAL!
If you connect these two pieces, you'll get CORRECT SERIAL!
 
:00407D2A 6884F44600            push 0046F484
:00407D2F FF750C                push [ebp+0C]                       ;Memory location to save serial
:00407D32 E869E20400            call 00455FA0                       ;Save serial to memory
:00407D37 83C410                add esp, 00000010
:00407D3A 5F                    pop edi
:00407D3B 5E                    pop esi
:00407D3C 5B                    pop ebx
:00407D3D C9                    leave
:00407D3E C3                    ret
 
 
We came to the end of routine that generates first valid serial number.
Let's see how program generates second serial...
 
 
 
Second valid serial number
 
 
Program generates second valid serial number on the very similar way.
I'll don't write all code here because it's almost same, i'll explain how program do that!
 
First, program generates second valid serial from second copy of our name in lower case!
If you don't remember second copy of name is without spaces, numbers... ONLY LETTERS!
Calculation routines for second serial are same!
But here is the difference:
Second four characters of serial are decimal value of result of first calculation routine!
First four characters of serial are decimal value of result of second calculation routine!
 
Here is exemple:
 
My name is "Borna Janes"
Program generates second serial from second copy of name in lower case, It's "bornajanes"!
Result of first calculation routine is "12AE", decimal value of  "12AE" is  "4782".
"4782" are second four characters of my second valid serial number
 
Result of second calculation routine is "1B9C", decimal value of  "1B9C" is  "7068".
"7068" are first four characters of my second valid serial number.
 
The most easiest way to found second serial is to enter second copy of your name( lower case),
for USER NAME, and any random serial!
Then trace the code just how I explain before, and when you step on 407D2A you'll see
first piece of serial in EAX, and secod piece in ECX.
You can also put breakpoint at 407D2A with "BPX 407D2A"
 
 
Now only what you must do is to convert them to decimal and you have your second serial!!
 
Final Notes
 
 
Winzip like an other program can be cracked in few diffrent ways, patching, finding right serial...
However program still has simple name/serial protection and simple generation routine.
 
If you already didn't make dead listing of winzip32.exe file then do it now!
With dead list of winzip you can easy translate serial generation routine to
any advanced programming language,  unfortunately I know only Qbasic :(
Here is piece of my source code writed in Qbasic....
 
DECLARE FUNCTION firstpiece$ (name$)
DECLARE FUNCTION secondpiece$ (name$)
DECLARE SUB hextodec (hexx$, sum&)
DECLARE SUB hexfunc (hex1$, hex2$, hex3$, op$)
name$ = ""
COLOR 15
PRINT "                        Winzip 7  KeyGen"
COLOR 14
PRINT "               By Borna Janes 1998 Croatia"
PRINT "           Email - BornaJanes@hotmail.com"
PRINT "           ------------------------------------------"

....hope this helps :)
 

My thanks and gratitude goes to:-

The Sandman for his great site(the best site for newbies) full of knowledge and for
his cracking forum(also the best on the net)!

Eternal Bliss, my best 'virtual' friend, for all what he done for me!
 
Ob Duh
Do I really have to remind you all that by buying and NOT stealing the software you use will ensure that these software houses will encourage them to produce even *better* software for us to use and enjoy.

Ripping off software through serials and cracks is for lamers..

If your looking for cracks or serial numbers from these pages then your wasting your time, try searching elsewhere on the Web under Warze, Cracks etc.
 


 
 
 Return 
 


Essay by: Borna Janes
Page Created: 31th December 1998