
    _ ___ _ __ _ _____ _ ___ _ ____
   /_____ ___ _ __ ____ _ _____ _ /|
  |       Desktop Server 98      | |
  |   How to get a valid serial# | |
  |                              | |
  |     (c) 1998 by Dynamite     | |
  |___ _ _ _____ _ ___ _ _ _ _ __|/


 Index
  (0)   -   Who should try this
  (1)   -   What are we doin'
  (2)   -   About the prog
  (3)   -   What do we need
  (4)   -   The crack
  (5)   -   Some notes by me
  (6)   -   Greetz


(0) Who should try this
   This tut is only dedicated to people who are new to cracking. If you are
   an advanced or expert then you will not learn anything new. If you learned
   allready a bit about cracking and you allready patched some progs, but you
   never found a serial#, then this is a good tut for you.

(1) What are we doin'
   In this essay, you will not only NOP out a jump. You will get the correct
   unlock key for the entered serial#.

(2) About the prog
   Desktop Server 98 is a program to send emails without an outgoing mail
   server. The only limitation is, that you can only send 10 mails at a time.
   We will not crack the S/N protection. We will find a valid unlock key for
   our S/N. It's a nice prog for finding S/Ns, because you can register
   over and over and don't have to re-install it every time.

(3) What do we need
   (x) SoftICE 3.0+ (http://www.numega.com)
   (x) Desktop Server 98 (http://www.desktopserver98.com)
   (x) W32Dasm (I'm using version 8.9)

(4) The crack
   If you run DS98 (Desktop Server 98), you will note, that it's a simple
   s/n protection. Just enter any serial# and any unlock key (I used
   serial:+dynamite / key:12121212). When you press OK, a nag will popup, and
   tell you, that your key doesn't match the serial. Let's load DSKTPSVR.EXE
   into W32Dasm and search for the words in the nag. You will find the
   following piece of code:

   :0047F385 E852DAFEFF       call 0046CDDC                         ; Check the key
   :0047F38A 84C0             test al, al                           ; If al = 0 Then WrongUnlockKey
   :0047F38C 7472             je 0047F400                           ; Jump if key is bad, else go on
   :0047F38E A1C4614800       mov eax, dword ptr [004861C4]
   :0047F393 8B00             mov eax, dword ptr [eax]
   :0047F395 E8E62A0000       call 00481E80
   :0047F39A 8D55F8           lea edx, dword ptr [ebp-08]
   :0047F39D A10C614800       mov eax, dword ptr [0048610C]
   :0047F3A2 8B00             mov eax, dword ptr [eax]
   :0047F3A4 8B80E4010000     mov eax, dword ptr [eax+000001E4]
   :0047F3AA E8CD30FAFF       call 0042247C
   :0047F3AF 8B55F8           mov edx, dword ptr [ebp-08]
   :0047F3B2 8B83F8020000     mov eax, dword ptr [ebx+000002F8]
   :0047F3B8 0598020000       add eax, 00000298
   :0047F3BD E8BA47F8FF       call 00403B7C
   :0047F3C2 8B83F8020000     mov eax, dword ptr [ebx+000002F8]
   :0047F3C8 E83FD1FEFF       call 0046C50C

   * Possible StringData Ref from Code Obj ->"Registration succeeded"
                              |
   :0047F3CD B864F44700       mov eax, 0047F464
   :0047F3D2 E855D7FBFF       call 0043CB2C                         ; SuccessfullyReged_Window pops up
   :0047F3D7 C683FC02000000   mov byte ptr [ebx+000002FC], 00
   :0047F3DE 8B83F8020000     mov eax, dword ptr [ebx+000002F8]
   :0047F3E4 05D8020000       add eax, 000002D8

   * Possible StringData Ref from Code Obj ->"Destop Server 98 Unlock"
                              |
   :0047F3E9 BA84F44700       mov edx, 0047F484
   :0047F3EE E88947F8FF       call 00403B7C
   :0047F3F3 8B83F8020000     mov eax, dword ptr [ebx+000002F8]
   :0047F3F9 8B10             mov edx, dword ptr [eax]
   :0047F3FB FF5244           call [edx+44]
   :0047F3FE EB2C             jmp 0047F42C

   * Referenced by a (U)nconditional or (C)onditional Jump at Address:
   |:0047F38C(C)
   |

   * Possible StringData Ref from Code Obj ->"Key doesn't match serial number"
                              |
   :0047F400 B8A4F44700       mov eax, 0047F4A4
   :0047F405 E822D7FBFF       call 0043CB2C                         ; WrongUnlockKey_Window pops up
   :0047F40A 8B83F8020000     mov eax, dword ptr [ebx+000002F8]
   :0047F410 E867D2FEFF       call 0046C67C
   :0047F415 EB15             jmp 0047F42C


   We could easily patch this, by NOPing the "JE 0047F400" at :0047F38C. But
   that's not good. We want to get a valid unlock key. So look into the
   KeyCheckFunction at :0046CDDC.


   * Referenced by a CALL at Address:
   |:0047F385   
   |
   :0046CDDC 53               push ebx
   :0046CDDD 56               push esi
   :0046CDDE 57               push edi
   :0046CDDF 83C4B4           add esp, FFFFFFB4
   :0046CDE2 8BF1             mov esi, ecx
   :0046CDE4 8D3C24           lea edi, dword ptr [esp]
   :0046CDE7 33C9             xor ecx, ecx
   :0046CDE9 8A0E             mov cl, byte ptr [esi]
   :0046CDEB 80F909           cmp cl, 09
   :0046CDEE 7202             jb 0046CDF2
   :0046CDF0 B109             mov cl, 09

   * Referenced by a (U)nconditional or (C)onditional Jump at Address:
   |:0046CDEE(C)
   |
   :0046CDF2 880F             mov byte ptr [edi], cl
   :0046CDF4 46               inc esi
   :0046CDF5 47               inc edi
   :0046CDF6 F3               repz
   :0046CDF7 A4               movsb
   :0046CDF8 8BF2             mov esi, edx
   :0046CDFA 8D7C240A         lea edi, dword ptr [esp+0A]
   :0046CDFE 33C9             xor ecx, ecx
   :0046CE00 8A0E             mov cl, byte ptr [esi]
   :0046CE02 80F932           cmp cl, 32
   :0046CE05 7202             jb 0046CE09
   :0046CE07 B132             mov cl, 32

   * Referenced by a (U)nconditional or (C)onditional Jump at Address:
   |:0046CE05(C)
   |
   :0046CE09 880F             mov byte ptr [edi], cl
   :0046CE0B 46               inc esi
   :0046CE0C 47               inc edi
   :0046CE0D F3               repz
   :0046CE0E A4               movsb
   :0046CE0F 8BF0             mov esi, eax
   :0046CE11 33DB             xor ebx, ebx
   :0046CE13 889E75030000     mov byte ptr [esi+00000375], bl
   :0046CE19 8D442440         lea eax, dword ptr [esp+40]
   :0046CE1D 50               push eax
   :0046CE1E 8BCB             mov ecx, ebx
   :0046CE20 8D54240E         lea edx, dword ptr [esp+0E]
   :0046CE24 8BC6             mov eax, esi
   :0046CE26 E805FEFFFF       call 0046CC30
   :0046CE2B 8D442440         lea eax, dword ptr [esp+40]
   :0046CE2F 8BD4             mov edx, esp
   :0046CE31 33C9             xor ecx, ecx
   :0046CE33 8A08             mov cl, byte ptr [eax]
   :0046CE35 41               inc ecx
   :0046CE36 E8395DF9FF       call 00402B74                         ; Check the unlock key
   :0046CE3B 0F94C0           sete al                               ; Set AL = 1, if equal
   :0046CE3E 84C0             test al, al                           ; Key OK?
   :0046CE40 7538             jne 0046CE7A
   :0046CE42 B301             mov bl, 01
   :0046CE44 889E75030000     mov byte ptr [esi+00000375], bl
   :0046CE4A 8D442440         lea eax, dword ptr [esp+40]
   :0046CE4E 50               push eax
   :0046CE4F 8BCB             mov ecx, ebx
   :0046CE51 8D54240E         lea edx, dword ptr [esp+0E]
   :0046CE55 8BC6             mov eax, esi
   :0046CE57 E8D4FDFFFF       call 0046CC30
   :0046CE5C 8D442440         lea eax, dword ptr [esp+40]
   :0046CE60 8BD4             mov edx, esp
   :0046CE62 33C9             xor ecx, ecx
   :0046CE64 8A08             mov cl, byte ptr [eax]
   :0046CE66 41               inc ecx
   :0046CE67 E8085DF9FF       call 00402B74                         ; Check the unlock key
   :0046CE6C 0F94C0           sete al                               ; Set AL = 1, if equal
   :0046CE6F 3C01             cmp al, 01                            ; Key OK?
   :0046CE71 7507             jne 0046CE7A
   :0046CE73 C6867503000001   mov byte ptr [esi+00000375], 01

   * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
   |:0046CE40(C), :0046CE71(C)
   |
   :0046CE7A 83C44C           add esp, 0000004C
   :0046CE7D 5F               pop edi
   :0046CE7E 5E               pop esi
   :0046CE7F 5B               pop ebx
   :0046CE80 C3               ret


   You know, that it depends on the value in AX, if the key is valid or not.
   So we can search for the last place in the function, where AL gets set. We
   note the two places, where AL is set to 1 if zeroflag is set (sete al). So
   we found the function, that compares our entered unlock key with the
   correct one. Now look into the function, to find the place, where our key
   gets compared.


   * Referenced by a CALL at Addresses:
   |:0040348A   , :0045250C   , :00452523   , :004534E7   , :00453533   
   |:00453546   , :00455983   , :00456343   , :0045636E   , :004563B2   
   |:004563D9   , :004563FF   , :0046CE36   , :0046CE67   
   |
   :00402B74 53               push ebx
   :00402B75 56               push esi
   :00402B76 51               push ecx
   :00402B77 89CE             mov esi, ecx
   :00402B79 C1EE02           shr esi, 02
   :00402B7C 7426             je 00402BA4

   * Referenced by a (U)nconditional or (C)onditional Jump at Address:
   |:00402B9A(C)
   |
   :00402B7E 8B08             mov ecx, dword ptr [eax]              ; Move the first 4 bytes of the VALID
                                                                      unlock key to ECX.
                                                                      The first byte is the length of the key
   :00402B80 8B1A             mov ebx, dword ptr [edx]              ; Move the first 4 bytes of the entered
                                                                      unlock key to EBX
   :00402B82 39D9             cmp ecx, ebx                          ; Compare the first 4 bytes
   :00402B84 7545             jne 00402BCB                          ; Jump if they doesn't match
   :00402B86 4E               dec esi
   :00402B87 7415             je 00402B9E
   :00402B89 8B4804           mov ecx, dword ptr [eax+04]           ; Move the next 4 bytes of the
                                                                      valid key to ECX
   :00402B8C 8B5A04           mov ebx, dword ptr [edx+04]           ; Move the next 4 bytes of the
                                                                      entered key to EBX
   :00402B8F 39D9             cmp ecx, ebx                          ; Compare the 4 bytes
   :00402B91 7538             jne 00402BCB                          ; Jump if they doesn't match
   :00402B93 83C008           add eax, 00000008
   :00402B96 83C208           add edx, 00000008
   :00402B99 4E               dec esi
   :00402B9A 75E2             jne 00402B7E
   :00402B9C EB06             jmp 00402BA4

   * Referenced by a (U)nconditional or (C)onditional Jump at Address:
   |:00402B87(C)
   |
   :00402B9E 83C004           add eax, 00000004
   :00402BA1 83C204           add edx, 00000004

   * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
   |:00402B7C(C), :00402B9C(U)
   |
   :00402BA4 5E               pop esi
   :00402BA5 83E603           and esi, 00000003
   :00402BA8 7436             je 00402BE0
   :00402BAA 8A08             mov cl, byte ptr [eax]                ; Move next byte of valid key to CL
   :00402BAC 3A0A             cmp cl, byte ptr [edx]                ; Compare the byte of the valid key
                                                                      with the one from the entered key
   :00402BAE 7530             jne 00402BE0                          ; Jump if they doesn't match
   :00402BB0 4E               dec esi
   :00402BB1 7413             je 00402BC6                           ; Jump if end of key
   :00402BB3 8A4801           mov cl, byte ptr [eax+01]             ; Move next byte of valid key to CL
   :00402BB6 3A4A01           cmp cl, byte ptr [edx+01]             ; Compare the byte of the valid key
                                                                      with the one from the entered key
   :00402BB9 7525             jne 00402BE0                          ; Jump if they doesn't match
   :00402BBB 4E               dec esi
   :00402BBC 7408             je 00402BC6                           ; Jump if end of key
   :00402BBE 8A4802           mov cl, byte ptr [eax+02]             ; Move the last byte of the valid
                                                                      key to CL
   :00402BC1 3A4A02           cmp cl, byte ptr [edx+02]             ; Compare the last byte of the valid
                                                                      key with the one from the entered key
   :00402BC4 751A             jne 00402BE0                          ; Jump if the doesn't match
   
   * Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
   |:00402BB1(C), :00402BBC(C)
   |
   :00402BC6 31C0             xor eax, eax                          ; Erase EAX
   :00402BC8 5E               pop esi
   :00402BC9 5B               pop ebx
   :00402BCA C3               ret


   Okay. If you want to know the valid key for your entered serial#, just enter
   "D EAX" at :00402B7E, and you will see it. Easy, isn't it? ;)
   But remember, that there was a second jump to this function. The first jump
   was at :0046CE36 and the second was at :0046CE67. Our key is checked twice.
   But everytime with another valid key. That means, that there are two valid
   keys for one serial#. Here are my keys:

   Serial#: +dynamite
   Key_1:   $A655BFBD
   Key_2:   $CC7C8C7B

(5) Some notes by me
   That's it. I hope you enjoyed it.
   This was my first essay I ever wrote.
   Sorry for my bad english :]
   If you have any comments, questions or criticism about this
   tut, you can contact me by eMail, ICQ or IRC:

    eMail: dynamite_@gmx.net
    ICQ:   15225180
    IRC:   #cracking or #cracking4newbies

(6) Greetz
   Greets are going to +ORC, fravia+, +HCU and all other crackers
   in the world!
