- Understand how debugger saves debugger information
- Know how to use binary editor to examine file contents
- Trouble shooting and fix issues of debuggers when necessary
- Assembly Language.
- Computer Security.
- Programming Language Principles.
- Operating Systems.
In Tutorial 11, we have shown you the trick played by Max++ to load its own malicious executable using the "corpse" of another DLL called "lz32.dll". The basic idea is to cut in the LdrLoadDll call and reset the base address and other relevant information of the module, without loading the executable of lz32.dll from its file (while the malicious PE has been copied into that memory area). This is achieved by setting up a hardware breakpoint inside LdrLoadDll and the "surgery" is performed by the vectored exception handler configured by Max++ in advance.
Now, one side-effect of Max++'s "surgery" on Lz32.dll is that, we are no longer able to make comments in that particular area of "lz32.dll". When you try to place comments on the code (starting from 0x003C24FB, the starting addr of "lz32.dll"), they will not be properly saved by IMM. The next time you load Max++ in IMM, all comments related to lz32 will be lost! The reason is that Max++'s surgery is incomplete -- it did not fix the entire kernel structure of lz32.dll and the mal-formated data structure fails the internal analysis of IMM. When IMM tries to create a UDD file (a file records the debugging information for each module in a binary executable), it fails.
Clearly, there are two ways to fix this:
(1) make sure that all kernel data related to lz32.dll are properly reset [which can be a huge task], and
(2) debug into IMM and tweak its control flow so that it can work correctly given the malformed data.
We will take approach 2 and show you how to debug the IMM debugger and fix issues on the spot.
2. Lab Configuration
2.1 Software You need
You need the following software tools. They can be easily downloaded from Internet: (1) HxD binary editor and (2) NotePad++.
2.2 Lab Configuration
You can either continue from Tutorial 10, or follow the instructions below to set up the lab. Refer to Tutorial 1 and Tutorial 4 for setting up VBOX instances and WinDbg. We now proceed to the steps that we need for this tutorial:
(0) -- IT IS IMPORTANT TO TAKE A SNAPSHOT after you've installed HxD and NotePad. At this moment, the system is still clean. After step (3), the system will be infected, later, whenever you restart the system, you have to restore the snapshot to start from a clean system!!!
(0.5) restore the snapshot as discussed in step (0)
(1) In IMM, clear all hardware breakpoints and software breakpoints.
(2) Go to 0x4012DC and set a hardware breakpoint there (the instruction at 0x4012DC should be CALL 0x413652). Press F9 to run to 0x4012DC.
This is the point right before the tricks introduced in Tutorial 11 (which sets up hardware breakpoint inside zwMapViewSection and then calls LdrLoadDLL).
At this point, you might want to straighten out the display of the assembly code of IMM (if there is a large gibberish section of DB instructions). Highlight and select one or two pages of DB instructions, right click and then select Analysis -> During Next Analysis Treat Selection As -> Command, and then right click and select Analysis -> Code Analysis.
(3) Now at 0x401419 (instruction is MOV [ESP-2E8]: ESI) set a SOFTWARE BREAKPOINT (by pressing F2), and then press Shift+F9 (at least twice) until you hit 0x401419.
Shift+F9 is to RUN (but passing all exceptions to user code). This way we allow the vectored exception handler set by Max++ to be effective. Hence, the malicious code will be layed in the "body" of lz32.dll. Notice that when you hit the 0x401419, the code of the fake lz32.dll has already been executed (which infects a number of driver files and modifies system registry etc.). We will introduce the analysis of this code in future tutorials. At this moment, we are interested in making comments working in IMM.
(4) At this point, if you click IMM View->Executable Modules (as shown in Figure 1, the first row), you can find a new module is loaded for "lz32.dll". Its base address is 0x3C0000 (could vary depending on the run-time behavior of the system). Using the trick introduced in Tutorial 9, we can find the entry point of the module to be 0x3C24FB.
|Figure 1. New "lz32.dll" Module|
3. Introduction of UDD Format
The missing comments problem is caused by IMM. When the module information structure is mal-formed, IMM will not behave correctly when analyzing its code section, and hence will not create a corresponding UDD file for lz32.dll (that's the reason all your comments are lost). IMM creates UDD files to record the debugging information (e.g., comments created by users). This section introduces some background information about the UDD file format.
|Figure 2. UDD Files|
There are several simple fact about UDD files:
(1) All UDD files are located in the Immunity Debugger folder (e.g., c:\Program files\Imm Inc\Immunity Debugger), as shown in Figure 2.
(2) For each module that is analyzed by IMM (i.e., its code is shown at least once in the IMM code pane), IMM will create a corresponding UDD file. For example, look at Figure 2 (to analyze Max++, we once stepped into ntdll, and there is a corresponding ntdll.udd). The ".bak" files are the temporary UDD files.
|Figure 3. Snapshot of Max++_Downloader.udd (in Notepad)|
A UDD file is a collection of records while each record occupies a line. Each record begins with some binary data, and then continued with the corresponding comment by the user. For example, in Figure 3, we displays a fragment of the Max++ download.udd. You can see that the file (opened by Notepad++) corresponds to the comments in the IMM debugger window.
|Figure 4. Same UDD file in HxD binary editor|
So far, there is no complete documentation on UDD format, however, it's easy to infer the meaning of the binary data at the beginning of each record. Look at the "ENTRY PC!" comment in Figure 4 and its subsequent comment "Standard stack protection for function call".
The binary data before "ENTRY PC!" is
0x 55 73 36 13 00 00 00 C8 3B 01 00 .... 00 0A
Clearly the tag "55 73 36" indicates the type of the record (a user comment) - this is the same for the next comment "Standard stack protection". The next 4 bytes "13 00 00 00" indicates that the record length is 0x13 bytes, and then "C8 3B 01 00" indicate its relative location (beginning from the module base address) - you can verify this in Figure 3 (the location of the comment is 0x413BC8 - note the reversed byte sequence of integers). Clearly "00 0A" is used to end the record.
It is straightforward to infer how IMM works with a UDD file. For each module, IMM gets its base address and for each user comment, it calculates its offset and place the record in the UDD file. Clearly, if IMM's analysis fails somehow, the UDD file will not be created and thus all user comments will be lost.
4. Debug the Debugger
Now we show the tricks to debug into the IMM debugger and fix the issues. Our purpose is to redirect the control flow of IMM so that it would work normal. Follow the instructions below:
(1) Start IMM, and then open the executable of IMM (located in c:\Program Files\Imm Inc\Immunity Debugger). Press F9 to run it. In this case, we have two IMM instances, we call the first one IMM1 and the second one IMM2.
|Figure 5. Set Breakpoint on IMM|
(3) Now in IMM1, View -> Executable Modules and then right click on IMM (the first one) and then right click and select View -> Names. Basically, this shows the list of exported functions. You might immediately notice that there is something that we are interested in: the function Analyzecode at 0x00411020(see Figure 5).
|Figure 6. Python Script to Trigger Analyzecode|
(4) We would like to trigger the Analyzecode() of IMM2 and then analyze its logic in IMM1. In IMM2, repeat Steps (1) to (3) in Section 2.2 until you hit 0x401419.
(5) Now in IMM2, click to open the python script window (it's the second button in the toolbar, right after the "open file" button). Type the first two commands: mod = getModule('ntdll.dll'); mod.Analyse() (see Figure 6). You will then hit the breakpoint in IMM1!
Step through the instructions in IMM1 and make a good memory of it. When the function Analyzecode() returns, press F9 to let it run and you will go back to IMM2.
Now do the same thing for lz32.dll. Did you notice there is something different?
5. Challenge of the Day
(1) The control flow of two analyzecode() sessions depart from a CMP EDX, 7 instruction. Find out where it is.
(2) The value contained in EDX is an important attribute of a DLL module. Can you find out its meaning? [hint: codeSize. Prove it]
(3) Can you modify the control flow so that analyzecode() is successfully completed? After that, you can repeat steps (4) and (5) in section 2.2 and make comments. In the c:\program...\immunity debugger\ folder, you can verify that the lz32.udd file is created and your comments will be recorded.