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"
-
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!!
-
-
-
-
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!
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.
Essay by: Borna
Janes
Page Created: 31th December
1998