29

Is there any way how to enumerate process with given PID in windows, and get list of all his opened handles(locked files, etc.)?

EDIT: I dont care about language. If it is in .NET, I'd be glad, if in WinApi (C), it won't hurt. If in something else, I think I can rewrite it :-)

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
nothrow
  • 15,882
  • 9
  • 57
  • 104

3 Answers3

29

I did a deep googling and found this article. This article gave a link to download source code:

I tried method in NtSystemInfoTest.cpp ( downloaded source code ) and it worked superbly.

void ListHandles( DWORD processID, LPCTSTR lpFilter )

The code has following declaimer:

// Written by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
// The source is free, but if you want to use it, mention my name and e-mail address
//
//////////////////////////////////////////////////////////////////////////////////////
//

I hope this helps you.

aJ.
  • 34,624
  • 22
  • 86
  • 128
  • Superb! It's exactly what I needed (and wasn't unable to google). Thanks. :-) – nothrow Apr 15 '09 at 08:40
  • 1
    Unfortunately, while this works, it still requires calling `NtQuerySystemInformation` which returns *all* handles that then need to be iterated and filtered by required PID. There's no way that I know of to ask the OS for the handles for just one process. – Bartek Banachewicz Dec 05 '18 at 09:11
  • this does not work when the handle is a pipe. NtQueryObject will hung forever. – vadim_hr May 17 '22 at 23:28
8

The command-line 'Handle' tool from Sysinternals does this, if you just want a tool. This won't help you if you're looking for a code solution, though.

Zac Thompson
  • 12,401
  • 45
  • 57
  • _Handle_'s GUI counterpart [Process Explorer](https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer) can also do this. _Find_ → _Find Handle or DLL_ menu brings up a dialog for this. Search path works only when drive letter is omitted (as mentioned in _Handle_'s documentation). – legends2k Nov 18 '22 at 10:24
7

Here is an example using ZwQueryProcessInformation from the DDK. The DDK is now known as the "WDK" and is available with MSDN. If you don't have MSDN, apparantly, you can also get it from here.

I haven't tried it, I just googled your question.

#include "ntdll.h"
#include <stdlib.h>
#include <stdio.h>
#include "ntddk.h"

#define DUPLICATE_SAME_ATTRIBUTES 0x00000004

#pragma comment(lib,"ntdll.lib")

BOOL EnablePrivilege(PCSTR name)
{
TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};
LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid);

HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);

AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof priv, 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;

CloseHandle(hToken);
return rv;
}

int main(int argc, char *argv[])
{
if (argc == 1) return 0;

ULONG pid = strtoul(argv[1], 0, 0);

EnablePrivilege(SE_DEBUG_NAME);

HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);

ULONG n = 0x1000;
PULONG p = new ULONG[n];

while (NT::ZwQuerySystemInformation(NT::SystemHandleInformation, p, n * sizeof *p, 0)
== STATUS_INFO_LENGTH_MISMATCH)

delete [] p, p = new ULONG[n *= 2];

NT::PSYSTEM_HANDLE_INFORMATION h = NT::PSYSTEM_HANDLE_INFORMATION(p + 1);

for (ULONG i = 0; i < *p; i++) {

if (h[i].ProcessId == pid) {
HANDLE hObject;

if (NT::ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &hObject,
0, 0, DUPLICATE_SAME_ATTRIBUTES)
!= STATUS_SUCCESS) continue;

NT::OBJECT_BASIC_INFORMATION obi;

NT::ZwQueryObject(hObject, NT::ObjectBasicInformation, &obi, sizeof obi, &n);

printf("%p %04hx %6lx %2x %3lx %3ld %4ld ",
h[i].Object, h[i].Handle, h[i].GrantedAccess,
int(h[i].Flags), obi.Attributes,
obi.HandleCount - 1, obi.PointerCount - 2);

n = obi.TypeInformationLength + 2;

NT::POBJECT_TYPE_INFORMATION oti = NT::POBJECT_TYPE_INFORMATION(new CHAR[n]);

NT::ZwQueryObject(hObject, NT::ObjectTypeInformation, oti, n, &n);

printf("%-14.*ws ", oti[0].Name.Length / 2, oti[0].Name.Buffer);

n = obi.NameInformationLength == 0
? MAX_PATH * sizeof (WCHAR) : obi.NameInformationLength;

NT::POBJECT_NAME_INFORMATION oni = NT::POBJECT_NAME_INFORMATION(new CHAR[n]);

NTSTATUS rv = NT::ZwQueryObject(hObject, NT::ObjectNameInformation, oni, n, &n);
if (NT_SUCCESS(rv))
printf("%.*ws", oni[0].Name.Length / 2, oni[0].Name.Buffer);

printf("\n");

CloseHandle(hObject);
}
}
delete [] p;

CloseHandle(hProcess);

return 0;
}
1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
  • Well, I googled it too, but I was unable to download DDK for Vista :-( So I thought, that there is some else solution (ProcessExplorer from sysinternals doesnt link ntdll at all) – nothrow Apr 09 '09 at 09:09
  • 1
    ProcessExplorer doesn't link statically to ntdll but it will load it on runtime. You can find it with a depends. – Shay Erlichmen Apr 11 '09 at 17:49
  • How do you work around this solution hanging if you're doing ZwQueryObject(.. ObjectNameInformation..) on a pipe with opened with SYNC_READ? – mrduclaw Aug 25 '10 at 06:05
  • 1
    @nothrow - Every process implicitly links with ntdll, it's part of the Windows loader. This is discussed in the Windows Internals book by Mark Russinovich, see Chapter 3 "Image Loader". – antiduh Nov 10 '18 at 05:55