· How to calculate a valid serial for Wingate 1.13.17 ·

© 1997 by Cruehead / MiB


Software: Wingate 1.13.17
Tools: Softice 3.0 or better and Wdasm 8.9.

Hello...

and welcome to this tutorial on how to calculate serials. The target is a program called Wingate version 1.13.17.What kind of program is it?A quick look at the user guide tells us that "WinGate is basically a multiple proxy server, Telnet server, FTP Server, SOCKS (V4.0) server and extra bits rolled into one". Can come in handy!

We start with dissasembling the code using Wdasm (I guess we could have used IDA as well) and save the dead listing. Then we fire up wingate and choose "Info" and "Register". Ah - name and key... we have seen this before hav'nt we? Ok...lets begin! Chosse a name and a key (Cruehead - 123123) and then enter Softice and put a bpx on GetWindowTextA. Back to the program again and press OK. First of all we'll just put a breakpoing on the serial and forget the name for now. Why? Because we want to see how difficuly the program is to crack. Maybe there is a "memory echo" somewhere, and then we dont have to care about what calculations are made from the user name. So when softice breaks in, just hit CTRL-D (or F5) and softice will break in again. Press F11 to get out of the function. Trace the two first call and we'll see:

 mov edi, dword ptr [ecx]

 "D edi" and what do we see? Our key! This cracking stuff is amazing huh? Well, maybe that wasnt very exiting, but put a BPR on the location. Clear the breakpoint on GetWindowTextA (BC) and leave softice again. We will break in where the length of the key is calculated. Step out of the function and we'll see this:


:0042D97A 8B0E                    mov ecx, dword ptr [esi]

:0042D97C 8941F8                  mov dword ptr [ecx-08], eax

:0042D97F 8B0E                    mov ecx, dword ptr [esi]

:0042D981 5E                      pop esi

:0042D982 C6040100                mov byte ptr [ecx+eax], 00

:0042D986 C20400                  ret 0004
Nothing new here, it just stores the length of the string at ecx-8 (ecx is a pointer to our key). So, "BPM ds:ecx-8 RW" and leave softice again. We'll see this code when softice breaks in again:

:00418C36 8378F818                cmp dword ptr [eax-08], 00000018

:00418C3A 7415                    je 00418C51

Ah - the key must have a length of exactly 18h (24 dec) chars. So, we'll have to clear all the breakpoints (BC *) and start over again. This time we'll choose another string (Cruehead - 123451234512345123451234). Do the above steps again until you reach the location where we left before.

 Now I'll let you play some on your own for a while...see if you can find a memory echo somewhere...

Ok - you give up? No wonder - there is none :). We'll have to breakpoint on the location of the user name as well, in order to see what calculations are made from it. What are you waiting for? Do so (use the same meothod as above).

When you get back to code where we left before (00418C36) you should have 4 breakpoints. Two BPR's (both the user name and the key) and two BPM's (length of user name and length of key). You can now delete the two BPM's ... we dont need them anymore. Ok, leave softice again and it will break in at:

* Referenced by a Conditional Jump at Address:

|:00418C8C

|

:00418C55 8D0C7D00000000          lea ecx, dword ptr [2*edi+00000000]

:00418C5C 47                      inc edi

:00418C5D 030E                    add ecx, dword ptr [esi]

:00418C5F 885DF3                  mov byte ptr [ebp-0D], bl

:00418C62 8A01                    mov al, byte ptr [ecx]        <-- We'll land here

:00418C64 8845F0                  mov byte ptr [ebp-10], al

:00418C67 8D45F0                  lea eax, dword ptr [ebp-10]

:00418C6A 8A5101                  mov dl, byte ptr [ecx+01]

:00418C6D 8D4DF3                  lea ecx, dword ptr [ebp-0D]

:00418C70 51                      push ecx

:00418C71 8855F1                  mov byte ptr [ebp-0F], dl

This code moves two bytes at a time from the key string to another location (EBP-10).

 I dont think you want to see a lot of useless code here in this tutorial so I'll just skip the next piece of code and describe what it does instead. It takes the first byte of the two that are located at EBP-10 and substracts 30 from it. Then it multiplies this value with A hex (10 dec), takes the second byte and substracts 30 from it. Then it adds this value to the former value. This value is saved in location EBP-1C. This loop goes on until the whole string is processed. EG: if the string you entered was 123451234512345123451234 then the bytes starting at location EBP-1C would look like this:

 12 34 51 23 45 12 34 51 23 45 12 34

 Got It? Good... so when you reach cs:00418C62 remove the BPR on your key, and BPR ds:ebp-1C ds:ebp-10 instead. Softice will break in many times when the string is copied into this location.

After the whole string has been copied, leave softice again, and when we get our beloved softice on the screen again the length of the user name is calculated again. After this we'll land when the user name is copied to another location. So remove the BPR and place it on the new location. Leave softice and it will pop up in a code that looks like this:

* Referenced by a Conditional Jump at Address:

|:00418B47

|

:00418B16 8D2C06                  lea ebp, dword ptr [esi+eax]

:00418B19 33D2                    xor edx, edx

:00418B1B 33DB                    xor ebx, ebx

:00418B1D 83C104                  add ecx, 00000004

:00418B20 8A5503                  mov dl, byte ptr [ebp+03]     <-- We'll land here

:00418B23 8A5D01                  mov bl, byte ptr [ebp+01]

:00418B26 C1E210                  shl edx, 10

:00418B29 83C604                  add esi, 00000004

:00418B2C 0BD3                    or edx, ebx

:00418B2E 33DB                    xor ebx, ebx

:00418B30 C1E208                  shl edx, 08

:00418B33 8A5D02                  mov bl, byte ptr [ebp+02]

:00418B36 C1E310                  shl ebx, 10

:00418B39 0BD3                    or edx, ebx

:00418B3B 33DB                    xor ebx, ebx

:00418B3D 8A5D00                  mov bl, byte ptr [ebp+00]

:00418B40 0BD3                    or edx, ebx

:00418B42 3BFE                    cmp edi, esi

:00418B44 8951FC                  mov dword ptr [ecx-04], edx

:00418B47 77CD                    ja 00418B16

Explanation of the code: The username is copied to another location and the space after the name will be filled with 00 bytes. Change the bpr once again (hope you're not getting tierd of all these changing of locations) and leave softice. Now for the first time we'll land in an interesting part:
 Referenced by a CALL at Addresses:

|:0041811B   , :00418135

|

...

...

...

:0041820C 8BC7                    mov eax, edi

:0041820E 8BCE                    mov ecx, esi

:00418210 F7D0                    not eax

:00418212 23C3                    and eax, ebx

:00418214 23CF                    and ecx, edi

:00418216 0BC1                    or eax, ecx

:00418218 03442414                add eax, dword ptr [esp+14]   <-- We'll land here

:0041821C 2D885B9528              sub eax, 28955B88

:00418221 03E8                    add ebp, eax

...

...

...

:00418A7F 015104                  add dword ptr [ecx+04], edx   <-- Important

:00418A82 014108                  add dword ptr [ecx+08], eax   <-- Important

:00418A85 01790C                  add dword ptr [ecx+0C], edi   <-- Important

:00418A88 8D7C2414                lea edi, dword ptr [esp+14]

:00418A8C 33C0                    xor eax, eax

:00418A8E 5D                      pop ebp

:00418A8F 017110                  add dword ptr [ecx+10], esi

:00418A92 B910000000              mov ecx, 00000010

:00418A97 F3                      repz

:00418A98 AB                      stosd

:00418A99 5F                      pop edi

:00418A9A 5E                      pop esi

:00418A9B 5B                      pop ebx

:00418A9C 83C448                  add esp, 00000048

:00418A9F C20400                  ret 0004

I skipped a lot of code and only included the interesting part. Some calculcations are beeing done from out username, and the result will be saved in edx,eax and edi. At 00418A7F the result are beeing added to an already made value. So after these additions has been done take a look at ecx-4 (d ecx-4). These 12 bytes are VERY important, so write them down on paper. For my name (Cruehead) the values were "28 31 58 01 CB E7 42 95 45 8B A4 0F".
Delete the bpr on the username, and put one on the values instead. Leave softice and it will break in when the values are beeing copied into another location. Change the bpr. The next time softice breaks in, the string is beeing copied to another location again (geez - getting tierd of all these location swaping soon?). Change the bpr again. When softice breaks in again we'll land in another interesting part:


* Referenced by a Conditional Jump at Address:

|:00418CDA

|

:00418CCE 8A4435D4              mov al, byte ptr [ebp+esi-2C]   value calculated from username

:00418CD2 304435E4              xor byte ptr [ebp+esi-1C], al   xor this value with serial value

:00418CD6 46                    inc esi

:00418CD7 83FE0C                cmp esi, 0C

:00418CDA 7CF2                  jl 00418CCE

:00418CDC 8B45EC                mov eax, dword ptr [ebp-14]     the last four bytes to eax

:00418CDF 33F6                  xor esi, esi

:00418CE1 C1E810                shr eax, 10                     keep the last 2 bytes

:00418CE4 0FB7C8                movzx ecx, ax

:00418CE7 51                    push ecx

:00418CE8 E843320000            call 0041BF30



So....XOR...nice, is'nt it? Write the new string down and make a "table" of it, like this:
Original Value  12  34  51 23  45  12  34  51  23  45  12  34 
Name Value  28  31  58  01  CB  E7  42  95  45  8B  A4  0F 
Xor'ed Value  3A  05  09  22  8E  F5  76  C4  66  CE  B6  3B 

Now, we only need one BPR, the one on the new xor'ed string, so delete the other. The next interesting part is:


* Referenced by a CALL at Address:

|:00418CF1



:0041BF40 E82B320000              call 0041F170

:0041BF45 8B4814                  mov ecx, dword ptr [eax+14]

:0041BF48 8BD1                    mov edx, ecx

:0041BF4A 8D0C89                  lea ecx, dword ptr [ecx+4*ecx]

:0041BF4D 8D0C89                  lea ecx, dword ptr [ecx+4*ecx]

:0041BF50 03CA                    add ecx, edx

:0041BF52 8D0CCA                  lea ecx, dword ptr [edx+8*ecx]

:0041BF55 C1E108                  shl ecx, 08

:0041BF58 2BCA                    sub ecx, edx

:0041BF5A 8D8C8AC39E2600          lea ecx, dword ptr [edx+4*ecx+00269EC3]

:0041BF61 894814                  mov dword ptr [eax+14], ecx

:0041BF64 8BC1                    mov eax, ecx

:0041BF66 250000FF7F              and eax, 7FFF0000

:0041BF6B C1E810                  shr eax, 10

...

:00418CF0 46                      inc esi

:00418CF1 E84A320000              call 0041BF40

:00418CF6 304435E3                xor byte ptr [ebp+esi-1D], al

:00418CFA 83FE0A                  cmp esi, 0000000A

:00418CFD 7CF1                    jl 00418CF0

Then the value in AL will be xor'ed with the already xor'ed value (in my case 3A 05 09 22 8E F5 76 C4 66 CE). Note that only the 10 first bytes is xored this way! When this is done, you see this:

:00418CFF 8B55E4                  mov edx, dword ptr [ebp-1C]

:00418D02 8B4DE8                  mov ecx, dword ptr [ebp-18]

:00418D05 C1EA10                  shr edx, 10

:00418D08 8B45EC                  mov eax, dword ptr [ebp-14]

:00418D0B C1E910                  shr ecx, 10

:00418D0E C1E810                  shr eax, 10

:00418D11 668BDA                  mov bx, dx

:00418D14 66C1EB08                shr bx, 08

:00418D18 02DD                    add bl, ch

:00418D1A 02DC                    add bl, ah

:00418D1C 025DE5                  add bl, byte ptr [ebp-1B]

:00418D1F 025DE9                  add bl, byte ptr [ebp-17]

:00418D22 025DED                  add bl, byte ptr [ebp-13]

:00418D25 02D8                    add bl, al

:00418D27 02D9                    add bl, cl

:00418D29 02DA                    add bl, dl

:00418D2B 025DE8                  add bl, byte ptr [ebp-18]

:00418D2E 025DE4                  add bl, byte ptr [ebp-1C]

:00418D31 3A5DEC                  cmp bl, byte ptr [ebp-14]

:00418D34 752C                    jne 00418D62

:00418D36 837DE800                cmp dword ptr [ebp-18], 00000000

:00418D3A 7526                    jne 00418D62

:00418D3C 8B450C                  mov eax, dword ptr [ebp+0C]

:00418D3F 8A4DED                  mov cl, byte ptr [ebp-13]

:00418D42 8B55E4                  mov edx, dword ptr [ebp-1C]

:00418D45 8808                    mov byte ptr [eax], cl

:00418D47 8B4510                  mov eax, dword ptr [ebp+10]

:00418D4A C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF

:00418D51 8910                    mov dword ptr [eax], edx

:00418D53 E830000000              call 00418D88

:00418D58 B801000000              mov eax, 00000001

:00418D5D E9DCFEFFFF              jmp 00418C3E

So...here is the accual check! First all values except the nine'th are add'ed. Then this value will be compared with the nine'th, and if it is a correct serial, they will be equal to eachother. Simply nop away the JNE (if we would do a patch, here is one of the locations we would change), and continue the stepping. Next it compares byte 4,5,6 and 7 with 00. They will be zero if it is a valid serial! So...those were the two checks...but isnt the code at offset 0041D3F interesting??? Have a look in the help file!

You may register with payment for a key that will not expire. Depending on your requirements, you may choose a license that suits. Keys are available for the following numbers of concurrent users.
· 2 Users
· 5 Users
· 10 Users
· unlimited

 So...there are diffrent kinds of keys... Load the the dead-listing of wingate and search for "unlimitied". We'll land here:


:00402AED 682E040000              push 0000042E

:00402AF2 51                      push ecx

:00402AF3 E8610F0300              call 00433A59

:00402AF8 803DB8DC4400FF          cmp byte ptr [0044DCB8], FF

:00402AFF 7513                    jne 00402B14



* Possible StringData Ref from Data Obj ->"Unlimited"

Ah - it compares a byte with FF, and if it's a match, it will be registered with unlimited of users! At offset 00418D45 you see that CL i moved to another location. If you want to be sure that this is the "number of users" byte, BPM this memory location, otherwise - take my word for it :).

So, now that we now all about how the check is done, lets get to the interesting part - how to calculate a valid serial!

First, lets write down what we know:
* The 9'th byte and the sum of all the other bytes must be equal.
* Byte 4,5,6 and 7 must be zero.
* Byte 10 must be FF

 So...the serial must look like this (after all of the XOR steps): XX XX XX XX 00 00 00 00 ** FF XX XX, where ** = length of the rest of the bytes. So, now it's time for some thinking! Take a minute or two to think about this, and when you're done - continue reading.

 The difficult part is that 9'th byte...But if we could calculate the sum right now, that would solve alot of problems. So...can we? YES WE CAN! The last two bytes will only be modifed ONCE, during the first XOR part. And we know that the two last bytes of the name values were A4 and 0F (for the name "Cruehead" thas is). So if we use 0000 as the four last numbers in our serial, the two last bytes will be A4 and 0F. So our serial (after all XOR) will look like this: XX XX XX XX 00 00 00 00 ** FF A4 0F. Now, what about the four first bytes? Well, lets make it simple - lets make them zero. So our final serial would be 00 00 00 00 00 00 00 00 ** FF A4 0F and now we can easily calculate the sum of the bytes. FF + A4 + 0F = B2 (well, accually 1B2, but we only use B2). And the correct serial for Cruehead after the XOR steps would be : 00 00 00 00 00 00 00 00 B2 FF A4 0F.

 So, lets run Wingate again, but this time with the serial 123451234512345123450000. Do the same steps as described above, but wait when you're about to XOR the already XOR'ed value (at offset 00418CF6) and write down the values in AL for each XOR'ed byte. I got these values: "39 F2 C4 C9 FB 97 5B B5 6A F5".
Now we're almost done! Lets make a table again:
 
 
We want these bytes 00  00  00  00  00  00  00  00  B2  FF  A4  0F 
The values we got from the second XOR 39  F2  C4  C9  FB  97  5B  B5  6A  F5  00  00 
Result if we XOR them 39  F2  C4  C9  FB  97  5B  B5  D8  0A  A4  0F 

Did I hear someone shouting "Hey! Why did you XOR them???" somewhere? Well, I'll try to explain it. The first byte we wanted after the second XOR step was 00 and we knew what value the first byte would be Xor'ed with (39).
Guess what XOR 39,39 is? Yes - 00!!!

 So the bytes we wanted after the first XOR would be "39 F2 C4 C9 FB 97 5B B5 D8 0A A4 0F". Remeber the values calculated from username? Now we'll need them! As I said in the begining the serial entered was XOR'ed with the name values. What if we XOR'ed the name values with the values we wanted after the first XOR step?
WE WOULD GET THE CORRECT SERAIL!

 So, here we are:
 
 
We want these values after the first XOR step 39  F2  C4  C9  FB  97  5B  B5  D8  0A  A4  0F 
Name Values 28  31  58  01  CB  E7  42  95  45  8B  A4  0F 
Correct serial 11  C3  9C  C8  30  70  19  20  9D  81  00  00 

And we're done! The correct serial for Cruehead is 11C39CC8307019209D810000


Anything you want to ask me about? Cruehead_@hotmail.com is my email.


Copyright © MiB 1998. All rights reversed.


[Back]