Desktop Server 98 is a program to send emails without an outgoing mail server. It's very curious because if you successfully register your copy of Dektop Server, there will be no changes you can see. So, why should we crack it? The answer is simple. Just to enlarge your knowledge!
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 tells 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 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 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 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 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 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 Jump at Address:00402B87(C) | :00402B9E 83C004 add eax, 00000004 :00402BA1 83C204 add edx, 00000004 * Referenced by a 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 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
Okey. 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 for all the poor lamers in the world, that will never be
able to crack:
Serial#: +dynamite Key_1: $A655BFBD Key_2: $CC7C8C7B
That was it. I hope you enjoyed it. This was my first essay to the +HCU. Greets are going to +ORC and all other +HCUkers. (c) +dynamite (dynamite_@gmx.net)