Cracking SendMail 2.0 for Windows NT
(Obvious Name Protections)

by Flipper (upg)

(24 September 1997)

Courtesy of reverser's page of reverse engineering

Well, here is Flipper's email:

  I have written another essay, but I hope you can use it under the 1997 HCU
training exercises. It has a date check, in a DLL file which uses obvious to
spot names like 'ValidateTrial', etc. Once again, I only used Hiew and wdasm
8.5 -- no softice. It also contains an explanation of how if..then..else
statements are compiled in C for Windows. I hope you can find a spot on your
page to stick it.

flipper (upg)
So, dear stupid shareware programmers... Should you call your routine "Fuck_all_hackers"; "Bombtheluser"; "Protectmyass"; or "Bitethosewhodaremodifymycode"? No, no, no you silly little poor things! First you should not call them at all (learn a little assembly, for Godot's sake!) and if you really do, call them "Allocatingmorememory"; "Freeingpointers"; "Givingextraspeed" or "GH45HHA-12" (this last one is a little suspect :-)
Write it one hundred times on your blackboards:
"I should not use plain English names to tag my protection routines"
"I should not use plain English names to tag my protection routines"
"I should not use plain English names to tag my protection routines"
"I should not use plain English names to tag my protection routines"

Cracking SendMail 2.0 for Windows NT - Obvious Name Protections
Written by Flipper (upg) on 09/21/97
This time around, our target is Metainfo's SendMail 2.0 for Windows NT. The
trouble with reverse engineering this software is that you must be running
Windows NT Server to install and configure it. I was running NT Server, but
couldn't get my DNS address verified -- I had hit a brick wall. Now, all that
was left was a dead listing approach without the actual program installed on
my machine.

I had a friend install it on an internet connected NT Server machine, and I
copied the file SENDMAIL.EXE onto a disk. This was just the beginning.

Tools You'll Need:

1. Windows Disassembler 8.5 or above
2. Hiew 5.65
3. A copy of SendMail 2.0 Build 2144 for Windows NT Server.
   [it can easily be found at]

First things first. I had no idea what would happen if I had set the clock
ahead after SendMail was installed, so back I went to my friend's place to
see what would happen. The software works for 30 days, and then the trial
key expires. Thus, the service will start, but anyone trying to access the
SMTP port will get a nice message stating that the software has expired.

If you enter an invalid key, it will bring up a message box saying the all
too familiar phrase, "Invalid Key."

So, let's get a dead listing of SENDMAIL.EXE. After looking through the code
for string references and the like, you'll come up with absolutely nothing.
How can this be? Well, all this means is that those strings are contained
in a dynamic link library (dll) file. So, do we find out what file those
strings are stored in? Simple.

Load up SENDMAIL.EXE (assuming you could either get a copy, or installed it
yourself) with Hacker's View. Press F7 and search for the string "Invalid
Key". No luck there, so try "expired". Finally, a match -- now I know what
you are saying, 'but you said there was no string reference to this phrase
in the dead listing, flipper old pal..'. I did say that, but sometimes the
dead listing does not reveal all that lies beneath the code.

By just looking at the code from Hiew, we can see what file those nasty
strings are being held in.

.0005D010:  49 6E 76 61-6C 69 64 20-73 65 72 69-61 6C 20 6E  Invalid serial n
.0005D020:  75 6D 62 65-72 20 6F 72-20 74 72 69-61 6C 20 74  umber or trial t
.0005D030:  69 6D 65 20-65 78 70 69-72 65 64 00-53 4D 00 00  ime expired SM
.0005D040:  46 73 64 61-68 36 37 61-6E 76 63 00-53 4F 46 54  Fsdah67anvc SOFT
.0005D050:  57 41 52 45-5C 4D 65 74-61 49 6E 66-6F 5C 53 65  WARE\MetaInfo\Se
.0005D060:  6E 64 6D 61-69 6C 00 00-66 31 32 33-2D 34 35 36  ndmail  f123-456
.0005D070:  32 2D 30 33-36 31 2D 31-32 33 34 00-43 61 6E 6E  2-0361-1234 Cann
.0005D080:  6F 74 20 6C-6F 61 64 20-6D 65 74 61-63 70 31 30  ot load metacp10
.0005D090:  2E 64 6C 6C-00 00 00 00-47 65 74 54-72 69 61 6C  .dll    GetTrial
.0005D0A0:  49 6E 73 74-61 6C 6C 54-69 6D 65 00-56 61 6C 69  InstallTime Vali
.0005D0B0:  64 61 74 65-53 65 72 69-61 6C 00 00-49 6E 69 74  dateSerial  Init
.0005D0C0:  52 65 67 69-73 74 72 61-74 69 6F 6E-00 00 00 00  Registration
.0005D0D0:  6D 65 74 61-63 70 31 30-2E 64 6C 6C-00 00 00 00  metacp10.dll

How interesting these lines above are. Look at what we have in the above
listing, and you'll see how powerful a hex editor can be.

1. We have the phrase we searched for at 5D010 (all addresses are in 32 bit
   DWORD format)

2. At 5D040 we have the location in the registry where the serial number
   will be stored (SOFTWARE\MetaInfo\Sendmail)

3. Loo and behold, we even have a reference to the Demo License serial number
   at 5D060.

4. At line 5D080 we now know the name of the dll that is being called :-)

5. And to make our job even easier, we also have the names of all of the
   functions called in order to check the serial number at line 5D090.

With all this, we should be able to crack this program in about ten minutes.

First, find the file METACP10.DLL. It should be located in your Windows NT
'System32' directory. Once you have that file, get a dead listing of it
right away. One of the reasons I use dead listings so much is that SoftIce
for Windows NT is a pain to setup, and I don't want to restart the computer
just to get rid of a little date check ;->

All right, what should we search for in the METACP10.DLL dead listing? Simple,
anything that leads us to the protection scheme. Such words as 'Expired Key'
and 'Invalid Key' come to mind.. as well as 'Registered', 'Days in use', and

Let's begin with 'ValidateSerial', since we know this function was called
from inside SENDMAIL.EXE. Now stop for a moment; the name of this function
gives it away, and if you look further into the METACP10.DLL file, you'll
come across similar functions, with down to earth, easy to understand names.

Here's what I came across when I searched for that phrase.

* Referenced by a CALL at Addresses:10001D82   , :10001E2B
Exported fn(): ValidateSerial - Ord:001Fh
:10001673 55                      push ebp
:10001674 8BEC                    mov ebp, esp
:10001676 83EC0C                  sub esp, 0000000C
:10001679 837D0800                cmp dword ptr [ebp+08], 00000000
:1000167D 7408                    je 10001687
:1000167F 8B4508                  mov eax, dword ptr [ebp+08]
:10001682 8945F8                  mov dword ptr [ebp-08], eax
:10001685 EB07                    jmp 1000168E

Aha, we've stumbled upon a goldmine. There are only two places where this
function is called from. Now, there are two possible ways to crack this
software. One way is to assume the user has left the demo key as is, and
the program will expire normally, and the other is to allow the user to enter
any key they want, and then the program will report an invalid key.

The easiest way (and most rewarding way) to do this crack is to choose the
second way, but I will leave that as an exercise for the more advanced
cracker. For time's sake, we'll take the easy way out, and a way out that
will let you make a crack that any user can use.

Let's follow this procedure through, and see where it takes us. At 1000167D
we see a jump if ebp+08 is equal to 0. If that's the case, it takes us to
this piece of code.

:10001687 C745F848140110          mov [ebp-08], 10011448

So, if epb+08 is equal to zero, then epb-08 will now equal 10011448, which
is not a pointer, so it will not show up in the dead listing.

Back to the function, it will eventually jump to 1000168E. We find..

* Possible StringData Ref from Data Obj ->"f123-4562-0361-1234"
:1000168E 6874E00010              push 1000E074
:10001693 8B4DF8                  mov ecx, dword ptr [ebp-08]
:10001696 51                      push ecx
:10001697 E8042B0000              call 100041A0
:1000169C 83C408                  add esp, 00000008
:1000169F 85C0                    test eax, eax         
:100016A1 7509                    jne 100016AC          ; ref to ValidateBomb
:100016A3 6A00                    push 00000000
* Reference To: METACP10.ValidateTrial
:100016A5 E847010000              call 100017F1
:100016AA EB37                    jmp 100016E3

So there is our reference to the demo serial number, and finally a call
to a function called 'ValidateTrial'. I spent a good deal of time looking
through each of these procedures, and I won't dwell too deeply on them here,
but if you trace 'ValidateTrial' to 100017F1, you'll run into another good
function name, 'ValidateBomb'. Suffice it to say, we don't want this program
to ever reach the 'ValidateBomb' phase, so the crack is very clear now.

Well, we don't want to jump to a procedure that calls 'ValidateBomb', so we
simply remove that jump alltogether from 100016A1.

:100016A1 90                      nop
:100016A2 90                      nop

That should take care of the first check, and now onto the second check.

:100016A5 90                      nop          
:100016A6 90                      nop
:100016A7 90                      nop
:100016A8 90                      nop
:100016A9 90                      nop

I know this method is horrible, and a nicer way is to use inc ax, dec ax
instead, but I only patched it this way to show you how this program uses 
simple plain English names for every function, and in that respect, making 
it very easy to jump around, or complete cut them out.

The above patch will properly crack this software, and the demo key will now
work as if the program is in registered mode. However, I'm not done yet. I
have one more thing to show you about the wonderful dll we are cracking.

Search for the word 'Registered' in the dead listing. You should end up at
line 10001ED1. If you look below, there are 5 different possibilities that
a serial key can force the program to report. These five 'blocks' of code
are set one after another without a call or jump reference above them. This
is very interesting indeed. Let's have a look at the code just above 10001ED1
for a moment.

The five keyfile 'modes' are as follows. Registered, Trial Key, Expired Key,
Invalid Key, and Intermediate (hmm..)

* Referenced by a Jump at Address:10001E37(C)
:10001EA5 833D4816011000          cmp dword ptr [10011648], 00000000
:10001EAC 0F858B000000            jne 10001F3D
:10001EB2 8B55FC                  mov edx, dword ptr [ebp-04]
:10001EB5 8995A8F6FFFF            mov dword ptr [ebp+F6A8], edx
:10001EBB 83BDA8F6FFFF04          cmp dword ptr [ebp+F6A8], 00000004
:10001EC2 7774                    ja 10001F38
:10001EC4 8B85A8F6FFFF            mov eax, dword ptr [ebp+F6A8]
:10001ECA FF2485AB200010          jmp dword ptr [4*eax + 100020AB]

Look at the last line of code, at line 10001ECA. This is a very unique jump
indeed. It translates as JUMP to a 32 BIT ADDRESS, which is the value of EAX
multiplied by 4, plus the DWORD (pointer) value of 100020AB.

At 100020AB we find this piece of code.

:100020AB D11E0010                DWORD 10001ED1

So, FOUR times the value of EAX plus DWORD 10001ED1.. that sounds like a
jump to this following bit of code..

* Possible StringData Ref from Data Obj ->"Registered"
:10001ED1 6804E10010              push 1000E104
:10001ED6 8B4D0C                  mov ecx, dword ptr [ebp+0C]
:10001ED9 51                      push ecx
:10001EDA 8B5508                  mov edx, dword ptr [ebp+08]
:10001EDD 52                      push edx

How interesting. So, if the line before the jump inserts a value into EAX,
it makes no matter what it is, then we can assume that this very interesting
jump routine is an if then else structure, very well compiled.

:10001EC4 8B85A8F6FFFF            mov eax, dword ptr [ebp+F6A8]

Now, let's assume for a moment that the structure looks something like this
in C.

 if (RegFlag == 1)
  .. this program is registered, set other flags, jump, etc. ..
 else (RegFlag == 2)
  if (DaysInUse > 30)

And it continues like this for the next three options. So, using a bit of
logic, we can come to the conclusion that if EAX would somehow equal ZERO,
zero multiplied by four is STILL ZERO, plus 10001ED1 would make this program
jump to what's at 10001ED1, which is the correct address for the 'Registered'
mode string.

Simply change the instruction at 10001EC4 to

:10001EC4 33C0                    xor eax, eax             ; set eax to ZERO
:10001EC6 90                      nop
:10001EC7 90                      nop
:10001EC8 90                      nop
:10001EC9 90                      nop

Alas, this only controls the text display, so the program will still not work
after thirty days ;-) but it makes for interesting reverse engineering, as
this code is compact, and written very well.

Final notes? Well, I only had to use two tools to accomplish this job, and
one of them wasn't softice. Hiew does such a nice job of 32 bit addressing
that I find it does the job without the need for debugging at all. SendMail
is an excellent e-mail server, and since most high priced Windows NT programs
need to be written as efficiently as possible, most NT programs tend to use
a lot of compact code, as we've seen here.

Oh, and one final warning about this program. If you try and disassemble any
of the files mentioned here in Windows NT, wdasm32 just crashes and your
computer will record a memory access violation. To get a dead listing, use
Windows 95 instead.

written by flipper (upg) on 09/21/97.

(c) Flipper 1997. All rights reversed
You are deep inside reverser's page of reverse engineering, choose your way out:

redBack to Project 7 ("Most stupid protection")
redhomepage redlinks redanonymity +ORC redstudents' essays redacademy database
redtools redcocktails redantismut CGI-scripts redsearch_forms redmail_fravia
redIs reverse engineering legal?