Sunday, September 2, 2007

How to list all the open handles?


Recently I had to get the list of all the handles open in a process. I searched on the web to find a good way to do it, and realized that most of the articles I found are wrong.

I guess this is because the documentation in "Windows NT/2000 Native API Reference" by Gary Nebbett is a little bit misleading.

Under the SystemHandleInformation class, the structure defined is:

typedef struct _SYSTEM_HANDLE_INFORMATION {
USHORT ProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


One could think that the buffer returned is actually a list of structures like this one. But this is not the case, it's actually returning a structure like this one:


typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
ULONG NumberOfHandles;
SYSTEM_HANDLE_INFORMATION Information[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;


Even though the description in the book is misleading, Gary Nebbett is not wrong. There is a remark saying: "The data returning to the SystemInformation buffer is a ULONG count of he number of handles followed immediately by an array of SYSTEM_HANDLE_INFORMATION".


There is another factor making this task a little bit more complex to achieve: The function is really picky about the buffer size.


Usually you can call the function with a NULL buffer and 0 for the size and then get back the size you need to allocate your buffer. This does not work here. The return value is 0xC0000004 : The specified information record length does not match the length required for the specified information class.


If you try with a SYSTEM_HANDLE_INFORMATION buffer, it won't work either. You need to pass to the function a buffer large enough to hold the number of handles and the first handle if you want to get the size needed back. This is a little bit weird.


Finally, the code:



// Get the number of handles on the system
DWORD buffer_size = 0;
SYSTEM_HANDLE_INFORMATION_EX temp_info;


NTSTATUS status = NtQuerySystemInformation(
SystemHandleInformation, &temp_info,
sizeof(temp_info), &buffer_size);


SYSTEM_HANDLE_INFORMATION_EX *system_handles =
(SYSTEM_HANDLE_INFORMATION_EX*)(new BYTE[buffer_size]);


status = NtQuerySystemInformation(SystemHandleInformation,
system_handles,
buffer_size, &buffer_size);


printf("nb of handles = %d", system_handles->NumberOfHandles);

1 comment:

Alex Ionescu said...

I think you/Gary may be using the wrong structures, FYI. Take a look at the NDK for the correct ones (the _EX version was added in Vista, but the sub-structure you're using is the NT4 one).

In Native land, it's very common to have to send the "Small" version of the structure first. FIELD_OFFSET is what you usually use for this. The idea is you want to query how many handles there are on the system (which is the minimum information the API will return), multiply this by the handle size, then make a new request.

Of course this seems stupid for this API since it does have a "required size" parameter, but some APIs don't and that's why the model works this way.

Be very careful however, it's very likely that between your initial call and the re-allocation and subsequent call, the number of handles changed, and the API fails again...

You should always use it in a while (TRUE) loop until the second call returns STATUS_SUCCESS;

And even then, don't do anything critical with that array -- always double-check the handle still exists.