TippingPoint Digital Vaccine Laboratories
DID YOU KNOW... We release at least two Digital Vaccine updates a week to our IPS customers; on average each has about 10 new security filters, many of which are turned on by default.

MindshaRE: WinDbg Extensions

WinDbg may not have the same level of community developed plugins as other debuggers. But for your day to day tasks, like vulnerability analysis, reverse engineering, or exploit development, it provides a plethora of helper functions for digging deep into the happenings of a process or OS. Most of which don't exist for other debuggers. So today we will take a look at WinDbg extensions, and a few handy ones you can hopefully put to use right away.

MindshaRE is our weekly look at some simple reverse engineering tips and tricks. The goal is to keep things small and discuss every day aspects of reversing. You can view previous entries here by going through our blog history.

WinDbg extensions are libraries that can be written to compliment the built in debugger commands. Many Microsoft provided extensions are already pre-bundled with the debugging tools for windows package. To allow others to contribute to the ever growing command list Microsoft also provides an SDK for creating third party plugins.

When WinDbg is started, it automatically loads the default extensions you have in your installation directories extension folder (c:\Program Files\Debugging Tools for Windows\(winext|winxp|win2k[chk|fre])\). Once loaded the exported commands available are executed using the ! prefix to the command name. Lets take a quick look at some handy default extension provided commands.

The !analyze command is very useful when an access violation occurs during a debugging session. It gathers all of the pertinent information regarding the violation and formats it so that it is easier to read. Here is the output from a crash.

(178c.16e4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0007f998 ebx=000b33c8 ecx=000b02c8 edx=00000000 esi=80000000 edi=000b33d4
eip=01012318 esp=0007f974 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
calc!mulnumx+0x4:
01012318 8b750c          mov     esi,dword ptr [ebp+0Ch] ss:0023:0000000c=????????

0:000> !analyze -v
FAULTING_IP: 
calc!mulnumx+4
01012318 8b750c          mov     esi,dword ptr [ebp+0Ch]

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 01012318 (calc!mulnumx+0x00000004)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 0000000c
Attempt to read from address 0000000c

FAULTING_THREAD:  000016e4

PROCESS_NAME:  calc.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory
                                    at "0x%08lx". The memory could not be "%s".

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory
                                        at "0x%08lx". The memory could not be "%s".

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  0000000c

READ_ADDRESS:  0000000c

FOLLOWUP_IP:
calc!mulnumx+4
01012318 8b750c          mov     esi,dword ptr [ebp+0Ch]

NTGLOBALFLAG:  0

APPLICATION_VERIFIER_FLAGS:  0

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_DEREFERENCE

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE

LAST_CONTROL_TRANSFER:  from 00000000 to 01012318

STACK_TEXT: 
00000000 00000000 00000000 00000000 00000000 calc!mulnumx+0x4

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  calc!mulnumx+4

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: calc

IMAGE_NAME:  calc.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  3b7d8410

STACK_COMMAND:  ~0s ; kb

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_calc.exe!mulnumx

BUCKET_ID:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_calc!mulnumx+4

Followup: MachineOwner
---------

Using the -v option with analyze displays a great summarization of the process, and why it crashed. Some interesting things to note are the DEFAULT_BUCKET_ID, and LAST_CONROL_TRANSFER items.

The next extension provided command, which can be useful when working with malware, is the !dh command. !dh will display the image header specified, in an easy to read manner. Here is an example.

0:000> !dh calc
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
     14C machine (i386)
       3 number of sections
3B7D8410 time date stamp Fri Aug 17 15:52:32 2001

       0 file pointer to symbol table
       0 number of symbols
      E0 size of optional header
     10F characteristics
            Relocations stripped
            Executable
            Line numbers stripped
            Symbols stripped
            32 bit word machine

OPTIONAL HEADER VALUES
     10B magic #
    7.00 linker version
   12800 size of code
    9C00 size of initialized data
       0 size of uninitialized data
   12475 address of entry point
    1000 base of code
         ----- new -----
01000000 image base
    1000 section alignment
     200 file alignment
       2 subsystem (Windows GUI)
    5.01 operating system version
    5.01 image version
    4.00 subsystem version
   1F000 size of image
     400 size of headers
   1D7FC checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
       0 [       0] address [size] of Export Directory
   12B80 [      8C] address [size] of Import Directory
   16000 [    8960] address [size] of Resource Directory
       0 [       0] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
       0 [       0] address [size] of Base Relocation Directory
    1240 [      1C] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
       0 [       0] address [size] of Load Configuration Directory
     260 [      80] address [size] of Bound Import Directory
    1000 [     228] address [size] of Import Address Table Directory
       0 [       0] address [size] of Delay Import Directory
       0 [       0] address [size] of COR20 Header Directory
       0 [       0] address [size] of Reserved Directory

SECTION HEADER #1
   .text name
   126B0 virtual size
    1000 virtual address
   12800 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

Debug Directories(1)
    Type       Size     Address  Pointer
    cv           19        160c      a0c    Format: NB10, 3b7d8410, 1, calc.pdb

SECTION HEADER #2
   .data name
    101C virtual size
   14000 virtual address
     A00 size of raw data
   12C00 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #3
   .rsrc name
    8960 virtual size
   16000 virtual address
    8A00 size of raw data
   13600 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

My next handy example will dump the SEH chain from the current process. We use this all the time to verify when an overflow has smashed the chain allowing simple code execution. To view this we use !exchain.

0:000> !exchain
0007faec: calc!terminate+10 (010128f8)
0007fb14: calc!terminate+1a (01012902)
0007fbcc: USER32!_except_handler3+0 (7e44048f)
0007fd88: USER32!_except_handler3+0 (7e44048f)
0007fde8: USER32!_except_handler3+0 (7e44048f)
0007ff10: calc!terminate+6 (010128ee)
0007ffb0: calc!_except_handler3+0 (010128e2)
0007ffe0: kernel32!_except_handler3+0 (7c839ac0)

In the case of an overflow we might see something like this.

0:000> !exchain
0007ffe0: 41414141
Invalid exception stack at 41414141

This tells us the pointers to the chain on the stack have been overwritten.

!handle will dump fantastic information pertaining to a specified handle. You can get a list of handles by issuing a 0 for the handle id. Here is an example of a handle to an open registry key.

0:000> !handle 28 f
Handle 28
  Type             Key
  Attributes       0
  GrantedAccess    0xf003f:
         Delete,ReadControl,WriteDac,WriteOwner
         QueryValue,SetValue,CreateSubKey,EnumSubKey,Notify,CreateLink
  HandleCount      2
  PointerCount     3
  Name             \REGISTRY\MACHINE
  Object Specific Information
    Key last write time:  15:16:40. 1/21/2009
    Key name MACHINE

Of particular interest is the Name field associated with this handle. Note that this also works for file handles.

This is just a few of the numerous extensions provided with the debugging tools package. The following list are several other extensions provided by Microsoft, each containing dozens of commands.
  • Logger Extensions (Logexts.dll) 
  • NDIS Extensions (Ndiskd.dll) 
  • RPC Extensions (Rpcexts.dll) 
  • ACPI Extensions (Acpikd.dll and Kdexts.dll) 
  • NDIS Extensions (Ndiskd.dll) 
  • Graphics Driver Extensions (Gdikdx.dll) 
  • Kernel Streaming Extensions (Ks.dll) 
  • SCSI Miniport Extensions (SCSIkd.dll and Minipkd.dll) 
  • Kernel-Mode Driver Framework Extensions (Wdfkd.dll) 
  • User-Mode Driver Framework Extensions (Wudfext.dll)
  • WMI Tracing Extensions (Wmitrace.dll) 
  • OEM Support Extensions (Kdex2x86.dll) 
As we mentioned previously Microsoft also provides an SDK for creating new plugins. Several great ones exist, however I primarily use one mandatory extension, SdbgExts. SdbgExts is an extension written by Skywing adding some very useful commands. One of the commands I use most from this extension is !remotecall. Before we use !remotecall we must load it via the !load <dllname> command. Doing this will import the exposed third party commands into your current session of WinDbg. !remotecall allows you to call any function in a binary supplying the arguments of your choosing. Let's try it out.

0:002> !remotecall 01007C4C 0 10 5
calc!longtonum() will be run when execution is resumed
0:002> g
Files\Debugging Tools for Windows\winext\sdbgext.dll - 
calc!longtonum() [conv=0 argc=8 argv=00C20488]
calc!longtonum() returned 000B32D8

We can see all of the extensions defined commands by issuing the !help command (Many commands have been omitted).

0:001> !load sdbgext
0:001> !help
Skywing Debugger Extensions (SDbgExt) help
!valloc       [address] <size> <type> <protect>     Allocates virtual memory
...
!loaddll      <dllname>                             Loads a dll into the target process (from a new thread)
...
!heapalloc    [heap] <size>                         Allocates heap memory (defaults to the process heap)
...
!loadsym      <module> [symbol list file] [path]    Loads custom symbols from a symbol list file.
...
!cmpmem <[[-a|-x] addr length] | [-e addr] | [-c addr] [-s addr] [-l]> 
                                                    Compares memory over time.
...

More information about Skywing's extension can be found in his two part series on the extension at his blog.

Microsoft has really gone the extra mile to make their debugger full featured by providing extra extensions. Hundreds of useful commands are at your fingertips. Open the WinDbg help file and take a look. I hope you find something you've been wanting.

-Cody
Tags:
Published On: 2009-01-22 14:53:50

Comments post a comment

No comments.
Trackback