Calling The DLL Functions

In this section, we will be modifying notepad's ASM code to call our NotePlug DLL function, as well as a NotePlugCmd function which will be written in the next section.

Tools Used

[~] OllyDbg - Debugger/disassembler
[~] LordPE - For modifying notepad's import table

Calling NotePlug

Add the NotePlug and NotePadCmd functions to notepad's import table using LordPE and be sure to note their addresses (in my case 0101409E and 010140A2). Now we need to find a place to call our function from, but it must be called after the window has been created. Run notepad in Olly, press F12 to pause and single step (F8) until you return from the User32 functions and you will be in a loop at 010029B3:

This is the standard GetMessage loop used for pretty much all Win32 programs which translates and dispatches window messages to the WndProc function. Notice also that the TranslateAccelleratorW function is passed the main window handle which is stored at 01009830. If you search for CreateWindowExW and look at the instance that creates the window with the 'Notepad' class (the main window), you will see that the window handle is also stored at offset 100A4A4:

Hijacking the execution flow to our imported function just before the loop at 010029B3 would be ideal, because notepad's window has been sucessfully created at that point and we are free to modify the menu. Note immediately above the loop there is an unconditional jump directly to the GetMessage call ('CALL EDI' at 01002A19 is a call to GetMessage):

This is ideal because the jump is taken once, immediately before entering the GetMessage loop. Unfortunately, it is a JMP SHORT instruction, and we will need to use a JMP LONG to get to our code which will overwrite the first instruction of the GetMessage loop (CMP DWORD PTR SS:[EBP-1C],50). We will need to add that overwritten instruction to our new code after having called NotePlug, but will also need to modify the jump at the bottom of the loop (JNZ SHORT 010029B3) because it will be pointing to this first instruction which will be overwritten with our new code. This also is a JMP SHORT instruction, so jumping to our replacement code will create the same problem as before of overwriting another instruction. We will have to add two jumps immediately after GetMessageW is moved into EDI (010029AF) and modify the loop's bottom jump to point to our second jump which in turn points to our new code. This also requires overwriting the MOV EBX,EAX instruction at 010029AF, so we will also have to add that instruction to  our new code before returning the execution flow to its original place. Below is the new code to be added, the differences between the original and modified GetMessage loop, and an execution flow chart to better visualize the new execution flow:

Add new code at 0100874A:

Original GetMessage loop code:

Modified GetMessage loop code (added jumps at 010029AF and 010029B4 and modified conditional jump at 01002A1D):

Execution flow chart:

010029AF   JMP notepad6.0100874A <---Used to jump directly to 01002A12
		|
		|-----> 0100874A   PUSHAD
			0100874B   PUSHFD
			0100874C   PUSH DWORD PTR DS:[1009830]    <---- Push the main window handle
			01008752   CALL DWORD PTR DS:[01001409E]  <---- Call our function
			01008758   POP EAX
			01008759   POPFD
			0100875A   POPAD
			0100875B   MOV EBX,EAX  <---- Restore this instruction which we wrote over
			0100875D   JMP notepad6.01002A12  <---- Jump back to the original code at 01002A12
				    |
				    |------------------------------------------------------------
010029B4   JMP notepad6.01008762								|
	    |											|		
	    |----->	01008762   CMP DWORD PTR SS:[EBP-1C],50 -----				|
			01008766   JNZ notepad6.010029CC	      |	Restore original code	|
			0100876C   JMP notepad6.010029B9        -----	      			|
												|
												|		
010029B9   PUSH ESI                                 						|
010029BA   PUSH ESI                                 						|	
010029BB   PUSH 8001                                						|
010029C0   PUSH DWORD PTR DS:[1009830]              						|
010029C6   CALL DWORD PTR DS:[<&USER32.PostMessageW>						|
010029CC   MOV EAX,DWORD PTR DS:[100983C]							|
010029D1   CMP EAX,ESI										|
010029D3   JE SHORT notepad6.010029E4								|
010029D5   LEA ECX,DWORD PTR SS:[EBP-20]							|
010029D8   PUSH ECX                                 						|
010029D9   PUSH EAX                                 						|
010029DA   CALL DWORD PTR DS:[<&USER32.IsDialogMess>						|
010029E0   TEST EAX,EAX										|
010029E2   JNZ SHORT notepad6.01002A12								|
010029E4   LEA EAX,DWORD PTR SS:[EBP-20]							|
010029E7   PUSH EAX                                 						|
010029E8   PUSH DWORD PTR DS:[100A6D8]              						|
010029EE   PUSH DWORD PTR DS:[1009830]              						|
010029F4   CALL DWORD PTR DS:[<&USER32.TranslateAcc>						|
010029FA   TEST EAX,EAX										|
010029FC   JNZ SHORT notepad6.01002A12								|
010029FE   LEA EAX,DWORD PTR SS:[EBP-20]							|
01002A01   PUSH EAX                                 						|
01002A02   CALL DWORD PTR DS:[<&USER32.TranslateMes>						|
01002A08   LEA EAX,DWORD PTR SS:[EBP-20]							|
01002A0B   PUSH EAX                                 						|
01002A0C   CALL DWORD PTR DS:[<&USER32.DispatchMess>						|
01002A12   PUSH ESI	<-----------------------------------------------------------------------|
01002A13   PUSH ESI				
01002A14   LEA EAX,DWORD PTR SS:[EBP-20]
01002A17   PUSH ESI
01002A18   PUSH EAX
01002A19   CALL EDI
01002A1B   TEST EAX,EAX
01002A1D   JNZ SHORT notepad6.010029B4 -----------> Jump back up to 010029B4 instead of 010029B3

This takes care of calling NotePlug when notepad first loads, and we still maintain the original code for the GetMessage loop. Next we need to intercept all WM_COMMAND messages sent to the program and create a function which will allow each plugin to process the message.

Calling NotePadCmd

The function which will be be controlling WM_COMMAND messages for notepad's plugins will be called NotePadCmd. We have not written the code for this function yet, but I think it is easier if you understand the assembly code first.

In windows programs, all messages are processed by a WndProc function, so in order to catch all WM_COMMAND messsages, let's find notepad's WndProc function. Do a search in Olly for 'SHR EAX,10'. This should land you in the middle of the main case-switch statement in the WinProc function; the case that pertains to WM_COMMAND is a few instructions below:

If it is a WM_COMMAND message, the program jumps to 0100391B where it pushes three arguments and calls a function before returning to the case-switch loop:

0100391B  PUSH EDI                       ; /Arg3 - Unknown value
0100391C  PUSH DWORD PTR SS:[EBP+10]     ; |Arg2 - ID number of menu option
0100391F  PUSH DWORD PTR SS:[EBP+8]      ; |Arg1 - Handle to notepad's main window
01003922  CALL notepad.01002B87

Since we need to know the ID number and possibly the window handle (some plugins may require the window handle, so we will pass it on just in case), replace the 'CALL 01002B87' with 'JMP 01008772', and let's call our NotePadCmd function. At address 01008772, add the following code:

01008772   PUSHAD                      <----- Save the register values
01008773   PUSHFD
01008774   PUSH EDI                    <----- Push the three arguments onto the stack for our function
01008775   PUSH DWORD PTR SS:[EBP+10]  
01008778   PUSH DWORD PTR SS:[EBP+8] 
0100877B   CALL DWORD PTR DS:[010140A2]<---- Call our function
01008781   TEST EAX,EAX                <---- Check the return value
01008783   JNZ notepad9.010034BD       <---- If the return value is not zero, jump back into the case-switch loop
01008789   POP EAX                     <---- If the return value is zero, restore the stack and registers
0100878A   POP EAX                                  
0100878B   POP EAX                                  
0100878C   POPFD                                    
0100878D   POPAD                                    
0100878E   CALL notepad9.01002B87      <---- Call the original function
01008793   JMP notepad9.01003927       <---- Jump back to notepad's original code

Note that we test the return value to determine if notepad should continue processing the WM_COMMAND message, or if it should return to the case-switch loop. Remember that this was one of the four original objectives; we want each plugin to be able to control whether or not notepad and the remaining plugins will continue to process the message.

Conclusion

We now have calls to both NotePlug and NotePadCmd, and the assembly coding is complete at this point. All that remains is to complete the NotePlug and NotePadCmd functions, and create a standard structure for plugin DLLs.

Copyright ©2006 craigheffner.com