April 1998
"Memory Map 2"
My first crack! 
MS-DOS PROGRAM
MS-DOS Reversing 
 
by The Sandman 
 
 
Code Reversing For Beginners 
 
 
 
Program Details
Program Name: Memory Map 2
Program Type: Utility
Program Location: [ here ]
Program Size: 24379 Bytes
Packed using: LZEXE V0.91 or V1 
 
  
Tools Required:
Unp  - DOS generic unpacker
Softice V3 - Win'95 De-bugger
 
Rating
Easy ( X )  Medium (   )  Hard (   )  Pro (   ) 
There is a crack, a crack in everything. That's how the light gets in.
 
 
 
An example of cracking a small DOS Utility
Written by The Sandman
 
 
 
Introduction
 
Memory Map 2 (with Nigel) originally came out with an issue of PC Plus  around *1990*.

It's a full blown TSR (Terminate Stay Resident) program with nothing crippled but has an annoying feature where at random times, a message box will pop-up reminding you to buy the version without the "Nigel nag messages".  It features a breakdown of the BIOS, displays memory contents in Assembler, Hex and in text formats and much more.
Not bad for just 40K!.
 
The Essay 
 

Some years ago when this program originally came out I tried  ( un-successfully ) to *crack* the annoying Nigel nag messages out from it but remembered that I got bogged down trying to unpack it's code so that I could get a crack at the protection scheme used within it. I remember also  trying to work out where the messages where stored and how they were used within the protection system itself. If only I knew about ZEN, things *might* have been different..:)

Since I am a newbie to reverse engineering code my essay's will take you through possibly the same steps as you might make only in this case you can learn from my mistakes in this field and progress further to better and more elaborate schemes...
 
On with the essay...
 

With Softice up and running, start up the Window's File Manager and use the option 'Quick View' on our target file (MAP.EXE).  OK, it's an MS-DOS program so no messy Windows files are involved to distract us in our work.
 
My first step at this stage was to see what, if any, readable messages  were within the code itself, every little bit of information about our  target program helps to build a better picture on it's overall structure.

A quick tip you can use to view this file for any readable text is to  Rename the file's extension from .EXE to .TXT then open it up in Window's Notepad!. Because the file is relatively small ( less than 64K ) Notepad  will happily load in this file for you too look at.

Wordpad on the other hand will detect that it's really an executable file and refuse to load it in. (Why does Word Pad check for this? anyone know why?).
 

OK, what can we see....  Ah, notice that the file begins with:-
 

MZ;0    Uÿÿì     €    Ü   LZ91

 
This tells us that the file has been compressed by the DOS File Packer LZEXE V0.91.  Some further readable text can still be seen within this file but nothing else of any real interest. We could, if we wish, unpack this file here and now using a unpacker utility like UNP or UNLZEXE but that's not necessary at the moment, since when we first run our target program the code will automatically be de-compressed in memory by the time we get inside it.
 
Un-packing the target program so that we can create a 'Dead Listing' of the code ( more about this later, one thing at a time ) will not help us much since our knowledge of assembly and the layout of the internal code within the target program is limited or non-existent at the moment.
 
While still in the Window's File Manager Double-Click on our Target File ( Map.EXE ).  While we are waiting for our first 'Nigel nag message' try out the various features to be had within this utility. Our first nag window should soon pop-up, notice the following:-
 

     1. When it first appears there is a 2-3 second pause before it gives you the chance to press it's chosen key from the keyboard. This is standard for all these nag messages. Watching further nag messages you will see that there are three stages to each message, they are:-
 
    1b.  Display initial message.
           Pause 2-3 seconds.
           Display required key to close message window.
 

On the next message press Ctl and D keys together to start Softice while in the 2-3 pause. Softice should then break into the following piece of Code:-
 
 
:0715.959D  
:0715.959F   
:0715.95A4  
:0715.95A7    
:0715.95AA  
:0715.95AC   
:0715.95AF  
:0715.95B1 
mov es, ax  
mov bx, cs:[884D]  
mov ax, es:[bx]  
add ax, 0024    ;ROM BIOS Time routine.  
jb 95B1  
cmp ax, es:[bx] ;You should land   
ja 95AC         ;somewhere here   
ret             ;Job done
 
**Please Note **
 
In my example the Memory Map2 program was loaded at memory segment :0715. but this will proberbly be different on your computer. The important address as far as your concerned is the memory offset .959D that follows it.

Example:
 
:0715.959D
:          :
:          :...........Memory Offset
:......................Memory Segement

The above 8 lines I worked out is our routine to create those 2-3 second  pauses after each nag message is shown on the screen and which makes us wait before we are shown the key to press on our keyboard to close it. At this stage I typed STACK into Softice to see if their was any clues to where we might be going next once we get to the RET instruction but nothing was shown.
 

The STACK is simply a location inside the computer's memory that temporarily records the exact location ( memory address ) of where the program was last at before it was told to stop what it was doing and carry out the task of  doing something else. It also is used as a temporary storage for memory addresses etc.
 
A RET instruction in Assembly simply means RETurn back to where-ever in the program's code this routine was called from.
 

If you now press the F10 key several times you will see that Softice keeps executing the same two lines:-

:0715.95AC                  cmp ax, es:[bx]
:0715.95AF                  ja 95AC
 

What's happening here is that the register AX has been given the value of a long integer counter within the ROM BIOS at location 04Ch that is present in all P.C's and then had a value of 24 added to it. The line containing the cmp ax,es:[bx] instruction is now comparing the value stored in the ax register to the value stored in the ROM BIOS.
 
The ja 95AC instruction simply keeps you waiting until the ROM BIOS counter catches up
to the value stored in the ax register.  Don't forget that the value stored in the ax register was increased by 24, representing many thousands of idle clock ticks of your P.C doing nothing ( our 2-3 second pause! ).
 
To get past this seemingly 'endless loop' simply move your mouse cursor to the line below these two lines so that it's on the line shown below:-
 

:0715.95B1 C3                     ret

Then type Here

After a 2-3 second pause Softice should break once more and display the same line that we had just told Softice to stop at when we had typed Here.
 

Press F10 once more.

We now arrive at the two main Nigel nag screen routine, although it originally took  me quite a while to figure out..:(
 
 
:0715.94EB E882F3  
:0715.94EE 2E3B064B88  
:0715.94F3 7307  
:0715.94F5 5E  
:0715.94F6 5F  
:0715.94F7 5A   
:0715.94F8 59  
:0715.94F9 5B   
:0715.94FA 58  
:0715.94FB C3  
 
*** NIGEL'S NAG SCREEN ROUTINE  

:0715.94FC 2E8B1ED494  
:0715.9501 8B37   
:0715.9503 8B0C   
:0715.9505 BFF005   
:0715.9508 81E1FE00   
:0715.950C 2BF9  
:0715.950E 2E893E5088  
:0715.9513 8B0C  
:0715.9515 51  
:0715.9516 56  
:0715.9517 E8A300   
:0715.951A 2E8A263D01  
:0715.951F 2E8B3E5088  
:0715.9524 E805C7  
:0715.9527 5E  
:0715.9528 83C602  
:0715.952B E84BC7  
:0715.952E E8AFF1  
:0715.9531 E86700  
:0715.9534 BE9195   
:0715.9537 2E8B3E255C  
:0715.953C 83EF16  
:0715.953F 2E8A263D01  
:0715.9544 50   
:0715.9545 E892C7  
:0715.9548 B42C  
:0715.954A CD21  
:0715.954C 80E60F  
:0715.954F 80C641   
:0715.9552 58  
:0715.9553 8AC6  
:0715.9555 83EF04  
:0715.9558 AB   
:0715.9559 E85A00  
:0715.955C B400  
:0715.955E CD16  
:0715.9560 24DF  
:0715.9562 3AC6  
:0715.9564 75F3   
:0715.9566 E807F3  
:0715.9569 052800  
:0715.956C 2EA34B88  
:0715.9570 59  
:0715.9571 E87100  
:0715.9574 2E8306D49402   
:0715.957A 2E813ED494D494  
:0715.9581 7207  
:0715.9583 2EC706D494AA94  
:0715.958A 5E  
:0715.958B 5F  
:0715.958C 5A  
:0715.958D 59  
:0715.958E 5B 

call 8870  
cmp ax, cs:[884B]  
jnb 94FC  
pop si  
pop di  
pop dx  
pop cx  
pop bx  
pop ax  
ret  
  
* Referenced by a (C)onditional Jump at Address: 0001.94F3(C)  
  
mov bx, cs:[94D4]  
mov si, [bx]  
mov cx, [si]  
mov di, 05F0  
and cx, 00FE  
sub di, cx  
mov cs:[8850], di  
mov cx, [si]  
push cx  
push si  
call 95BD  
mov ah, cs:[013D]  
mov di, cs:[8850]  
call 5C2C  
pop si  
add si, 0002  
call 5C79  
call 86E0  
call 959B ;Our 2-3 second wait routine  
mov si, 9591 ;Land here from the wait routine  
mov di, cs:[5C25]  
sub di, 0016  
mov ah, cs:[013D]  
push ax  
call 5CDA  
mov ah, 2C    ;Get Time from the BIOS  
int 21  
and dh, 0F  
add dh, 41  
pop ax  
mov al , dh  
sub di, 0004  
stosw  
call 95B6  
mov ah, 00    ;Read Keystroke  
int 16  
and al, DF  
cmp al , dh  
jne 9559  ;read key until it is the right 
call 8870 ;one 
add ax, 0028  
mov word ptr cs:[884B], ax  
pop cx  
call 95E5  
add word ptr cs:[94D4], 0002  
cmp word ptr cs:[94D4], 94D4  
jb 958A  
mov word ptr cs:[94D4], 94AA  
pop si  
pop di  
pop dx  
pop cx 
 

 
There are a number of branches that go out from this routine but in order to keep things simple here I won't go into them, but instead I will  concentrate on the main issues here in order that you don't waste more time on this program than is necessary.  If you look at the above listing you will see where we have RETurned from our 2-3 second pause routine.

If you have been reading the lessons given to us by ORC+ ( they can be obtained from here ) then you will know that you need to know what it is your after and that pursuing something else while doing this is a waste of your time, especially if that wodka your poured earlier is getting warm!.

During the course of this programming exercise I forgot this golden rule and wasted many hours travelling all over the program's code getting bogged down with notes that made no sense to me 10 minutes after I had made them.

So the idea here is to keep things simple, for the time being that is..:) OK, in this case we know that this program is fully functional, i.e not crippled, and that to make this program just like it's 'registered' version all we need to do is to disable these annoying Nigel nag messages.

 
What do we do now?.  Do we start trying to track down the locations of all these nag messages?, we could do because the program has been de-compressed in memory when we ran it so now everything is in a readable form, or do we try to get to locate the source in the program that say's whether or not to display these messages in the first place!. Disable the point where this decision is actually made and we never have to worry about where or how those messages are created!. Does that light bulb start to glow brighter?.

Let's crack on...

Using a little Zen we can see in Softice where this routine starts and where it ends. It starts at the line:-
 

:0715.94FC 2E8B1ED494             mov bx, cs:[94D4]

because above this line we see that there is a RET instruction, which 99 times out of a 100 means that it belongs to another routine and that is it ends, so then the next routine begins right after this RET instruction.

In simple terms we can say that for each routine in the program's code ends with a RET instruction and that the next routine begins right after this instruction.
 

Programmers tend to think in straight lines when it comes to putting a program together, it helps to keep things simple for them too. So if they created a protection system for their program it makes sense to place all the associate routines close by in the program's code so that they can always go to each of these routines during testing that much quicker.

Imagine having a hard copy of the entire program printed out, wouldn't it be easier to have say all the routines on just one or two pages than having it spread out across 100's or 1000's of pages!. In our case this is what has happened, all our routines are close by.  Since protection routines are usually the last thing to be added to program they tend ( but not always ) to be stuck right at the end of the program's code, bolted on if you like.

OK, history lesson over, lets get what knowledge we need and do the crack..

At the point we are at we can assume for now that we've RETurned from our pause routine and ended up in one of the main routines that handles our nag messages, we know that because we used Softice after the nag message was shown but before the program asks us to press a certain key to clear it, so we're roughly speaking in the middle of this process.

It's worth writing down the whole routine on paper so that you will have a better idea of it when looking at it than having to scroll up and down in Softice.

At this point there are a number of way's to proceed, each would be equally valid. We could place breakpoints on one or two of those CALL instructions that are above where we emerged from our 2-3 second pause routine which would at least give us a better idea of how this protection system worked but that might just bog us down with too much info which in turn could bury us in the program's inner workings!.

Remember I said earlier that their had to be a trigger that determines whether or not the nag messages get shown or not,  and that as a rule, all the associate routines to do with this protection would be close by ( this is certainly true of 'older' programs, which our program is ) then in that case we can start by just looking at the routines that sit next to the one we're currently in.

We're looking for something that does a CoMPare to a number or register (the AX or AH or AL registers are good bets to look for ) which is then followed by a JP on condition instruction which is based on the results of this comparison.  We will know if we have found the right 'trigger' to the our nag screen routine because it will JUMP TO THE BEGINNING OF IT!.

Sure enough above our main routine there lies a Comparison and a Jump  instruction AND it Jumps to the beginning of our routine!.  Right, now scroll further up the listing to see if there are any more likely 'triggers' and then scroll down past our main routine to see if there are any down there.

 
:0715.94EB E882F3       call 8870
:0715.94EE 2E3B064B88   cmp ax, cs:[884B]     ;Does AX equal the
:0715.94F3 7307         jnb 94FC              ;contents of loc cs:[884b]
:0715.94F5 5E           pop si
 

For all intentional purposes we can forget the CALL 8870 instruction above our likely nag screen 'trigger'. If it helps we can assume it set's up the AX register in someway ( which it does ) so that this comparison can be made.  From the above conditional JumP are two outcomes, either JUMP directly to our nag screen message routine or carry on with the next instruction, which in this case is:-
 

:0715.94F5 5E                     pop si
 

What if we change one byte that belongs to the JumP instruction so that when it gets triggered, instead of going directly to our nag screen message routine it went instead to the next instruction directly underneath it, as though it hadn't been triggered in the first place!.

At present this conditional JumP instruction will jump over seven places to reach our nag screen message routine, so why not make this JumP instruction jump only itself onto the next instruction below it, then it will procced  onto the next instruction even though it has been triggered!.

So, all you need to do is type:-

e 94F3
 

This tells Softice we want to edit the memory contents at location 94F4 Now change the value 73 to 90 then the next value 07 change this also to 90

Finish off now by pressing the ESC button then typing x and finally exiting out of Softice. You now have a *cracked* Memory Map 2 program that runs without any nag screens but remember, this will work only as long as the program is in memory.  The copy you have on your hard disk hasn't been touched, so it's still un-cracked... Read on.
 
 
Final Notes 
 
This program uses a simple 'trigger' based on the memory contents at 0715:884B which is then compared to a pre-defined value stored in the AX register. Depending on the results of this comparison will decied wether or not our Nigel Nag Screen Routine gets called or not.

By changing the destination only of the JumP instruction that gets called from time to time we have, in effect, managed to isolate and preserve from the program all it's protection routines.

There are of course, many ways to achieve the same outcome as described above, I have shown you just one of these, the way I did things.  I could have located the 'timer' routine that decieds how long before the next message gets shown and disable that so it never gets round to showing any messages at all or you could have perhaps... see what I mean here, the possibilities are endless and just as challenging.
 
To make this *crack* permanent, load up map.exe into your favourite hex-editor ( I use HexWorkshop Version 2) then get it to SEARCH FOR: 5756E882F32E3B06
 
000093F0 91932394 AA942EC7 064B8801 002E803E ..#......K.....>
00009400 5C010674 16505351 525756E8 82F32E3B \..t.PSQRWV....;
00009410 064B8873 075E5F5A 595B58C3 2E8B1ED4 .K.s.^_ZY[X.....
 
 
Now REPLACE the following HIGHLIGHTED BYTES:
 
000093F0 91932394 AA942EC7 064B8801 002E803E ..#......K.....>
00009400 5C010674 16505351 525756E8 82F32E3B \..t.PSQRWV....;
00009410 064B8890 905E5F5A 595B58C3 2E8B1ED4 .K.s.^_ZY[X.....

Now get your hexeditor to save the changes to your hard disk.
 
Job Done.
Ob Duh 
 
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 continue to produce even *better* software for us to use and more importantly, to continue offering even more challenges to breaking their often weak protection systems.

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.
 


 
 
 Next   Return to Essay Index   Previous 
 


Essay by:          The Sandman
Page Created: 2nd May 1998