    
        ____                     __       __           
       /  _/_ _  __ _  ___  ____/ /____ _/ /            
      _/ //  ' \/  ' \/ _ \/ __/ __/ _ `/ /              
     /___/_/_/_/_/_/_/\___/_/  \__/\_,_/_/               
       ____                          __          __      
      / __ \___ ___ _______ ___  ___/ /__ ____  / /____  
     / /_/ / -_|_-</ __/ -_) _ \/ _  / _ `/ _ \/ __(_-<  
    /_____/\__/___/\__/\__/_//_/\_,_/\_,_/_//_/\__/___/  
                                                         
          Web: http://www.ImmortalDescendants.com        
                     Author: Amante4                     
                      Date: 03/27/2000                   
          Topic: My solution to Santmat's reverseme 1    
                      Level: Intermediate                
                                                         
      
       
        
        
***************************
* Introduction
***************************

Well I'm going to reverse another interesting reverseme from a fellow
Immortal Descendants member, SantMat. This reverseme can be found on
our site at:
http://www.immortaldescendants.org 

***************************
* Tools Needed
***************************

1) Disassembler - I use IDA but W32Dasm is just fine too.
2) Debugger - SoftIce
3) Hexeditor - HVIEW
4) ProcDump32 v1.6FINAL - For the PE editor

***************************
* The Essay
***************************

OK, first lets see what the job is at hand. Looking at the included readme file it says the program
will tell us what to do. So lets look at the program to see what it does. Opening it, we see a nice
intro screen. Telling an amusing story of our friend Dr. Evil. If you press the "Continue to Program" 
button, you'll start the destruction tool to destroy the world. For this, challange we must change this
intro screen into a password protection screen so that Dr. Evil can't use this destruction tool without a 
correct password. OK Let's get down to it and disassemble the file reverseme.exe. 

Looking at the file you'll see a pretty small main program like this:

.text:00401000 6A 00                    public start
.text:00401000                   start  proc near
.text:00401000                          push    0
.text:00401002 E8 4B 05 00 00           call    j_GetModuleHandleA
.text:00401007 6A 0A                    push    0Ah
.text:00401009 6A 00                    push    0
.text:0040100B 6A 00                    push    0
.text:0040100D FF 35 F4 33 40 00        push    dword_0_4033F4
.text:00401013 E8 07 00 00 00           call    sub_0_40101F     **** Call the main part of the program
.text:00401018 6A 00                    push    0
.text:0040101A E8 2D 05 00 00           call    j_ExitProcess
.text:0040101A                   start  endp


Then you'll see the subroutine at 0x0040101f register a window class and call CreateWindowExA to create our
lovely intro window.


.text:0040101F 55                     push    ebp                                               
.text:00401020 8B EC                  mov     ebp, esp                                          
.text:00401022 83 C4 B0               add     esp, 0FFFFFFB0h                                   
.text:00401025 B0 01                  mov     al, 1                                             
.text:00401027 C7 45 D0 30 00 00 00   mov     [ebp+var_30], 30h     **** Load up the WNDCLASSEX structure
.text:0040102E C7 45 D4 03 00 00 00   mov     [ebp+var_2C], 3                                   
.text:00401035 C7 45 D8 07 11 40 00   mov     [ebp+var_28], offset main_win_proc  **** 3rd thing is Window Procedure           
.text:0040103C C7 45 DC 00 00 00 00   mov     [ebp+var_24], 0                                   
.text:00401043 C7 45 E0 00 00 00 00   mov     [ebp+var_20], 0                                   
.text:0040104A FF 35 F4 33 40 00      push    dword_0_4033F4                                    
.text:00401050 8F 45 E4               pop     [ebp+var_1C]                                      
.text:00401053 C7 45 F0 05 00 00 00   mov     [ebp+var_10], 5                                   
.text:0040105A C7 45 F4 00 00 00 00   mov     [ebp+var_C], 0                                    
.text:00401061 C7 45 F8 00 30 40 00   mov     [ebp+var_8], offset aSimplewindow ; "SimpleWindow"
.text:00401068 6A 00                  push    0                                                 
.text:0040106A 6A 00                  push    0                                                 
.text:0040106C E8 17 05 00 00         call    j_LoadIconA                                       
.text:00401071 89 45 E8               mov     [ebp+var_18], eax                                 
.text:00401074 89 45 FC               mov     [ebp+var_4], eax                                  
.text:00401077 68 00 7F 00 00         push    7F00h                                             
.text:0040107C 6A 00                  push    0                                                 
.text:0040107E E8 FF 04 00 00         call    j_LoadCursorA                                     
.text:00401083 89 45 EC               mov     [ebp+var_14], eax                                 
.text:00401086 8D 45 D0               lea     eax, [ebp+var_30]    **** Move pointer to WNDCLASSEX structure to eax
.text:00401089 50                     push    eax                  **** The only parameter is WNDCLASSEX Structure
.text:0040108A E8 0B 05 00 00         call    j_RegisterClassExA   **** Register the window class     

You'll notice here that I've used IDA to disassemble the program and renamed some things. Like main_win_proc
is really the address 0x00401107. Below this code you'll see the call to CreateWindowExA. This will call
upon the window procedure to handle it's messages for it along with some other things. Let's look at the window
procedure for this main window. 

.text:00401107                       push    ebp                                                                                        
.text:00401108 8B EC                 mov     ebp, esp                                                             
.text:0040110A 83 C4 A8              add     esp, 0FFFFFFA8h                                                      
.text:0040110D 83 7D 0C 02           cmp     [ebp+arg_4], 2                                                       
.text:00401111 75 0C                 jnz     short loc_0_40111F                                                   
.text:00401113 6A 00                 push    0                                                                    
.text:00401115 E8 7A 04 00 00        call    j_PostQuitMessage                                                    
.text:0040111A E9 45 03 00 00        jmp     loc_0_401464
.text:0040111F                                                                                                                            
.text:0040111F                               loc_0_40111F:    ; CODE XREF: main_win_proc+Aj                       
.text:0040111F 83 7D 0C 01           cmp     [ebp+arg_4], 1                                                       
.text:00401123 0F 85 93 02 00 00     jnz     loc_0_4013BC                                                         
.text:00401129 80 3D 28 34 40 00 00  cmp     byte_0_403428, 0                          
.text:00401130 0F 85 79 01 00 00     jnz     loc_0_4012AF                                                         
.text:00401136 6A 00                 push    0                                                                    
.text:00401138 FF 35 F4 33 40 00     push    dword_0_4033F4                                                       
.text:0040113E 6A 04                 push    4                                                                    
.text:00401140 FF 75 08              push    [ebp+arg_0]                                                          
.text:00401143 6A 35                 push    35h                                                                  
.text:00401145 68 1C 02 00 00        push    21Ch                                                                 
.text:0040114A 6A 05                 push    5                                                                    
.text:0040114C 6A 00                 push    0                                                                    
.text:0040114E 68 04 08 00 50        push    50000804h                                                            
.text:00401153 68 8D 30 40 00        push    offset aYouHaveJustGai ; "You have just gained access to a server"...
.text:00401158 68 6A 30 40 00        push    offset aEdit    ; "edit"   **** hmmm... an edit box type                                          
.text:0040115D 6A 00                 push    0                
.text:0040115F E8 FA 03 00 00        call    j_CreateWindowExA  **** Create a window within the outer window

You can see here that the start of the window procedure deals with creating the text in the intro window.
We can tell by the string references all in a row like "You have just gained access to a server" etc...
The interesting thing to note here is that they are all created with a edit box as a type. hmm... Seems like
Santmat made this easy for us, since we know that we need an edit box to grab some user input. Before I expand on 
this lets continue to look at the disassembly and feel what the else the program is doing.
You'll see a section of code below the snippet above that creates the next window which allows either
running the "Nuke the World" or "Exit Program" functions:

.text:004012AF                                                                                                                    
.text:004012AF          loc_0_4012AF:                           ; CODE XREF: main_win_proc+29j              
.text:004012AF 6A 00             push    0                                                            
.text:004012B1 FF 35 F4 33 40 00 push    dword_0_4033F4                                               
.text:004012B7 6A 0A             push    0Ah                                                          
.text:004012B9 FF 75 08          push    [ebp+arg_0]                                                  
.text:004012BC 6A 14             push    14h                                                          
.text:004012BE 68 1C 02 00 00    push    21Ch                                                         
.text:004012C3 6A 05             push    5                                                            
.text:004012C5 6A 78             push    78h                                                          
.text:004012C7 68 04 08 00 50    push    50000804h                                                    
.text:004012CC 68 C4 33 40 00    push    offset aWelcomeToTheTo ; "Welcome to the Top Secret Program!"
.text:004012D1 68 6A 30 40 00    push    offset aEdit    ; "edit"                                     
.text:004012D6 6A 00             push    0                                                            
.text:004012D8 E8 81 02 00 00    call    j_CreateWindowExA   


Continuing on in the window procedure we come to a section of the procedure that deals with WM_COMMAND
messages. We know this because it compares a register with the value 0x111 which we know is defined as WM_COMMAND.

.text:004013BC     loc_0_4013BC:                           ; CODE XREF: main_win_proc+1Cj                                                               
.text:004013BC 81 7D 0C 11 01 00 00 cmp     [ebp+arg_4], 111h      **** Is this a WM_COMMAND message?                                              
.text:004013C3 0F 85 86 00 00 00    jnz     loc_0_40144F                                                         
.text:004013C9 8B 45 10             mov     eax, [ebp+arg_8]       **** If so do this:                                              
.text:004013CC 66 83 F8 01          cmp     ax, 1                                                                
.text:004013D0 75 45                jnz     short loc_0_401417                                                   
.text:004013D2 C1 E8 10             shr     eax, 10h                                                             
.text:004013D5 66 0B C0             or      ax, ax                                                               
.text:004013D8 75 3D                jnz     short loc_0_401417                                                   
.text:004013DA 68 00 02 00 00       push    200h                                                                 
.text:004013DF 68 28 34 40 00       push    offset byte_0_403428 ; buffer for getwindowtext                      
.text:004013E4 FF 35 00 34 40 00    push    dword_0_403400  ; handle of window                                   
.text:004013EA E8 8D 01 00 00       call    j_GetWindowTextA                                                     
.text:004013EF 68 F7 31 40 00       push    offset aHereIsYourMiss ; "Here is your mission, if you choose to "...
.text:004013F4 68 28 34 40 00       push    offset byte_0_403428 ; buffer for getwindowtext                      
.text:004013F9 E8 5A 01 00 00       call    j_lstrcmpA                                                           
.text:004013FE FF 75 08             push    [ebp+arg_0]                                                          
.text:00401401 E8 64 01 00 00       call    j_DestroyWindow                                                      
.text:00401406 6A 0A                push    0Ah                                                                  
.text:00401408 6A 00                push    0                                                                    
.text:0040140A 6A 00                push    0                                                                    
.text:0040140C FF 35 F4 33 40 00    push    dword_0_4033F4                                                       
.text:00401412 E8 53 00 00 00       call    sub_0_40146A      


Wow, this is very strange. You'll notice that the snippet above calls GetWindowTextA. Well the program as
it stands currently can't get text from anywhere because it doesn't have any place to get meaningful text.
Then you'll see it call lstrcmpA with 2 parameters, 1 being the buffer GetWindowTextA placed the text it got,
and the other the string "Here is your mission, if you choose to...". Then the program goes on to destroy the
intro window and call the subroutine at 0x0040146a which will create the Nuke the World window.
If you look at the string references you'll notice that the "Here is your mission, if you choose to" one
is the only one that is a 1 line edit box. All the rest of the edit boxes created in the intro window are
multiple lines long. That and the fact that the window procedure is calling both GetWindowTextA and lstrcmpA
are pretty good hints that this is the right place to get to work.

Let's start to make the intro screen a password entry screen. What we're going to do is make the edit box 
that contains the text "Here is your mission, if you choose to..." to be an edit box that accepts input
from the user in the form of a password. We'll also change the text in the edit box above that to read
"Please enter your password:". The other edit boxes we'll change them so that no text gets displayed in them.
Then, we'll inject some code behind the button "Continue to Program" to check the results of the lstrcmpA
and either display a message box stating the password is invalid or continue on to the program if the password
is OK. Let's Start.

Making the 1 line edit box accept user input:

We see the code looks like this:

.text:00401197 A3 FC 33 40 00    mov     dword_0_4033FC, eax
.text:0040119C 6A 00             push    0
.text:0040119E FF 35 F4 33 40 00 push    dword_0_4033F4
.text:004011A4 6A 06             push    6
.text:004011A6 FF 75 08          push    [ebp+arg_0]
.text:004011A9 6A 14             push    14h
.text:004011AB 68 1C 02 00 00    push    21Ch
.text:004011B0 6A 6E             push    6Eh
.text:004011B2 6A 00             push    0
.text:004011B4 68 04 08 00 50    push    50000804h       ; style
.text:004011B9 68 F7 31 40 00    push    offset aHereIsYourMiss ; "Here is your mission, if you choose to "...
.text:004011BE 68 6A 30 40 00    push    offset aEdit    ; "edit"
.text:004011C3 6A 00             push    0
.text:004011C5 E8 94 03 00 00    call    j_CreateWindowExA

Ok, so you'll notice the window style is 50000804, this breaks down into:
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_MULTILINE

We, get this from looking in winuser.h. Well, this is read only. This is why the edit box is grey and no
user input is accepted. So we must change this and also change it to be of a password type. Once again in winuser.h
we see this #define ES_PASSWORD         0x0020L. We also really don't need the ES_MULTILINE so lets change this
windows style to 50000020. That will give us WS_CHILD | WS_VISIBLE | ES_PASSWORD. Lets also change the window
width from 0x21c to about half of that which is 0x10e. That way the edit box won't span across the entire
window. Notice the 2 changes below:

.text:00401197 A3 FC 33 40 00    mov     dword_0_4033FC, eax     
.text:0040119C 6A 00             push    0                       
.text:0040119E FF 35 F4 33 40 00 push    dword_0_4033F4          
.text:004011A4 6A 06             push    6                       
.text:004011A6 FF 75 08          push    [ebp+arg_0]             
.text:004011A9 6A 14             push    14h                     
.text:004011AB 68 0E 01 00 00    push    10Eh          **** change the width of edit box            
.text:004011B0 6A 6E             push    6Eh                     
.text:004011B2 6A 00             push    0                                                 
.text:004011B4 68 20 00 00 50    push    50000020h     **** change the window style                                  
.text:004011B9 68 F7 31 40 00    push    offset unk_0_4031F7   **** Notice No reference to a string                         
.text:004011BE 68 6A 30 40 00    push    offset aEdit    ; "edit"                          
.text:004011C3 6A 00             push    0                                                 
.text:004011C5 E8 94 03 00 00    call    j_CreateWindowExA         


You'll also notice that I've changed the String reference so that nothing prints in the edit box at the start.
Let's also do that for the other text in the edit boxes by simply changing the first byte of the strings that
start off the edit box to 00. 

Like so:

.data:0040308D 59 6F 75 20 68 61 76 65 20 6A+ 'You have just gained access to a server containing a program'     

to

.data:0040308D 00 6F 75 20 68 61 76 65 20 6A+ 

Notice the first byte changed to a 00. That way the string is simply null terminated from the start.

We'll do this to the following strings:

.data:004031F7 48 65 72 65 20 69 73 20 79 6F+ 'Here is your mission, if you choose to accept it:' 

.data:00403229 59 6F 75 20 6D 75 73 74 20 72+ 'You must reverse the program by making this screen you see n' 

.data:004032D1 59 6F 75 20 63 61 6E 20 64 6F+ 'You can do anything you want, just make sure it is password ' 

and

.data:00403365 53 6F 2C 20 63 6F 6D 65 20 6F+ 'So, come on and save the World. You are the only hope. You h' 

With this string, 

.data:0040315F 4E 6F 77 2C 20 79 6F 75 72 20+ 'Now, your first response would be to delete the file from ex' 

We'll change it to "Please Enter Your Password:" So that this text will appear directly above the edit box
to enter your password.

.data:0040315F 50 6C 65 61 73 65 20 45 6E 74+ 'Please Enter Your Password:'  

Ok at this point you should have an intro window with only the message "Please Enter Your Password:" and,
an edit box to enter your password. When you type in the edit box it should appear as stars (*) because
of the password style we added. 

Now to add the code to do some password checking. As Santmat said in the original intro window, Dr. Evil is
too stupid to know how to crack so we won't concern ourselves with a complex routine to fool crackers.
Also, seeing that Santmat has already included a pretty good protection in the window procedure, we won't 
need to do much. Let's look at that part of the window procedure again:

.text:004013BC      loc_0_4013BC:                           ; CODE XREF: main_win_proc+1Cj                      
.text:004013BC 81 7D 0C 11 01 00 00 cmp     [ebp+arg_4], 111h                                                    
.text:004013C3 0F 85 86 00 00 00    jnz     loc_0_40144F                                                                        
.text:004013C9 8B 45 10             mov     eax, [ebp+arg_8]                                                                               
.text:004013CC 66 83 F8 01          cmp     ax, 1                                                                                          
.text:004013D0 75 45                jnz     short loc_0_401417                                                                             
.text:004013D2 C1 E8 10             shr     eax, 10h                                                                                       
.text:004013D5 66 0B C0             or      ax, ax                                                                                         
.text:004013D8 75 3D                jnz     short loc_0_401417                                                                             
.text:004013DA 68 00 02 00 00       push    200h                                                                                           
.text:004013DF 68 28 34 40 00       push    offset byte_0_403428 ; buffer for getwindowtext                                                
.text:004013E4 FF 35 00 34 40 00    push    dword_0_403400  ; handle of window                                                             
.text:004013EA E8 8D 01 00 00       call    j_GetWindowTextA                                                                               
.text:004013EF 68 F7 31 40 00       push    offset aHereIsYourMiss ; "Here is your mission, if you choose to "...                          
.text:004013F4 68 28 34 40 00       push    offset byte_0_403428 ; buffer for getwindowtext                                                
.text:004013F9 E8 5A 01 00 00       call    j_lstrcmpA                                                                                     
.text:004013FE FF 75 08             push    [ebp+arg_0]                                                                                    
.text:00401401 E8 64 01 00 00       call    j_DestroyWindow                                                                                
.text:00401406 6A 0A                push    0Ah                                                                                            
.text:00401408 6A 00                push    0                                                                    
.text:0040140A 6A 00                push    0                                                                    
.text:0040140C FF 35 F4 33 40 00    push    dword_0_4033F4                                                       
.text:00401412 E8 53 00 00 00       call    sub_0_40146A   

Ok so this procedure is already getting the text typed into the edit box. and comparing it to the string
"Here is your mission, if you choose to..." which we just NULL'ed out above. So let's instead change this 
string to a fixed password string of our own. I'm going to put it at 004034f8 since the string we nulled out 
is at 004034f7 and we need to preserve that byte with the NULL byte we changed above so nothing gets printed
in the edit box. So at 004034f8 I've added the string "DrEvilisCool" to use as the password. 

.data:004031F8 44 72 45 76 69 6C 69 73 43 6F+ aDreviliscool   db 'DrEvilisCool' 

Ok now to add some code right after the lstrcmpA to check if the compare was ok and continue or to pop up a messagebox
and stay where we are waiting for a correct password to be entered. Let's open up ProcDump32 to find
some free space in the program to add our code. Looking at the .text section we've got a raw size of 0x600
and a virtual size of 0x5b2. Therefore we have 0x600 - 0x5b2 = 0x4e = 78 bytes free. That should be plenty since
we're not going to need to add alot of code. Now we're going to need to know where to add it. Taking the
Raw Offset of 0x400 and adding the virtual size of 0x5b2 we get 0x9b2. That's the RVA where we'll add the code
First let's jump to the new code from address 0x004013fe:

.text:004013EA E8 8D 01 00 00    call    j_GetWindowTextA                                     
.text:004013EF 68 F8 31 40 00    push    offset aDreviliscool ; "DrEvilisCool"    **** Our new hardcoded password            
.text:004013F4 68 28 34 40 00    push    offset byte_0_403428                     **** buffer of GetWindowTextA           
.text:004013F9 E8 5A 01 00 00    call    j_lstrcmpA                               **** compare the strings            
.text:004013FE E9 AF 01 00 00****jmp     loc_0_4015B2                             **** Jump to our new code            
.text:004013FE                ; ---------------------------------------------------------------------------
.text:00401403 90 90 90                       db 3 dup(90h)                       **** 3 NOPs to get rid of extra bytes                           
.text:00401406                ; ---------------------------------------------------------------------------
.text:00401406                                                                                             
.text:00401406                loc_0_401406:                           ; CODE XREF: .text:004015D8j        
.text:00401406 6A 0A             push    0Ah                                      **** return here is password OK

Now looking at the code I added:

.text:004015B2       loc_0_4015B2:    ; CODE XREF: sub_0_401107+2F7j                 
.text:004015B2 85 C0             test    eax, eax                        **** Test the result of lstrcmpA                     
.text:004015B4 74 19             jz      short loc_0_4015CF              **** If OK jump down a bit
.text:004015B6 6A 00             push    0                                                    
.text:004015B8 68 1D 30 40 00    push    offset aTopSecret ; "Top Secret"                     
.text:004015BD 68 8E 30 40 00    push    offset aPasswordIsInco ; "Password is incorrect"     
.text:004015C2 6A 00             push    0                                                    
.text:004015C4 FF 15 30 20 40 00 call    ds:MessageBoxA  ; MessageBoxA:  **** Pop up message box if password wrong                     
.text:004015CA E9 95 FE FF FF****jmp     loc_0_401464                    **** Jump back to window procedure                      
.text:004015CF                               ; ---------------------------------------------------------------------------
.text:004015CF                                                                                                            
.text:004015CF       loc_0_4015CF:    ; CODE XREF: .text:004015B4j        
.text:004015CF FF 75 08          push    dword ptr [ebp+8]               **** restore the 2 instructions we blew away                     
.text:004015D2 FF 15 18 20 40 00 call    ds:DestroyWindow ; DestroyWindow:  **** from jumping here to our new code                  
.text:004015D8 E9 29 FE FF FF****jmp     loc_0_401406                    **** and return to where we came from

You'll notice on failure we jump to a different place in the window procedure as shown below:

.text:00401464                               loc_0_401464:                           ; CODE XREF: sub_0_401107+13j                     
.text:00401464 33 C0                              ; sub_0_401107+1A3j ...      
.text:00401464            xor     eax, eax    **** return a 0 in eax                                  
.text:00401466 C9         leave                                                 
.text:00401467 C2 10 00   retn    10h         **** and return from window procedure                                 
.text:00401467            sub_0_401107    endp   

This will return from the window procedure returning a 0 which means the window procedure didn't handle the
message sent. Which should be ok. If you run the program again you'll notice that all is OK and the password 
intro screen stays up waiting for a correct password to be entered. You'll also notice I've used the notation
of stars (*) between the opcodes and the mnemonic for any jumps that I used the SoftIce  'a' (assemble)
command to get the correct opcodes for. This is the easiest way when the jumps are long.

That's all there is to it. You should have now satisfied all requirements for this reverseme. :)

***************************
* Final Thoughts
***************************

Well another good reversing session. I really love this stuff. You learn so much about how programs actually
operate and get a better understanding of the workings of the OS. Hope you learned something from this essay.
Shouts out to Santmat, Volatility, alpine, Muad`Dib-, Neural Noise, and all the other Immortal Descendants. 
And oh ya, anyone else I might have missed. Quite a few I suppose. I've attached my patched version of the 
reverseme executable for you to see the end result. Remember the password is "DrEvilisCool" without the
quotes of course.

You can contact me via email at amante_4@yahoo.com or on EFNet on #ImmortalDescendants.

Later,
Amante4