One of the programs up on my homepage (does anyone call their website a “homepage” anymore?) is SDbgExt, a WinDbg-compatible extension DLL. It’s a little collection of various debugging tools that I have put together over time that you might find useful. There is some minimal documentation included, but not a whole lot to tell you where and when certain extensions are useful – hence, the topic of today’s blog post.
This posting series assumes that you have already installed WinDbg, installed the Visual C++ 2005 Runtimes, and placed SDbgExt.dll into your Debugging tools for Windows\WinExt directory. At present, SDbgExt can only be loaded into the 32-bit WinDbg package, although some extensions do support 64-bit targets (such as 64-bit kernel debugging targets).
To get started using SDbgExt, you’ll need to load it into your debugger. For WinDbg, ntsd, cdb, and kd, you can use the “.load SDbgExt” command to do this. If you then use the “!sdbgext.help” command, you should be presented with a list of the available extensions supported by SDbgExt. Most of the extensions are targetted at live 32-bit processes on the local computer (such as the extensions dealing with displaying HWND information). The documentation does not specify which targets are supported by each extension yet, so if you aren’t sure whether an extension is supported against your current debugging target, just try it; if not, it will harmlessly fail in an obvious manner.
Many of the SDbgExt extensions have very specific purposes, so I’ll try to several of them address them individually and describe what they are best used for. Additionally, most of the SDbgExt extensions can be broken down into several categories, such as symbol management, UI debugging, STL datastructures manipulation, kernel object support, and debuggee state manipulation. I’ll be skipping some of the extensions that are either obvious or not generally useful, but I’ll try to cover most of the interesting ones.
To start off, I’ll talk about some of the debuggee state manipulation extensions. These extensions allow you to control the state of a live 32-bit target process that is running on the same computer as the debugger (remote debugging and 64-bit targets are not supposed yet by these extensions). The extensions that fall under this category include:
- !valloc, !vallocrwx, !heapalloc, !heapfree: Allocate memory within the address space of the target.
- !remotecall, !remotecall64: Call a function in the target, using the currently active thread (symbols are not required, unlike “.call”).
- !loaddll, !unloaddll: Load or unload a .dll within the address space of the target, using the currently active thread.
- !close: Close a kernel object handle in the targets handle space.
- !killthread: Terminate a thread in the target process.
- !adjpriv: Alter privileges of the target process or currently active thread.
- !ret: Effect a virtual function return in the context of the currently active thread.
Many of these extensions are useful if you are doing some runtime patching of a target or are trying to see how the target will react to specific circumstances. If you are trying to reverse engineer or modify the behavior of a target, in particular, you might find several of these extensions very useful.
The first group of extensions are used for managing memory allocation in the targets address space – either by directly allocating pages within the target or allocating heap memory. The latter requires that you resume execution of the target as internally the remote heap manipulation functions use the remote function call support to call the heap manager in the target process. Perhaps the most common use for this family of functions is if you need to allocate some space on the fly if you are adding some code to the debuggee on the fly (maybe you need to patch a function and add several instructions, in which case you could allocate memory with !vallocrwx, and then patch a jump instruction to refer to the newly allocated memory block).
The next two groups of functions are used for directly calling functions in the target, from the context of the currently active thread in the debuggee. Be warned that this is an invasive operation and may cause undesirable side effects in the context of the debuggee. The main advantage of the !remotecall family of extensions over the built-in .call command is that you do not need to have private symbols for the target, which makes it particularly useful if you are reverse engineering something or need to call a Win32 API function in the context of the debuggee from the debugger. These functions can allow you to do complicated things that are difficult or impossible to do remotely (from the debugger), such as calling SetHandleInformation to mark a handle closable or nonclosable from WinDbg. You can use !loaddll and !unloaddll as shortcuts (as opposed to using !remotecall on kernel32!LoadLibraryA/kernel32!FreeLibrary manually) for DLL management in the target process space.
!close is mostly analagous to the .closehandle built-in command, and is used to close a handle in the context of a debuggee.
!killthread is useful if you need to instantly terminate a thread in the debuggee process, for whatever reason. You can manually achieve something like this with a command like “r eip=kernel32!ExitThread;g” for Win32 targets, but this extension provides a more elegant means to killing debuggee threads (for instance, you might want to kill a thread that is crashed so that it doesn’t take down the rest of the process in the default SEH handler, for certain scenarios).
!adjpriv is useful if you are debugging problems related to the privileges that are enabled in a primary or impersonation token. You can use the built-in !token extension to determine what privileges are currently present, enabled, or disabled in a token, and the !adjpriv extension to manipulate these privileges from the debugger itself. This can also be used to work around buggy programs that don’t properly enable privileges before they try to do certain privileged operations (such as things written for Win9x).
!ret is primarily useful in conditional breakpoints if you want to return from the middle of a function at a breakpoint location based on a particular condition. It alters the context of the currently active thread (modifying the stack pointer, instruction pointer, and optionally return address registers) according to its arguments.
The next group of extensions that I’d like to describe are the symbol management extensions. These are extremely useful if you are reverse engineering a program and want to synchronize your work between a disassembler (such as IDA) and the debugger. The two extensions that fall into this category are !loadsym and !unloadsym.
These two extensions allow you to either create or remove custom virtual symbols in the target. A virtual symbol allows you to name an address (although it does not allow you to convey type information, unfortunately). This can be extremely useful if you are debugging a third-party program that has no symbols, and you want to name certain addresses to make them easier to recognize.
Both extensions can operate on two different types of symbol files: a custom format that is specific to SDbgExt and allows you to specify all possible attributes that are supported by virtual symbols (primarily the size of the symbol, name, and its offset from a base module), and a standard linker .map file. The latter is generally the most useful of the two formats, as there are many things that can write symbol information to a .map file which you can then load into SDbgExt and access through WinDbg. For instance, IDA allows you to dump all names in a database (disassembly project) to a .map file, which you could then load using SDbgExt and have names in WinDbg that match the work you have done in IDA. These commands can also be useful if the only symbols you have for a particular binary are the linker map files (which has happened to me once or twice, on rare occasions).
Both extensions require a 32-bit target, although the target may be a remote target and can be either a user mode or kernel mode target. For kernel targets, the symbol loading support will apply to modules in the kernel mode loaded module list primarily. Virtual symbols are automatically unloaded whenever you reload symbols (such as with the “.reload” command), so you may find yourself needing to re-apply the custom symbols more than once in a session. Additionally, due to a bug / limitation in how DbgHelp and DbgEng manage virtual symbols, the process of creating virtual symbols unfortunately gets exponentially slower relative to how many virtual symbols are currently in existance. As a result, creating more than a couple thousand virtual symbols may take a while.
The last group of extensions that I am going to cover in the first installment of this series is the kernel object support extension group. These extensions are intended to complement the built-in support (such as !handle or !token) for querying kernel objects by allowing access to things that are otherwise not easily queryable from the debugger. Although the information available from the built-in debugger support is usually sufficient, in special cases you may need additional information (such as security descriptor information). Most of these extensions require a live 32-bit target on the local computer to operate correctly.
The !objname extension takes an object handle relative to the handle space of the debuggee and returns the full name for it. This is similar to the built-in !handle extension, except that it works on all kernel object types (unlike !handle, which does not work on some object types, such as file object handles).
!tokeninfo will allow you to inspect some additional information about an access token object, beyond that which the built-in !token extension makes available to you (either given a token handle, or by operating on the primary or impersonation token that is effective for the currently active thread). The most useful pieces of information available from this extension are the TokenId (uniquely identifying a token object throughout the system) and the ModifiedId (which increments whenever a tokens attributes are altered in any way).
The !objsec extension is useful for displaying detailed information about the security descriptor of an object given an object handle. In kernel mode, you can use the !sd extension based on the security descriptor pointer embedded in a kernel object header, but this extension allows you to perform a similar function from user mode. It has built-in knowledge about the object specific access rights supported by all of the kernel object types (as of Windows Server 2003 SP1) and will automatically translate access right values in access masks to more human readable values.
If you are dealing with a raw access mask directly (perhaps passed to a security related function as a parameter), and you want to know what it means given a particular object type, then you can use the !amask extension to have SDbgExt interpret the access mask bits as they apply to a particular object type. The !objtypes extension lists the object type names that are supported by !amask. If you do not supply an object type argument to !amask, it will only interpret generic and standard access rights.
The !sidname extension can be used to convert a SID into an account name. Unlike most extensions, this extension does not operate on the debuggee at all; instead, it simply takes a string SID as a single argument and attempts to resolve it against the security database of the computer hosting the debugger. This is a shortcut for command line utilities (like PsGetSid) that could do the same for you, since many of the access token related functions will give you back a raw string SID and will not translate it into a more understandable account name.
The !threadinfo extension will display some basic information about a thread running in the debuggee. It will only work on local targets on the same computer as the debugger. This extension allows you to view a couple of rarely-used fields that aren’t easily viewable from the debugger in user mode, like processor affinity or thread and exit times.
That’s all for this post. The next post in this series will cover the remaining major extensions in SDbgExt.