|
This example shows how to use DbgHelp functions (MiniDumpWriteDump, MiniDumpCallback,
MiniDumpReadDumpStream) to get the list of handles opened by a process.
Background
With the help of MiniDumpWriteDump function, we can create a minidump with handle
information. With the help of MiniDumpReadDumpStream function, we can read the contents
of the minidump, including handle information. If we sum up these two simple facts,
in the outcome we get the possibility to obtain the list of handles opened by a process,
without the need to resort to undocumented functions NtQuerySystemInformation and
NtQueryObject. HandleDump example shows how to do it.
The process of getting the list of handles consists of the following steps:
- Create a minidump of the target process (with handle information included)
- Read the handle information from the minidump
Both steps are described below in more details
Creating the minidump
In order to create the minidump, we have to have a handle to the target process.
If we know the id of the process, we can use OpenProcess function to get the handle.
Since full access to the target process is required to create the minidump successfully,
it is useful to enable the debug privilege before calling OpenProcess.
After that, we are ready to create the minidump. Since we are only interested in
handle information, we pass MiniDumpWithHandleData flag to MiniDumpWriteDump function.
In order to keep the minidump as small as possible, MiniDumpCallback function is
also used – it handles IncludeModuleCallback and IncludeThreadCallback callbacks
and excludes all module and thread information from the minidump. (In this
article you can find more information
about MiniDumpCallback function and the ways to control the size and contents
of the minidump).
Reading handle information from the minidump
After we have created the minidump, it’s time to read it and extract the list of handles
opened by the process. At the beginning, we have to map the minidump file into memory
using CreateFileMapping and MapViewOfFile functions. Then we use MiniDumpReadDumpStream
function to get the contents of the stream that contains the handle information.
The stream starts with the following header structure:
typedef struct _MINIDUMP_HANDLE_DATA_STREAM {
ULONG32 SizeOfHeader; // sizeof(MINIDUMP_HANDLE_DATA_STREAM)
ULONG32 SizeOfDescriptor; // sizeof(MINIDUMP_HANDLE_DESCRIPTOR)
ULONG32 NumberOfDescriptors;
ULONG32 Reserved;
} MINIDUMP_HANDLE_DATA_STREAM;
The first two members allow us to verify that the stream format is valid and can be
understood by our application. The third member (NumberOfDescriptors) contains
the number of MINIDUMP_HANDLE_DESCRIPTOR structures that follow the header.
Every MINIDUMP_HANDLE_DESCRIPTOR structure describes a handle in the handle table
of the target process:
typedef struct _MINIDUMP_HANDLE_DESCRIPTOR {
ULONG64 Handle;
RVA TypeNameRva;
RVA ObjectNameRva;
ULONG32 Attributes;
ULONG32 GrantedAccess;
ULONG32 HandleCount;
ULONG32 PointerCount;
} MINIDUMP_HANDLE_DESCRIPTOR;
Most of the members of this structure have an obvious meaning, but TypeNameRva and
ObjectNameRva might need a short explanation. They contain an RVA (relative virtual
address) from the beginning of the minidump data in memory (as returned by MapViewOfFile)
to the location where a MINIDUMP_STRING structure is stored. This structure is defined
as the following:
typedef struct _MINIDUMP_STRING {
ULONG32 Length; // Size of the buffer, in bytes
WCHAR Buffer [0]; // The buffer with the string (null-terminated)
} MINIDUMP_STRING;
When we know the format of all structures used to describe handle information,
reading it from the minidump is easy.
Limitations
While the handle information collected by MiniDumpWriteDump is undoubtedly useful,
it has a serious limitation – it does not contain the names of open files (that is,
object name is always empty for handles that represent open files). At the same time,
object names are available for handles that represent other types of kernel objects.
Supported operating systems
Windows NT 4.0, Windows 2000, Windows XP and Windows Server 2003.
Sample files
The sample application consists of three source files. GetHandles.h and GetHandles.cpp
contain the implementation of CGetHandles class, which hides the details of obtaining
the handle information behind an easy-to-use interface. HandleDump.cpp file uses this
interface to read the handle information and display it to the user in readable format.
Download
Download HandleDump source code (6 KB)
Download HandleDump executable (no source code) (440 KB)
The following steps are needed to build the example:
1. Find the latest versions of DbgHelp.dll, DbgHelp.h and DbgHelp.lib files.
The latest versions of these files are always available with
Debugging Tools
for Windows package. Download and install Debugging Tools
for Windows (when installing, choose custom installation and install SDK).
2. Configure Visual Studio to find DbgHelp.h and DbgHelp.lib files.
These files are supplied with Visual Studio and Platform SDK, but it is necessary
to use the latest files – the files that come with Debugging Tools for Windows.
Thus it is necessary to configure Visual Studio include and library directories
so that the latest files will be found first.
Use the following directories:
Include -> %DebuggingTools%\sdk\inc
Library -> %DebuggingTools%\sdk\lib\i386
3. Create an empty console project and add the source files to the project.
4. When the project is built, make sure that the executable can find
the latest version of DbgHelp.dll.
Copy DbgHelp.dll from the installation directory of Debugging Tools
for Windows to the directory where the example executable resides.
|