Pages

Tuesday, January 31, 2012

Malware Analysis Tutorial 14: Retrieve Self-Decoding Key

Learning Goals:
  1. Understand PE manifest
  2. Practice analyzing function call parameters and stack
Applicable to:
  1. Operating Systems
  2. Assembly Language
1. Introduction
In this tutorial, we show you how Max++ retrieves an "instance specific" decoding key from the PE manifest. By planting a decoding key into the PE manifest, the malware can first distinguish a copy from the other so that it can trace which copy sits on which machine (thus tagging an ID to each victim and can even potentially trace back to malware analyst if the copy is being debugged). One more popular use of it would be making each copy of the binary executable significantly different from each other, thus making a much harder job for virus detectors to define virus signatures.

We will also practice how to analyze the parameters of a function call and the use of MSDN documentation and other relevant online resources to reverse engineer binary code.

2. Lab Configuration
(0) Start WinXP image in DEBUGGED mode. Now in your host system, start a windows command window and CD to "c:\Program Files\Debugging Tools for Windows (x86)" (where WinDBG is installed). Type "windbg -b -k com:pipe,port=\\.\pipe\com_12" (check the com port number in your VBox instance set up). When WinDbg initiates, types "g" (go) twice to let it continue.

(1) Now launch IMM in the WinXP instance, clear all breakpoints and hardware breakpoints in IMM (see View->Breakpoints and View->Hardware Breakpoints).

(2) Go to 0x4012DC and set a hardware breakpoint there. (why not software bp? Because that region will be self-extracted and overwritten and the software BP will be lost). Pay special attention that once you go to 0x4012DC, directly right click on the line to set hardware BP (currently it's gibberish code).

(3) PressF9 several times run to 0x4012DC. You will encounter several breakpoints before 0x4012DC. If you pay attention, they are actually caused by the int 2d tricks (explained in Tutorial 3 and 4, and 5). Simply ignore then and continue (using F9) until you hit 0x4012DC.

Figure 1 shows the code that should be able to see. As you can see, this is right before the call of RtlAddVectoredException, where hardware BP is set to break the LdrLoadDll call (see Tutorial 11 for details). At this point, the code at 0x3C24FB has not been extracted. If you go to 0x3C24FB at this moment, IMM will complain that this address is not accessible.
Figure 1: code at 0x4012DC
(4) Now scroll down about 2 pages and set a SOFTWARE BREAKPOINT at 0x401417. This is right after the call of LdrLoadDll("lz32.dll"), where Max++ finishes the loading of lz32.dll. Then hit SHIFT+F9 several times until you reach 0x401417 (you will hit 0x7C90D500 twice, this is somwhere inside ntdll.zwMapViewSection which is being called by LdrLoadDll).



Figure 2: code at 0x401407

(6) Now we will set a breakpoint at 0x3C24FB.  Goto 0x3C24FB and set a SOFTWARE BREAKPOINT there. Press SHIFT+F9 to run to 0x3C24FB.

(Figure 3 shows the code that you should be able to see. The first instruction at 0x3C24FB should be CMP DWORD PTR SS:[ESP+8], -2. You will notice that [ESP+8] is currently -2, and the execution will reach the instruction CALL 0x003C23DB. Press F7 to step into function 0x003C23DB.


Figure 3: code at 0x3C24FB

3. Background Introduction: Function 0x003C23DB
The function body of 0x003C23DB is shown in Figure 4. If you look at the comments of the code pane, you might notice that this function is doing a lot of malicious actions. It first retrieve a self-decoding key from the PE manifest. Then it injects a thread into a currently running process and sets a timer, which kills the Max++.exe 10 seconds after the process is terminated. It then infects a number of important system libraries such as ntdll.dll and also randomly picks a system driver to infect. It is not possible to cover all the malicious actions of function 0x003C23DB in one tutorial.  We concentrate on the function call at 0x3C23FE (reads decoding key)
Figure 4: The Malicious Actions

4. RtlAdjustPrivilege at 0x3C23F3.
Let's first study the instruction "CALL DS:[3D10E8]" at 0x3C23F3 (as shown in Figure 4 and Figure 5). Note that before the call of the entry function by Max++ itself, it has properly set up the DS register. So when the execution comes to 0x003C23F3, the value of DS + 0X3D10E8 is the entry address of the ntdll.RtlAdjustPrivilege function. IMM is smart enough to show the hint in the comments area, which is very nice (see Figure 2). Our job is to try to figure out, what is the semantics of all the parameters of this call. Doing a simple Google search of RtlAdjustPrivilege (again, please do the search in the VBox instance to avoid potential drive-by-download attack) leads us to the documentation such as [1] and [2]. We soon learn that the RtlAdjustPrivilege function has four parameters:
(1)ULONG Privilege
(2) BOOLEAN Enable
(3) BOOLEAN CurrentThread
(4) OUT Boolean Enabled

Then the question is: what are the corresponding values in the stack?

Now look at the stack contents in Figure 5. You can immediately infer that 0x14 is the Privilege, Enable value is 0x1 (true), CurrentThread is 0x0, and ENABLED value is 0x12D623 (why? because the output value will be stored at that address -- to verify this, read the source code at line 00174 of [2] ).

Challenge 1: What does the value 0 mean for CurrentThread? [hint: you have to read the source code in  [2])

Now the most intriguing  part to us is: what is the semantics of 0x14 for Privilege? We have to blame the macro definition of constants of the C language (what if the WINNT designers have used enumerated types, that makes our job much easier!) If you read [1] carefully, you will notice that it's the SeDebug privilege. [note: the decimal value of 0x14 is 20].

Why does Max++ need the SeDebug privilege? If you read the explanation in [1], you will notice that once a process has SeDebug, it is able to open any other process in the system, which is perfect for accomplishing the jobs like injecting another thread into a currently running process (see Figure 1 in Section 3).





Figure 5: RtlAdjustPrivilege

Section 5. Analysis of the Function call at 0x3C23FE (CALL lz32.003C1129)
Now, let's delve into the function call at 0x3C23FE (see Figure 4). F7 to step into it,
Figure 7 shows the function body of 0x003C1129. It gives you the general idea of what this function is doing.
There are several important calls: at 0x003C1131, it calls getModuleHandleW to get the handle of the current process, and then at 0x3C1145 it calls LdrFindResource_U to find some resources related to this process, and then at 0x3C1159, it calls LdrAccessResource. At 0x003C116B it calls strstr (to search for a string "<description>"). Then it takes out the decode-key "11001800" and saves it to somewhere in the stack at 0x003C1185.


Figure 7: Function body of 0x003C1129

Challenge 2.Explain the semantics of the parameters of all system calls in the function body (e.g., getModuleHandleW and LdrAccessResource).

Challenge 3. Explain how is the decoding key "11001800" taken out?

Challenge 4***. Can you find out how is "11001800" used in the later code of Max++? (hint: use Data breakpoint).



References
1. "Topic: Tip: Easy way to enable privileges", available at http://forum.sysinternals.com/tip-easy-way-to-enable-privileges_topic15745.html
2. ReactOS Doxygen, "RtlAdjustPrivilege source code", available at http://doxygen.reactos.org/d9/db7/lib_2rtl_2security_8c_a1cf697d376343212dfa89ac97b0c30d8.html

Thursday, January 26, 2012

Malware Analysis Tutorial 13: Tracing DLL Entry Point

Learning Goals:
  1. Understand C calling convention
  2. Practice reverse engineering
Applicable to:
  1. Operating Systems
  2. Assembly Language
1. Introduction
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".Beginning from this tutorial, we will analyze the functionality of the malicious DLL. In the following, we use "lz32.dll" to refer to this malicious code starting at 0x003C24FB. (In your VBox instance, this entry address might vary. Check Tutorial 11 for how to find out the correct entry address of lz32.dll).

Today, we will discuss some basic background information related to DLL entry point and analyze the first part of lz32.dll (it's not the real "lz32.dll", but the malicious code of Max++ planted into it).

2. Lab Configuration
(1) clear all breakpoints and hardware breakpoints in IMM (see View->Breakpoints and View->Hardware Breakpoints).
(2) Go to 0x4012DC and set a hardware breakpoint there. (why not software bp? Because that region will be self-extracted and overwritten and the software BP will be lost). Pay special attention that once you go to 0x4012DC, directly right click on the line to set hardware BP (currently it's gibberish code).
(3) Press SHIFT+F9 to run to 0x4012DC. Figure 1 shows the code that should be able to see. As you can see, this is right before the call of RtlAddVectoredException, where hardware BP is set to break the LdrLoadDll call (see Tutorial 11 for details). At this point, the code at 0x3C24FB has not been extracted. If you go to 0x3C24FB at this moment, IMM will complain that this address is not accessible.
Figure 1: code at 0x4012DC
(4) Now scroll down about 2 pages and set a SOFTWARE BREAKPOINT at 0x401417. This is right after the call of LdrLoadDll("lz32.dll"), where Max++ finishes the loading of lz32.dll.



Figure 2: code at 0x401407

(6) Now we will set a breakpoint at 0x3C24FB. Follow the instructions below:
Press SHIFT+F9 several times, until you hit 0x7C90D500 (this is somwhere inside ntdll.zwMapViewSection which is being called by LdrLoadDll). Goto 0x3C24FB and set a SOFTWARE BREAKPOINT there. (You will see a warning which says your BP is out of the range. This is because the malware author did not do a good job at resetting the binary PE information (executable code section size messed up - see Tutorial 12 for details). It should be fine, just click ok.

(7) If you hit SHIFT+F9 (probably twice), you will hit 0x3C24FB. If you hit 0x401417 directly, something wrong is with IMM (strangely, I cannot explain). You have to RESTART (Debug->Restart), and repeat steps (1) to (6) [yes, clear all BP and hardBPs). The current sequence should be you hit 0x7C90D500 twice, and then hit 0x3C24FB. This is because the LdrLoadDll will try to call the entry point of the DLL.

(Figure 3 shows the code that you should be able to see. The first instruction at 0x3C24FB should be CMP DWORD PTR SS:[ESP+8], -2. If you execute several steps, you might notice that it soon returns, because the value at [ESP+8] is 1.


Figure 3: code at 0x3C24FB

(9) Shift +F9 again, you will be hitting 0x401417,  and then SHIFT+F9 again, you will be hitting 0x3C24FB again! You might notice that now [ESP+8] has value -2 and if you F7, you will trace into a lot of details of the malicious logic.

Up to this point, you are doing it right. If there is anything messed up, you have to restore the snapshot because Max++ automatically removes its binary executable from the disk drive so that you will not be able to find it again.


2. Background Information of DLL Entry

DLLs, like .exe files, can have an entry point. This entry function will be executed when the DLL is loaded by system calls such as LdrLoadDLL(). MSDN has tons of excellent articles on it and you can read [1] for details. The following sample declaration is from [1], an DLL entry function takes three parameters, see below:

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL, // handle to DLL module 
  DWORD fdwReason, // reason for calling function 
  LPVOID lpReserved ) // reserved {...}

Challenge 1: Note the code at 0x3C24FB (Figure 3) is checking the value of [ESP+8]. Which parameter is stored at ESP+8?

We are particularly interested in the fwdReason. Where is it defined? Reading [1] you can find that there are some macros defined for fwdReason such as DLL_PROCESS_ATTACH (when a process first attaches the DLL), DLL_THREAD_ATTACH (when the thread of a process has it attached) etc. [1] does not provide information on the real integer values of these macros, but a simple google search of "#define DLL_PROCESS_ATTACH" yields the values [again! do the google search in your VM. Many sites hosting MS sources can be harmful!]. These values range from 1 to 8. For example, value 1 denotes DLL_PROCESS_ATTACH. This is the value of [ESP+8] when 0x3C24FB is hit the first time (which is called by LdrLoadDLL).

3. Analysis of Max++

If you pay attention to the first couple of instructions at 0x3C24FB, one natural question is:
Challenge 2: Why is the malware compare [ESP+8] with -2? What is the motivation for doing this?

The motivation is that, when it's a legal invocation (e.g., placed by LdrLoadDLL), the code at 0x3C24FB will return immediately (without doing any harm). Why? because, recall in  Tutorial 12, Max++ cut in LoadLdrDll and actually LoadLdrDll did not finish gracefully (some kernel structure information is not set up correctly). These information has be be properly set up, because the code can NOT call external functions (e.g., those provided by ntdll). Max++ does have to set up all these information by itself, and manually call the entry function at 0x3C24FB. Well, before calling it, it sets up the second parameter (fwdReason) to -2 (which is a value that will NEVER be used by a normal call of DLL entry point), so that the code knows that it's the call from Max++.

Last challenge of the day:
Challenge 3: Can you find out which instruction calls 0x3C24FB the second time (which provides -2 for fwdReason)? [hint: check out the stack contents] Look at how 0x3C24FB is called. Can a static analysis tool find out that 0x3C24FB is called by the Max++ code?

References
1. Microsoft, "Dynamic-Link Library Entry-Point Function",
available at http://msdn.microsoft.com/en-us/library/windows/desktop/ms682596(v=vs.85).aspx
2.

    Wednesday, January 18, 2012

    Malware Analysis Tutorial 12: Debug the Debugger - Fix Module Information and UDD File

    Learning Goals:
    1. Understand how debugger saves debugger information
    2. Know how to use binary editor to examine file contents
    3. Trouble shooting and fix issues of debuggers when necessary
    Applicable to:
    1. Assembly Language.
    2. Computer Security.
    3. Programming Language Principles.
    4. Operating Systems.

    1. Introduction
    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
    (5) Now in the code pane you can right click and goto 0x3C24FB. The first instruction should be "CMP [ESP+8], -2". You can set up some comments on any code below this instruction. To save your comments, goto to "View -> Executable Modules", right click on lz32.dll and select "Actualize" and then "save UDD files now". Stop the process being debugged and exit from IMM. Restart IMM again and repeat steps (1) to (5) again, you will notice that all your comments in the previous IMM session are gone!

    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
    (2) In IMM2, open the Max++ binary executable.
    (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.

    Tuesday, January 10, 2012

    Malware Analysis Tutorial 11: Starling Technique and Hijacking Kernel System Calls using Hardware Breakpoints

    Learning Goals:
    1. Understand hardware breakpoint
    2. Understand vectored/structured exception handling
    3. Understand the tricks that interrupt module loading
    Applicable to:
    1. Operating Systems.
    2. Computer Security.
    3. Programming Language Principles.
    4. Assembly Language.
    1. Introduction
    Starling is a bird that steals nests of other birds. In this tutorial, you will look at a "starling" technique used by Max++ to run its own malicious code using the "body" of another benign module named "lz32.dll". 

    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 will continue to analyze the function starting at 0x4014F9. 

    Figure 1. Function 0x4014F9 to Analyze

    (1) Clear all hardware breakpoints.
    (2) In code pane, right click and go to expression "0x4014F9"
    (3) right click and then "breakpoints -> hardware, on execution"
    (4) Press F9 to run to 0x4014F9
    (4) If you see a lot of DB instructions, select them and right click -> "During next analysis treat them as Command".
    (5) Restart Max++ and run to 0x4014F9 again. Select the instructions (about 1 screen) below 0x4014F9, right click -> Analysis-> Analyze Code. You should be able to see all loops now identified by IMM.


    3. Background
    Before we get to the interesting point, we will quickly go through the code before where the Max++ malware sets up a hardware breakpoint. We leave most of the analysis details to you and summarize the functionality of the these code snippets directly.

    3.1 Revisit of zwAllocateVirtualMemory 
    Recall that in Tutorial 10, we showed you the trick how Max++ can invoke ntdll system calls without the use of export table. At 0x00401157 it calls 0x004136BF, which does a binary search in the encoded export table  and then it jumps to the entry address of zwAllocateVirtualMemory. Now the interesting point is: what are the parameters of the call?

    Figure 2. Stack Contents

    According to [1], zwAllocateVirtualMemory has 6 parameters, as shown in the following:

    NTSTATUS ZwAllocateVirtualMemory(
      __in     HANDLE ProcessHandle,
      __inout  PVOID *BaseAddress,
      __in     ULONG_PTR ZeroBits,
      __inout  PSIZE_T RegionSize,
      __in     ULONG AllocationType,
      __in     ULONG Protect
    );

    The first parameter is the handle to a process within the address space of which a piece of memory will be allocated. Here, its value is 0xFFFF (-1) [see Figure 2], which means the current process. The second parameter (baseAddress) points to the memory word which will hold the base address of the newly allocated memory (note its type is inout). The last parameter, Protect, its value is 0x0040 [see the 5th word in Figure 2]. From the documentation in [1], we know that the constant values for "Protect" is defined in ntifs.h, or a simple Google search of "#define PAGE_NOACCESS" leads us to the header file directly. [NOTE: always use virtual machine to perform such Google search. Websites publishing windows source code are often loaded with malicious attack code such as drive-by download!] We now know that 0x40 is the value of macro "PAGE_EXECUTE_READWRITE". Did you smell something suspicious? The newly allocated memory will be executable!

    So far so good, we know that the beginning address of the new VM (virtual memory) will be stored in 0x0012D648. Right click on 0x0012D648 in the stack and select "Follow in Dump", step over (F8) the call 0x4136BF instruction at 0x00401157, you will notice that the newly allocated memory starts at 0x00003A00. [This value could vary between runs, even if you are using the same VBox instance]


    3.2 Another Layer of Self-Extraction
    Immediately following the zwAllocateVirtualMemory is a big two-layer nested loop (shown in Figure 3), starting from 0x00401567. Its purpose is to extract a section of data from Max++'s address space and copy it into the newly allocated VM starting at 0x00003A00 (the address may vary at run-time). We leave the details of the analysis to you and the following are some questions for you:

    (1) Where is the data from?
    (2) What is the size of the code copied into 0x00003A00?
    (3) How do you jump out of the two layer nested loop?

    Figure 3. Self-Extraction Again

    3.3. First section of 0x4012AB.
    If you successfully get out of the 2-layer loop of section 3.2, you would soon reach function 0x4012AB. This is an important function. Figure 4 shows the first part of this section. Now we get to the first interesting call at 0x4012C9 (see Figure 4). It calls function 0x004137D1. By tracing into the function, you will soon notice that it is actually a call to ntdll function RtlNtImageNtHeader, which takes a module address as a parameter, and returns a pointer to IMAGE_NT_HEADERS structure. Read Tutorial 8 (PE header) for the detailed analysis of the data structure.

    So what is the input parameter of RtlNtImageHeader? It's 0x003A0000 (the newly allocated memory). The return value (pointer to IMAGE_NT_HEADER) is also 0x003A0000. You can verify that it is indeed a pointer to IMAGE_NT_HEADER.
    Figure 4. RtlImageNtHeader
    In the memory dump pane, go to 0x003A0000, right click and select Special->PE header. (see Figure 5) You will notice that the information is beautifully rendered by the immunity debugger. There are, of course, several interesting points you have to note. For example, the entry point is offset 0x24FB. Also, you can find out the precise entry point of the module (that is 0X003A24FB).
    Figure 5. PE Header of the newly extracted binary executable
    Challenge 1 of the Day: Look at the two instructions starting at 0x4012CE (there is a comparison instruction following them). Explain the logic.

    4. The Starlings Trick: Take the Address Space of Another Module
    Starlings are well known for stealing other birds' nest. In the following, we show a highly skillful technique employed by Max++, which simulates starlings to load the new executable starting from 0x003A0000 using the address space of another module. The road map is follows:
    1. add an exception handler at 0x413657 (all interrupts, including hardware breakpoints, will trigger the code at 0x413657), 
    2. set a hardware exception at 0x7C90D500, 
    3. load a DLL file named "lz32.dll", 
    4. while the OS kernel is loading lz32.dll, the hardware exception triggers the code of 0x413657. It finishes the job of resetting the module address range to 0x003A0000 and avoid the loading of the real code from the "lz32.dll" file into the module's address space.
    Now let us examine each of these steps one by one.

    4.1 Add Vectored Exception Handler
    At 0x4012E4 (see Figure 6), the malware calls 0x413776 (again, it's a trick to avoid the use of export table to call ntdll functions) to invoke RtlAddVectoredExceptionHandler. For an introduction of Structured Exception Handlers, see Tutorial 3. It installs 0x00413657 as the first handler for all exceptions, including hardware breakpoints, any interrupt will trigger the code at 0x00413657 first.


    Figure 6. Set up Vectored Exception Handler


    Challenge 2 of the Day: (1) show the parameters of the RtlAddVectoredException; (2) If we run Max++ on a different computer, would the value of exception handler entry take a value other than 0x00413657?

    Challenge 3 of the Day: (1) at 0x401314, Max++ calls 0x4136E4. Analyze which system function it is actually invoking. (2) At 0x401346 (call 0x413811),  it is actually calling RtlPushFrame. Explain its purpose. (3) At 0x00401360 (call 0x413701), it is actually calling zwMapViewOfSection. Explain its purpose. (4) Combining (1), (2), and (3), what do you think the malware is trying to do?

    4.2 Set Hardware Breakpoint 0x7C90D500
    We now list some details of the second step. The key is the function 0x413736 as shown in Figure 7. It is essentially a call to zwSetContextThread. Its information is not officially available from Microsoft, but doing a little web search you will be able to find that it takes two parameters:

    IN HANDLE processHandle (value is 0xFFFF as shown in the stack pane of Figure 7)
    INOUT PCONTEXT pContext (value is 0x0012D028 as shown in Figure 7)

    Figure 7. zwSetContextThread
    0x0012D028 will hold a Context structure. Its data structure is shown as below (from [2]). Starting from the second word in the _CONTEXT structure are the values of hardware breakpoint registers (Dr0 to Dr7). Now if you look at Figure 8 (the current contents at 0x0012D028), you would notice that the value of ContextFlags is 0x00010010, and the value of Dr3 (the fourth hardware breakpoint register) is set to 0x7C90D500!!!



    //for x86
    typedef struct _CONTEXT {

    DWORD ContextFlags;
    ...
    DWORD Dr0;
    DWORD Dr1;
    DWORD Dr2;
    DWORD Dr3;
    DWORD Dr6;
    DWORD Dr7;
    ...
    FLOATING_SAVE_AREA FloatSave;
    /...
    } CONTEXT;

    Figure 8. CONTEXT structure contents at 0x0012D028
    Now we have almost unveiled all the tricks related to this step. Here are some of the challenges for you:

    Challenge 3 of the Day: (1) Explain the value 0x00010010 of the ContextFlags, what does it mean? (2) Find out 0x7C90D500, is it an entry address (or somewhere inside) of a system function?

    4.3 Load lz32.dll
    The next step is to load lz32.dll. Figure 9 shows the details (look at the comments area). It basically consists of two steps: (1) construct a unicode string "lz32.dll" and then (2) load the "lz32.dll" as a module. Tackle the following questions:

    Challenge 4 of the day: (1) Explain the logic of function 0x004137EF, (2) Explain the logic of 0x41385D.

    Figure 9. Load lz32.dll

    4.4 Interrupting the LdrLoadDll procedure
    Note that "lz32.dll" is not malicious, it IS the victim! When the dll file is loaded, the loading procedure will actually be interrupted by Max++. Recall that Max++ has already set the interrupt handler at 0x00413657.

    Now set a software breakpoint at 0x00413657, and also a breakpoint at 0x0040140E (right after the loading of lz32.dll). You going to get the most tricky part of the analysis:

    Challenge 5 of the day: Explain why isn't 0x00413657 never hit? Find a way to stop at 0x00413657.

    The correct way of hitting the 0x00413657:
    (1)goto 0x00413657 and set a SOFTWARE BREAKPOINT on it (by pressing F2).
    (2) Press SHIFT+F9 (think about what is the meaning of SHIFT+F9).
    (3) You might be hitting 0x7C90D5000 (think about why you are hitting it in IMM? -- because it's a hardware breakpoint set by Max++. IMM stops at it even though it's not a HW breakpoint set inside IMM).
    (4) Simply SHIFT+F9 again and you will hit 0x00413657. Now you can start your analysis of the exception handler.


    Then the analysis is going to be quite some work, in the following please find some hints:

    (1) The code at 0x00413657 is essentially an exception handler. Check out [3] for the calling convention (how the parameters are passed) for exception handlers. You will notice that the code is reading the exception record and tell if it is of its special interest. If it's not the hardware breakpoint exception (more exactly single_step_trap), the handler simply passes the exception to the next handler in the chain.

    (2) Once it is identified to be a hardware breakpoint, the handler does some writing into the memory. For example, it is writing value "0x003A0000" to some kernel data structures (related to a module). Think about why?

    (3) The handler sets the thread Context again to set the EIP register so that it does not return the 0x7Cxx (ntdll) function being called. The result? the actual binary code of lz32.dll is not loaded. Thus, the 0x003A0000 code stays there and is executed when the module "lz32.dll" is started.

    Challenge 6 of the day: analyze each line starting from 0x00413657 and verify if the above statement is true.





    References
    1. Microsoft, "zwAllocateVirtualMemory Routine", available at http://msdn.microsoft.com/en-us/library/windows/hardware/ff566416(v=vs.85).aspx.
    2. Microsoft,  "Context Structure", available at http://msdn.microsoft.com/en-us/library/windows/desktop/ms679284(v=vs.85).aspx.
    3. M. Pietrek, "A Crash Course on the Depth of Win32Tm Structured Exception Handling," Microsoft System Journal, 1997/01. Available at http://www.microsoft.com/msj/0197/exception/exception.aspxhttp://www.microsoft.com/msj/0197/exception/exception.aspx.

    Wednesday, January 4, 2012

    Malware Analysis Tutorial 10: Tricks for Confusing Static Analysis Tools

    Learning Goals:
    1. Explore Use of Stack for Supporting Function Calls
    2. Practice Reverse Engineering
    Applicable to:
    1. Operating Systems.
    2. Computer Security.
    3. Programming Language Principles.

    1. Introduction
    This tutorial explores several tricks employed by Max++ for confusing static analysis tools. These tricks effectively prevent static program analysis tools that plot call graph and extract system call invocation information of the malware. By "static" we mean that the tool does not actually execute/run the malware. Most "smart" virus scanners are static analysis tools. Many of them employ heuristics to tell if a binary executable is malicious or not by examining the collection of the system function calls in that binary. For example, if a binary invokes too many operations related to registry, then an alert should be flagged. If such analysis can be blocked, the malware can significantly improve its survival rate. Note that, however, such tricks cannot block "dynamic" tools which actually run the malware (typical examples include CWSandBox and Anubis).

    2. Lab Configuration
    You can either continue from Tutorial 9, 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 will analyze the function starting at 0x4014F9. 

    Figure 1. Function 0x4014F9 to Analyze


    (1) In code pane, right click and go to expression "0x40105c"
    (2) right click and then "breakpoints -> hardware, on execution"
    (3) Press F9 to run to 0x40105c
    (4) If you see a lot of DB instructions, select them and right click -> "During next analysis treat them as Command".
    (5) Exit from IMM and restart it again and run to 0x40105c. Select the instructions (about 1 screen) below 0x40105c, right click -> Analysis-> Analyze Code. You should be able to see all loops now identified by IMM.
    (6) Now go to 0x401147, you will notice that it's "CALL 0x4014F9". Press F4 to run to the point and then Press F7 to step into the function 0x4014F9.



    3. Two-Layer Function Return
    We now analyze the first trick of a two-layer function return which disrupts call graph generation. In the following we analyze function 0x00401838. Observe the instructions from 0x401502 to 0x401505 (in Figure 2). Our first impression would be that Function 0x401038 takes three parameters: a pointer to string "ntdll.dll", 0x7C903400, and 0x7C905D40. However, later you will find that it is not the case: function 0x00401838 is simply used to confuse static analysis tools.

    Figure 2. Two Layer Function Call at 0x401505
    Figure 3 displays the function body of 0x401838. It starts with a call of 0x00413650 and then a bunch of other instructions (later, you will notice that these instructions will never be executed).

    Figure 3. Function body of 0x401838
    Notice that at 0x0040183B, it calls function 0x00413650, whose function body is displayed in Figure 4. There are only two instructions: POP EAX, and RETN.
    Figure 4. Function Body of 0x413650
    Now we have the interesting part. Look at the stack contents in Figure 5. First of all, starting from the third computer word, we have the three words pushed by the code earlier (they are pointer to "ntdll.dll", 0x7c903400, and 0x7c905d40). Then you might notice that the top two words are the RETURN ADDRESSES pushed by the CALL instructions.

    Each CALL instruction consists of essentially two steps: push the address of the next instruction to the stack (so that it can return when the function being called is completed) and then jump to the entry address of the function. Thus, it is not difficult to infer that 0x00401840 is pushed by the CALL 0x00413650 at 0x0040183B (see Figure 3), and 0x0040150A is pushed by the CALL 0x00401838 at 0x00401505 (see Figure 2). So the POP EAX will pop off 0x00401840 and save it to EAX. When the RETN instruction is executed, it is directly returning to 0x40150A (i.e., it jumps two layers back)! Clearly, the instructions starting from 0x00401840 are never executed and the two layer jumping can confuse quite a number of static analysis tools when they try to plot call graphs.

    Figure 5. Stack Contents at 0x00413650


    4. Invoking NTDLL System Calls using Encoded Table
    Next we show an interesting technique to invoke ntdll.dll functions without the use of export table. We will analyze the instruction at 0x401557 (as shown in Figure 6), it calls function 0x4136BF. Later, you will find that function 0x4136BF invokes zwAllocateVirtualMemory without exposing the entry address of zwAllocateVirtualMemory explicitly and it does not use export table.

    We leave the analysis of  the logic between 0x40150A and 0x401557 (shown in Figure 6) to readers. Basically the code is to establish an encoded translation table in stack from 0x0012D538 to 0x0012D638.

    Figure 6. Code Between 0x40150A and 0x401557

    Now observe the function body of 0x004136BF in Figure 7. The first instruction is CALL 0x004136DC. You might notice that between 0x004136BF and 0x004136DC, there are some gibberish code. If you read it more carefully, you will find that they are actually the contents of string "zwAllocateVirtualMemory" where the byte at 0x004136C4 is the character "z".

    Think about the CALL 0x004136BF again. It is essentially two stesp:
        PUSH 0x004136C4   # note 0x004136C4 is the beginning of "zwAllocateVirtualMemory" (see Figure 8)
        JUMP 0X004136DC

    Figure 7. Function Body of 0x4136BF.

    Now you can pretty much guess the point of the code: it is trying to invoke zwAllocateVirtualMemory! But how is it accomplished? Let's delve deeper. At 0x004136DC it is calling function 0x00401172 and when it returns, at 0x004136E1, it JMP EAX. Can you guess the functionality of 0x00401172?


    Figure 8. Stack Contents at 0x4136DC before the Call of 0x00401172
    We list some hints below (see Figure 9):
    (1) The loop between 0x0040118E and 0x004011A0 is to compute the checksum of the function name
    (2) The loop between 0x4011A2 and 0x004011BA is a binary search. The search is performed on the encoded export table (as discussed in Tutorial 9). Each entry has two elements: (1) check sum of the function name, and (2) the entry address of the function.

    You could easily infer that function 0x00401172, given the name of a function, returns its entry address. Once it returns, the return value is saved in EAX. Then JMP EAX at 0x004136E1 will invoke the function.


    5. Challenge of the Day
    (1) What is the checksum of zwAllocateVirtualMemory?
    (2) What are the parameters of zwAllocateVirtualMemory? Why does Max++ call this function?
    (3) Look at 0x40117B, what is stored in the thread local storage (EAX+2C)? How do you make your conclusion?