"Hello World" For Windbg

This post is an introductory to Windbg from an Ollydbg user's perspective. It contains an example of the "Hello World" of malware analysis; which is unpacking UPX and bypassing IsDebuggerPresent. I'm still learning Windbg but I'm hoping this post will be useful to others. I assume the reader has the Debugging Tools for Windows installed and symbols setup. The quickest way to verify that the symbols are setup properly is to try the following in Windbg File > Open Executable > notepad.exe. Once the executable loads execute !peb from the command line.

We can see the symbols are not properly set up by the warning in the banner. If this is the case, the following link can be helpful in setting up the symbols and fixing them. If the symbols are setup properly we would see the following output.

One of the difficult parts of learning Windbg is enumerating useful commands. Ollydbg is great because you can see all the useful commands by selecting a drop down. This isn't the case for Windbg. The best place to look up commands is Windbg Help file. It's surprisingly useful. Below is a list of commands that I enumerated that are commonly used in debugging malware.
  • .tlist
    • list all running processes   
  • lm
    • list all loaded modules
  • lmf
    • list all loaded modules - full path
  • !dlls
    • list all loaded modules - more detailed
  • !dh address
    • displays the headers for the specified image
  • !dh -options address
    • no options, display all
    • -f  display file headers
    • -s display sections headers
    • -a display all header
  • @$exentry
    • location of entry point
  • u
    • unassemble
  • !SaveModule startaddress path
  • ~
    • thread status for all threads
  • |
    • process status
  • !gle
    • get last error
  • r
    • dump registers
  • r reg=value
    • assign register value
  • rF
    • dump Floating point
  • k
    • display call stack for current thread
    • k b (displays ChildEBP RetAddr  Args to Child ) 
  • !peb
    • dump process block
  • !address
  • .lastevent
  • .imgscan
    • dump al
  • bl
    • list breakpoints
  • bc
    • clear breakpoint, * or #
  • bd
    • disable breakpoints
  • bp
    • breakpoint
      • bp DLL!API_NAME
  • ba
    • r/write/execute (r,w,e) size addr
  • bu
    • bu myDriver!DriverEntry (break on entry point of driver) 
  • sxe cpr
    • break on process creation
  • sxe epr
    • break on process exit
  • sxe ct
    • break on thread creation
  • sxe et
    • break on thread exit
  • sxe ld
    • break on loading of module
  • sxe ud
    • break on unloading of module
  • $$
    • print string
  • p
    • step over
  •  t
    • step into
  • restart
    • restarts the debugging of the executable process
  • q
    • quit
Let's explore these commands on some UPX packed C code.

#include <windows.h>
#include <stdio.h>

int main(int argc, char *argv[])
 if (IsDebuggerPresent() == TRUE)
  MessageBox(NULL, TEXT("Please close your debugging application and restart the program"),  TEXT("Debugger Found!"), 0);
 MessageBox(NULL, TEXT("Hello World!"),  TEXT("Bypassed"), 0);
        return 0;

The compiled code can be downloaded from here (MD5: 4F6B57487986FD7A40CFCFA424FDB7B8). The first thing to do is File > Open Executable.. to load the sample into the debugger. Do not use the folder icon via the menu to load the executable. This will only open the executable as if we were opening it in Notepad.exe. 

Windbg will not break at the entry point of the executable but at what OllyDbg labels as the system breakpoint. Except Windbg breaks one instruction before OllyDbg sets it's system breakpoint. To get the address of the entry point we can read it from the portable executable (PE) header but in order to get it we have to know the base address of the executable. This is a common theme when using Windbg. In order to run one command, we have to calculate or parse the results of another command and then us as an argument. The base address is present in the output (as seen above) when the executable is first loaded in windbg. If we accidentally cleared the screen with the command.cls, the easiest way to get the base address is to execute lm (list modules) or lmf (list module with file path). 

To read the PE header we can use the command dh (dump headers) with an argument of the base address. The entry point of the executable will be found in the OPTIONAL HEADER VALUES. 

Since we have the base address (012c0000) and the entry point (79A0) we can add the two and print the assembly of the entry point using u with an argument of the address.

A much quicker approach to access the address of entry point is @$exentry. Since we are at the system breakpoint, we need to set a breakpoint using the command bp with an address as the argument and then execute until the breakpoint is hit by pressing g and then enter in the command window. It is sometimes useful to dump out the register to have an idea of where we are at. Dumping the registers can be done using the command r.

The pushad instruction is a good indicator that we are at the entry point of UPX. Let's dump the section headers using !dh -s address. The -s is short for section.

For safe practice we should remove the breakpoint. To remove a breakpoint we first show a list of all breakpoints by using the command bl (break list) and to remove it we use command bc (break clear) with an argument of the index of the breakpoint. 

UPX is very easy to unpack. The classic technique is to step over pushad, set a break on access on the contents of ESP, execute till breakpoint, set a breakpoint on the jump after the restoring of the stack (SUB ESP -0x80), then execute until breakpoint and single step into the jump. Stepping into is executed by the command t.  To create a break on access we use the command ba with an argument of r/w/x, size and address. To execute till the breakpoint the g command is used. Note: base address has changed to 01330000 due to restarting

At address 01337b54 we can see the JMP to the original entry point of the executable. First we need to remove the breakpoint via the the bl and bc combinations of commands.  Once removed we will set a breakpoint by using the command bp, execute g till breakpoint, step into t and we will be at the original entry point. 

Now it's time to bypass IsDebuggerPresent. The technique I'm going to use is from mmmmmm blog. Once you grasp the concepts presented in this post I'd highly recommend reading his post Games for Windows – Live. It's an excellent article on exploring anti-debugging using Windbg. What would happen if we executed our compiled code?

Quick recap to unpack UPX and get back to the original entry point.
  1. .restart
  2. bp @$exentry
  3. g
  4. t
  5. bl 
  6. bc 0
  7. ba r 4 @esp 
  8. bl
  9. bc 0
  10. bp address of JMP
  11. g
  12. bl 
  13. bc 0
  14. t
IsDebuggerPresent can be easily bypassed by patching the second byte of the PEB with 0. 

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;

To patch the byte we can use eb (edit byte) with an argument of the address and the value . 

We can see the BeingDebugged has a value of No. If we press g to execute we can see we bypass IsDebuggerPresent().


As previously mentioned  I'm still learning if you have any recommends on commands or examples please leave a comment. Cheers.