Sysinternals Homepage
Forum Home Forum Home > Windows Discussions > Development
  New Posts New Posts RSS Feed - HOWTO: Enumerate handles
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

Topic ClosedHOWTO: Enumerate handles

 Post Reply Post Reply
Author
Message
wj32 View Drop Down
Senior Member
Senior Member
Avatar

Joined: 16 January 2009
Location: Australia
Status: Offline
Points: 1016
Direct Link To This Post Topic: HOWTO: Enumerate handles
    Posted: 07 May 2009 at 12:48pm
(This is a new version of Overview - Handle Enumeration)

"How do I enumerate handles/opened files?" is a common beginner question here. I'll try to expand on the first handle enumeration topic and provide a bit more information on how to get handle names, etc. Complete sample code in C is attached.

Step 1: Enumerating handles
Call NtQuerySystemInformation with SystemHandleInformation (16). This will give you a list of handles opened by every single process. Here are the definitions:

#define SystemHandleInformation 16

typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
    );

/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
    ULONG ProcessId;
    BYTE ObjectTypeNumber;
    BYTE Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
    ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
    SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


An unusual aspect of calling NtQuerySystemInformation with SystemHandleInformation is that if you supply a buffer which is too small, it returns STATUS_INFO_LENGTH_MISMATCH (0xc0000004) instead of giving you the correct buffer size in ReturnLength. This means you will have to guess the buffer size. A common technique is to call NtQuerySystemInformation in a loop until it succeeds with STATUS_SUCCESS (0), reallocating and doubling the buffer size each time it fails with STATUS_INFO_LENGTH_MISMATCH.

Step 2: Getting handle types and names
After you have the list of handles, you will probably want to get the types and names of the handles. There is no way to do this without duplicating the handle into your own process, so we can do that using DuplicateHandle (NOTE: in the source code I use NtDuplicateObject, but it's the same idea).

Handle types
Call NtQueryObject with ObjectTypeInformation (2). You will get this structure back:

typedef struct _OBJECT_TYPE_INFORMATION
{
    UNICODE_STRING TypeName;
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
    ULONG TotalPagedPoolUsage;
    ULONG TotalNonPagedPoolUsage;
    ULONG TotalNamePoolUsage;
    ULONG TotalHandleTableUsage;
    ULONG HighWaterNumberOfObjects;
    ULONG HighWaterNumberOfHandles;
    ULONG HighWaterPagedPoolUsage;
    ULONG HighWaterNonPagedPoolUsage;
    ULONG HighWaterNamePoolUsage;
    ULONG HighWaterHandleTableUsage;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    ULONG PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;


Processes
To get the "name" of a process, you can duplicate the handle into your own process with PROCESS_QUERY_INFORMATION access and call GetProcessId (or use NtQueryInformationProcess with ProcessBasicInformation if you prefer, since GetProcessId is only supported on XP SP1 and higher).

Threads
Same idea as with processes (except you use THREAD_QUERY_INFORMATION access), and you can call GetThreadId and GetProcessIdOfThread (again, you can also call NtQueryInformationThread with ThreadBasicInformation and use the ClientId).

Tokens
Again, you can duplicate the handle and use GetTokenInformation to get the username.

Files, Events, Mutants, other objects
To get the names of other objects, you must duplicate the handle and use NtQueryObject
with ObjectNameInformation (1) to get the name of the object. You will get a UNICODE_STRING back. IMPORTANT: NtQueryObject may hang on file handles pointing to named pipes. To fix this, do not query any file handles opened with an access (GrantedAccess) of 0x0012019f. This problem only appears for ObjectNameInformation, not ObjectTypeInformation. See the sample code for more information.

You will get filenames in native filename format (i.e. \Device\HarddiskVolume1\...). You can use QueryDosDevice to get mappings between DOS drive letters and device prefixes.

(Step 3: Closing remote handles)
To close handles opened by other processes, you simply call DuplicateHandle with
DUPLICATE_CLOSE_SOURCE (1) specified in the options parameter (it's documented on the MSDN page for DuplicateHandle, so go read it). You can specify NULL for the target process handle and target handle parameters. For example:

DuplicateHandle(handleToTheRemoteProcess, theRemoteHandle, NULL, NULL, 0, FALSE, 0x1);

Note: I will be making updates to this post, like on how to get this information from kernel-mode.

Sample code
uploads/26792/handles.zip


Edited by wj32 - 07 May 2009 at 12:55pm
PH, a free and open source process viewer.
Back to Top
molotov View Drop Down
Moderator Group
Moderator Group
Avatar

Joined: 04 October 2006
Status: Offline
Points: 17516
Direct Link To This Post Posted: 24 June 2009 at 11:38am
Please discuss this topic here:
Discussion: HOWTO: Enumerate handles

Daily affirmation:
net helpmsg 4006
Back to Top
 Post Reply Post Reply
  Share Topic   

Forum Jump Forum Permissions View Drop Down