The First Breakpoint
If you are not seeing the label _LdrpInitialize@12 in the disassembly listing for LdrInitializeThunk I advise you to stop and try again after the glitches in your debug symbol setup have been worked out. Experimentation with PEBrowse Interactive's "Debug Symbols Location" and/or examining your _NT_SYMBOL_PATH environment variable might help. If you don't address the missing symbol issue, you will miss out on a lot of the fun that will follow.
0x77F75711: JMP _LdrpInitialize@12 ; (0x77F58086); (*-0x1D68B) [for SP2:] 0x7C901188: JMP _LdrpInitialize@12 ; (0x7C918E47); (*+0x17CBF)
Some of you familiar with other articles of mine might be anticipating (or dreading) another reverse engineering exercise at this juncture. (See the aforementioned JIT Thunk Layer article or try "Reversing HDSpoof: A Tutorial" at www.openrce.org/.) This is bound to disappoint but my intention in this tutorial is to teach you about my debugger while highlighting some of the interesting events you might see while stepping through our test program. It is not to explain what you will be seeing but how to get to what you are seeing. Hopefully, after this discourse you will be eager to use my debugger in order to explore further some of these interesting, yet glossed over areas.
Turning our attention now to the neglected Debug main menu item we see that all of the "normal" stepping commands are present and some even have accelerator keys. My audience might contain some that have not been weaned on Microsoft's products and are unfamiliar with F5 meaning Go; fear not, you can change this shortcut (and a few others) to F9 in the, you guessed it(!), Tools/Configure/Environment tab sheet with the "Borland-style short-cuts" checkbox. Pressing F10 (or F8) several times we will see the disassembly display changing slightly and the register contents changing as well (the user-configurable register update color defaults to red.) Continue pressing F10 until you reach the statement:
0x77F580E4: CALL _LdrpInitializeExecutionOptions@8; (0x77F5BC59) [for SP2:] 0x7C922D28: CALL _LdrpInitializeExecutionOptions@8; (0x7C922D56)
Pressing F11 (I will be using the Microsoft shortcuts from now on) would Debug/Step into the routine _LdrpInitializeExecutionOptions but we want to avoid the detour this time around. Instead, focus your attention on the upcoming call to RtlImageDirectoryEntryToData. For those of us with some background in the wacky worlds of PE files and NTDLL, we will easily recognize that here is a call to determine the existence or not of a certain "directory entry" in the main executable's optional header. How do we know that?
0x77F580EC: LEA EAX,DWORD PTR [EBP-0x38] 0x77F580EF: PUSH EAX 0x77F580F0: PUSH 0xE 0x77F580F2: PUSH 0x1 0x77F580F4: PUSH DWORD PTR [ESI+0x8] 0x77F580F7: CALL _RtlImageDirectoryEntryToData@16; (0x77F518D0) 0x77F580FC: CMP EAX,EBX 0x77F580FE: JNE 0x77F79CF1 ; (*+0x21BF3) [for SP2:] 0x7C922D30: LEA EAX,DWORD PTR [EBP-0x24] 0x7C922D33: PUSH EAX 0x7C922D34: PUSH 0xE 0x7C922D36: PUSH 0x1 0x7C922D38: PUSH DWORD PTR [ESI+0x8] 0x7C922D3B: CALL _RtlImageDirectoryEntryToData@16; (0x7C910856) 0x7C922D40: CMP EAX,EBX 0x7C922D42: JE 0x7C918D9A ; (*-0x9FA8) 0x7C922D48: MOV BYTE PTR [EBP-0x2C],0x1 0x7C922D4C: JMP 0x7C918D9A ; (*-0x9FB2)
The first PUSH statement is adding an output area to the parameter list; the next is pushing the hard-coded value of 0xE as the next argument, i.e., which image directory entry we are looking for. After the hard-coded 0x1 is added to the list, we see the final push of an offset from ESI before the call is made. Single-step to the call statement and examine what the last parameter's value will be. Activate the register window, and double-click (or Edit/Dump) the ESI line. The result of this will be the creation of a new window display, a memory dump window. It should be easily evident that ESI+0x8 contains the HModule for our debugee, Wilderland.EXE. Actually, we are now dumping the Process Environment Block, the PEB (ESI contains the PEB address), and locating the third DWORD, the ImageBase field. Now, time to decipher that 0xE value. Select the node labeled "Wilderland.exe" in the Index and expand it. If you do not see a node containing the text, "Optional Header", select View/Reload Symbols for Wilderland.exe, and try again. With the Optional Header node selected, press View/Structure from the main menu or the context-sensitive popup menu -- a new structure display window appears! Scroll the display down a bit: 0xE is equivalent to 14 in base ten which means we are looking for the IMAGE_COR20_HEADER in the executable. Stepping over the call to RtlImageDirectoryEntryToData we now see that EAX contains 0x00402008 (the ImageBase + the VirtualAddress of the directory). Since EBX was set to zero, the following comparison and jump statement will send the code off to set a local variable to 1. Try it now and see for yourself. Translating: the code in LdrInitializeThunk is checking to see if the program is a managed Microsoft .NET assembly or not and storing this knowledge in a local variable.
| | 1st page | next page |