locked
List open handles by a process RRS feed

  • Question

  • Hello everyone, for a long time I've been looking for a way to get a list of handles given a specific process. More in detail, I would like to write a function in C# that given as parameter a process, returns me a list of strings with all the names of the handles opened by that process: file names, registry key names, names of other processes to which the process passed as parameter is accessing, so I can see also (cycling all processes), if some other process is accessing mine. Doing some research, I saw that this is feasible by importing ntdll.dll and using the following methods (which I think are the same used in handle.exe of Sysinternals): NtQuerySystemInformation, NtDuplicateObject and NtQueryObject. The only problem is that I really have no idea where to start to do this. If anyone can help me, I'd really appreciate it.

    • Edited by C2002 Tuesday, July 28, 2020 1:26 PM
    Tuesday, July 28, 2020 1:06 PM

Answers

  • Is this doable? Yes using the PSAPI and equivalent. Is this efficient? Not really. Searching every process to see if they have a specific handle open is going to be very, very expensive. Besides the fact that you have to enumerate all the processes (some of which you won't have access to) and then all the handles of the process, you then have to query each process to get information about it (because a handle is an opaque structure so it is useless by itself). On my machine that I just turned on a couple of minutes ago I have 98K handles open across 178 processes. It is going to take a long time to enumerate all these. I don't think your solution is going to be feasible.

    But to answer your question the first thing I think of is just using Handle from SysInternals. You can programmatically call this to find specific handles which would save you all the effort. Note that your reference to NtQuerySystemInformation should be evaluated carefully as this function has been deprecated for years. It was never designed to be used directly and was deprecated so code would not rely on it.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:08 PM
  • You can create a single executable and use a separate process. In fact that is how Process Explorer works. Embed the console app as a resource. When your app runs extract to a temp folder and run it. This can be done in less than an hour in my opinion and may be a quick solution. Then take the time to figure out the Win32 calls (and all the interop structures you're going to need) to call the APIs directly. This is my recommendation.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:31 PM
  • Ok, let me look around and find the code you'll need. But I'll point out 2 things that still make this less than useful.

    1. If users are smart enough to block handles then nothing will stop them from blocking your app as well. Therefore there is nothing you can do to ensure that your process runs.

    2. To work around the explicit block of handles you simply save the embedded resource using a temporary filename instead. This happens all the time with installers. You might save it as aba3514.exe one time and 14asdfa562.exe the next. This makes it a lot harder to block.

    Nevertheless let me look for some code. It might be a little bit though.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:57 PM
  • A quick test enumerating all handles for all processes (very long...) that I adapted from old C++ code .

    To be improved...

    (add a button for the click)

    =>

    public partial class Form1 : Form
    {
        [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int ReturnLength);
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct SYSTEM_PROCESS_INFORMATION
        {
            public uint NextEntryOffset;
            public uint NumberOfThreads;
            public LARGE_INTEGER WorkingSetPrivateSize;
            public LARGE_INTEGER SpareLi2;
            public LARGE_INTEGER SpareLi3;
            public LARGE_INTEGER CreateTime;
            public LARGE_INTEGER UserTime;
            public LARGE_INTEGER KernelTime;
            public UNICODE_STRING ImageName;
            public int BasePriority;
            public int UniqueProcessId;
            public int InheritedFromUniqueProcessId;
            public uint HandleCount;
            public uint SessionId;
            public uint UniqueProcessKey;
            public uint PeakVirtualSize;
            public uint VirtualSize;
            public uint PageFaultCount;
            public uint PeakWorkingSetSize;
            public uint WorkingSetSize;
            public uint QuotaPeakPagedPoolUsage;
            public uint QuotaPagedPoolUsage;
            public uint QuotaPeakNonPagedPoolUsage;
            public uint QuotaNonPagedPoolUsage;
            public uint PagefileUsage;
            public uint PeakPagefileUsage;
            public uint PrivatePageCount;
            public LARGE_INTEGER ReadOperationCount;
            public LARGE_INTEGER WriteOperationCount;
            public LARGE_INTEGER OtherOperationCount;
            public LARGE_INTEGER ReadTransferCount;
            public LARGE_INTEGER WriteTransferCount;
            public LARGE_INTEGER OtherTransferCount;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        public struct LARGE_INTEGER
        {
            [FieldOffset(0)]
            public int LowPart;
    
            [FieldOffset(4)]
            public int HighPart;
    
            [FieldOffset(0)]
            public long QuadPart;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct UNICODE_STRING
        {
            public ushort Length;
            public ushort MaximumLength;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string Buffer;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct SYSTEM_HANDLE_INFORMATION
        {
            public uint ProcessId;
            public byte ObjectTypeNumber;
            public byte Flags;
            public ushort Handle;
            public IntPtr pObject;
            public int GrantedAccess;
        }
    
        public const int STATUS_SUCCESS = 0x0;
        public const int STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004);
    
        public enum SYSTEM_INFORMATION_CLASS
        {
            SystemBasicInformation,
            SystemProcessorInformation,
            SystemPerformanceInformation,
            SystemTimeOfDayInformation,
            SystemPathInformation,
            SystemProcessInformation,
            SystemCallCountInformation,
            SystemDeviceInformation,
            SystemProcessorPerformanceInformation,
            SystemFlagsInformation,
            SystemCallTimeInformation,
            SystemModuleInformation,
            SystemLocksInformation,
            SystemStackTraceInformation,
            SystemPagedPoolInformation,
            SystemNonPagedPoolInformation,
            SystemHandleInformation,
            SystemObjectInformation,
            SystemPageFileInformation,
            SystemVdmInstemulInformation,
            SystemVdmBopInformation,
            SystemFileCacheInformation,
            SystemPoolTagInformation,
            SystemInterruptInformation,
            SystemDpcBehaviorInformation,
            SystemFullMemoryInformation,
            SystemLoadGdiDriverInformation,
            SystemUnloadGdiDriverInformation,
            SystemTimeAdjustmentInformation,
            SystemSummaryMemoryInformation,
            SystemMirrorMemoryInformation,
            SystemPerformanceTraceInformation,
            SystemObsolete0,
            SystemExceptionInformation,
            SystemCrashDumpStateInformation,
            SystemKernelDebuggerInformation,
            SystemContextSwitchInformation,
            SystemRegistryQuotaInformation,
            SystemExtendServiceTableInformation,
            SystemPrioritySeperation,
            SystemVerifierAddDriverInformation,
            SystemVerifierRemoveDriverInformation,
            SystemProcessorIdleInformation,
            SystemLegacyDriverInformation,
            SystemCurrentTimeZoneInformation,
            SystemLookasideInformation,
            SystemTimeSlipNotification,
            SystemSessionCreate,
            SystemSessionDetach,
            SystemSessionInformation,
            SystemRangeStartInformation,
            SystemVerifierInformation,
            SystemVerifierThunkExtend,
            SystemSessionProcessInformation,
            SystemLoadGdiDriverInSystemSpace,
            SystemNumaProcessorMap,
            SystemPrefetcherInformation,
            SystemExtendedProcessInformation,
            SystemRecommendedSharedDataAlignment,
            SystemComPlusPackage,
            SystemNumaAvailableMemory,
            SystemProcessorPowerInformation,
            SystemEmulationBasicInformation,
            SystemEmulationProcessorInformation,
            SystemExtendedHandleInformation,
            SystemLostDelayedWriteInformation,
            SystemBigPoolInformation,
            SystemSessionPoolTagInformation,
            SystemSessionMappedViewInformation,
            SystemHotpatchInformation,
            SystemObjectSecurityMode,
            SystemWatchdogTimerHandler,
            SystemWatchdogTimerInformation,
            SystemLogicalProcessorInformation,
            SystemWow64SharedInformationObsolete,
            SystemRegisterFirmwareTableInformationHandler,
            SystemFirmwareTableInformation,
            SystemModuleInformationEx,
            SystemVerifierTriageInformation,
            SystemSuperfetchInformation,
            SystemMemoryListInformation,
            SystemFileCacheInformationEx,
            SystemThreadPriorityClientIdInformation,
            SystemProcessorIdleCycleTimeInformation,
            SystemVerifierCancellationInformation,
            SystemProcessorPowerInformationEx,
            SystemRefTraceInformation,
            SystemSpecialPoolInformation,
            SystemProcessIdInformation,
            SystemErrorPortInformation,
            SystemBootEnvironmentInformation,
            SystemHypervisorInformation,
            SystemVerifierInformationEx,
            SystemTimeZoneInformation,
            SystemImageFileExecutionOptionsInformation,
            SystemCoverageInformation,
            SystemPrefetchPatchInformation,
            SystemVerifierFaultsInformation,
            SystemSystemPartitionInformation,
            SystemSystemDiskInformation,
            SystemProcessorPerformanceDistribution,
            SystemNumaProximityNodeInformation,
            SystemDynamicTimeZoneInformation,
            SystemCodeIntegrityInformation,
            SystemProcessorMicrocodeUpdateInformation,
            SystemProcessorBrandString,
            SystemVirtualAddressInformation,
            SystemLogicalProcessorAndGroupInformation,
            SystemProcessorCycleTimeInformation,
            SystemStoreInformation,
            SystemRegistryAppendString,
            SystemAitSamplingValue,
            SystemVhdBootInformation,
            SystemCpuQuotaInformation,
            SystemNativeBasicInformation,
            SystemErrorPortTimeouts,
            SystemLowPriorityIoInformation,
            SystemBootEntropyInformation,
            SystemVerifierCountersInformation,
            SystemPagedPoolInformationEx,
            SystemSystemPtesInformationEx,
            SystemNodeDistanceInformation,
            SystemAcpiAuditInformation,
            SystemBasicPerformanceInformation,
            SystemQueryPerformanceCounterInformation,
            SystemSessionBigPoolInformation,
            SystemBootGraphicsInformation,
            SystemScrubPhysicalMemoryInformation,
            SystemBadPageInformation,
            SystemProcessorProfileControlArea,
            SystemCombinePhysicalMemoryInformation,
            SystemEntropyInterruptTimingInformation,
            SystemConsoleInformation,
            SystemPlatformBinaryInformation,
            SystemThrottleNotificationInformation,
            SystemHypervisorProcessorCountInformation,
            SystemDeviceDataInformation,
            SystemDeviceDataEnumerationInformation,
            SystemMemoryTopologyInformation,
            SystemMemoryChannelInformation,
            SystemBootLogoInformation,
            SystemProcessorPerformanceInformationEx,
            SystemSpare0,
            SystemSecureBootPolicyInformation,
            SystemPageFileInformationEx,
            SystemSecureBootInformation,
            SystemEntropyInterruptTimingRawInformation,
            SystemPortableWorkspaceEfiLauncherInformation,
            SystemFullProcessInformation,
            MaxSystemInfoClass // = 0x0095
        }
    
        [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int NtQueryObject(IntPtr Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, IntPtr ObjectInformation, uint Length, ref uint ReturnLength);
    
        public enum OBJECT_INFORMATION_CLASS
        {
            ObjectBasicInformation,
            ObjectNameInformation,
            ObjectTypeInformation,
            ObjectTypesInformation,
            ObjectHandleFlagInformation,
            ObjectSessionInformation
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct GENERIC_MAPPING
        {
            public int GenericRead;
            public int GenericWrite;
            public int GenericExecute;
            public int GenericAll;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_TYPE_INFORMATION
        {
            public UNICODE_STRING TypeName;
            public int TotalNumberOfObjects;
            public int TotalNumberOfHandles;
            public int TotalPagedPoolUsage;
            public int TotalNonPagedPoolUsage;
            public int TotalNamePoolUsage;
            public int TotalHandleTableUsage;
            public int HighWaterNumberOfObjects;
            public int HighWaterNumberOfHandles;
            public int HighWaterPagedPoolUsage;
            public int HighWaterNonPagedPoolUsage;
            public int HighWaterNamePoolUsage;
            public int HighWaterHandleTableUsage;
            public int InvalidAttributes;
            public GENERIC_MAPPING GenericMapping;
            public int ValidAccessMask;
            public byte SecurityRequired;
            public byte MaintainHandleCount;
            public int PoolType;
            public int DefaultPagedPoolCharge;
            public int DefaultNonPagedPoolCharge;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct OBJECT_NAME_INFORMATION
        {
            public UNICODE_STRING Name;
        }
    
        public const int DUPLICATE_CLOSE_SOURCE = 0x1;
        public const int DUPLICATE_SAME_ACCESS = 0x2;
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, ref IntPtr lpTargetHandle, int dwDesiredAccess, bool bInheritHandle, int dwOptions);
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetCurrentProcess();
    
        public const int SYNCHRONIZE = 0x100000;
        public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
    
        public const int PROCESS_VM_READ = (0x10);
        public const int PROCESS_VM_WRITE = (0x20);
        public const int PROCESS_DUP_HANDLE = (0x40);
        public const int PROCESS_CREATE_PROCESS = (0x80);
        public const int PROCESS_SET_QUOTA = (0x100);
        public const int PROCESS_SET_INFORMATION = (0x200);
        public const int PROCESS_QUERY_INFORMATION = (0x400);
        public const int PROCESS_SUSPEND_RESUME = (0x800);
        public const int PROCESS_QUERY_LIMITED_INFORMATION = (0x1000);
        public const int PROCESS_SET_LIMITED_INFORMATION = (0x2000);
        public const long PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF);
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
        
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr hObject);
    
    
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            int nStatus = STATUS_SUCCESS;
            IntPtr pLargeBuffer = IntPtr.Zero;
            int nCbLargeBuffer = 64 * 1024;
            int nReturnLength = 0;
    
            for (;;)
            {
                pLargeBuffer = Marshal.AllocHGlobal(nCbLargeBuffer);
                nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);
                if ((nStatus == STATUS_SUCCESS))
                {
                    break;
                }
                if ((nStatus == STATUS_INFO_LENGTH_MISMATCH))
                {
                    Marshal.FreeHGlobal(pLargeBuffer);
                    nCbLargeBuffer += 8192;
                }
                else
                {
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
            }
    
            int nCount = System.Convert.ToInt32(Marshal.PtrToStructure(pLargeBuffer, typeof(int)));
            IntPtr pLargeBufferNew = IntPtr.Zero;
            pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int));
            SYSTEM_HANDLE_INFORMATION pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
            for (int nIndex = 0; nIndex <= nCount; nIndex++)
            {
                pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));
                pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
     
                IntPtr hDup = IntPtr.Zero;
                IntPtr hProcess = OpenProcess(PROCESS_DUP_HANDLE, true, pHandleInfo.ProcessId);
                if (hProcess != IntPtr.Zero)
                {         
                    bool bReturn = DuplicateHandle(hProcess, (IntPtr)pHandleInfo.Handle, GetCurrentProcess(), ref hDup, 0, false, DUPLICATE_SAME_ACCESS);
                    if (hDup != IntPtr.Zero)
                    {
                        IntPtr pObjectType = IntPtr.Zero;
                        var oti = new OBJECT_TYPE_INFORMATION();
                        uint nLength = 0x1000;
                        pObjectType = Marshal.AllocHGlobal((int)nLength);
                        while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                        {
                            Marshal.FreeHGlobal(pObjectType);
                            pObjectType = Marshal.AllocHGlobal((int)nLength);
                        }
                        oti = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(pObjectType, typeof(OBJECT_TYPE_INFORMATION));
                        Marshal.FreeHGlobal(pObjectType);
    
                        string sName = "none";
                        if (pHandleInfo.GrantedAccess != 0x12019F && pHandleInfo.GrantedAccess != 0x120189)
                        {
                            IntPtr pObjectName = IntPtr.Zero;
                            var oni = new OBJECT_NAME_INFORMATION();
                            nLength = 0x1000;
                            pObjectName = Marshal.AllocHGlobal((int)nLength);
                            while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectNameInformation, pObjectName, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                            {
                                Marshal.FreeHGlobal(pObjectName);
                                pObjectName = Marshal.AllocHGlobal((int)nLength);
                            }
                            oni = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(pObjectName, typeof(OBJECT_NAME_INFORMATION));
                            Marshal.FreeHGlobal(pObjectName);
                            sName = oni.Name.Buffer;
                        }
    
                        Console.WriteLine("pid = {0} - Handle : 0x{1:X} - Type : {2} - Name : {3}", pHandleInfo.ProcessId, pHandleInfo.Handle, oti.TypeName.Buffer, sName);
                        CloseHandle(hDup);
                    }
                   CloseHandle(hProcess);
                }
            }
        }
    }

    • Marked as answer by C2002 Thursday, July 30, 2020 11:29 AM
    • Unmarked as answer by C2002 Friday, July 31, 2020 2:31 PM
    • Marked as answer by C2002 Friday, July 31, 2020 2:31 PM
    Tuesday, July 28, 2020 3:16 PM
  • You have to wrap each process in a try-catch. There are processes that you do not have privileges to even if admin. It will crash with a security exception in those cases.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:04 PM
  • Each process has to be try-catch separately. Your app will get all processes whether you have access to them or not. Then you will trigger a call to get data and it'll blow up. You need to wrap each iteration of the loop in a try-catch. Of course if you gave us the exception that occurs it would help narrow down if this is the problem.

    //For loop expression looks wrong in the original by the way
    for (int nIndex = 0; nIndex < nCount; ++nIndex)
    {
       try
       {
       } catch
       { /* ignore this process */ }
    }

    Note that the for loop second expression looks wrong. I think it should be < but I didn't look at how `nCount` is calculated.

    Also it is possible to blow up while enumerating the handles so you might want a try-catch within the while loop as well.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:18 PM
  • Okay, so I tried it, but after processing a large number of handles, the program crashes. I even tried running it as an administrator.

    At which line of code ?
    Which error/exception is returned ?

    I let it enumerate  handles for ~10 minutes and I could not make it crash

    (compiled with "Any CPU", on Windows 10 64-bit, .NET 4.7.2)

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:23 PM

  • But now the problem is something else. That is, it lists all the handles including a process (the game I'd like to protect), but it doesn't tell me the name of this process, so I can't know if it's really going on there.


    Just use APIs like QueryFullProcessImageName

    to get the process name

            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool QueryFullProcessImageName(IntPtr hProcess, int dwFlags, StringBuilder lpExeName, ref uint lpdwSize);

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:34 PM
  • Are you calling this on a UI thread? That isn't going to work out. You blocked the UI so long that it caused timeout errors in a COM object you seem to be using. You need to move this logic to a separate thread (possibly an async task) so that it doesn't freeze the UI thread.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:47 PM
  • Stops or throws an exception? Please post your updated code including how you're calling it.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:11 PM
  • How do you know it stops? Are you listening for the completion event? Are you printing out UI updates in the report progress handler? Have you stepped through the DoWork handler to see what it is doing?

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:36 PM
  • Possible causes:

    1) The code finishes and a bug is preventing you from finding the handle you want. Step through the code to debug this.

    2) Your output logic is wrong. Please post the relevant code that runs inside DoWork handler that does your output.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:52 PM
  • The only output line in that original code was a call to Console.WriteLine which isn't applicable to Winforms apps. You don't have a UI element that is going to be updated in your UI with the output from this method?

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:01 PM
  • Got it. So does it run for a fixed period of time and then stop or does it simply stop. Simply stopping doesn't make sense unless there is an exception (and the original code doesn't have any error handling you and only provided snippets of your error handling version). Wrapping the entire function in a try-catch and writing out the exception will help identify any exception errors.

    If there are no exceptions then the code must be done and it didn't find anything. I would recommend that you start up the process that you're looking for, set a conditional breakpoint inside the process loop function to break when the given process ID is found and then step through the remaining code to identify why it isn't returning a result.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:09 PM
  • FYI since it appears that all you need the process for is the handle you can also simply use Process.GetProcesses from .NET to get all the processes. This gives you the name automatically (but note that security prevents you from reading any properties of a process so make sure it is in a try-catch). Given the Process object you have the handle needed for other calls. Note that I'm not sure if this handle works in the other system calls but for other OS calls I've never had an issue. This might solve your current problem.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:34 PM
  • I tried, but it still won't return any names.

    Ah sorry, I thought you wanted the process name from the current PID....

    Then you can use NtQueryInformationProcess and ProcessBasicInformation to get the PID to identify the process (from hDup)

    I just tested but it only worked as Admin (I added a Manifest)

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:38 PM
  • This works for me, as Admin =>

    PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
    nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
    if (nStatus == 0)
    {
        System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
        string sProcName = proc.ProcessName;
    
    } 

    with :

    [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]                                                                                                                                 
    public static extern int NtQueryInformationProcess(IntPtr ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PROCESS_BASIC_INFORMATION info, int ProcessInformationLength, int[] ReturnLength);
    
    [StructLayout(LayoutKind.Sequential)]
    public class PROCESS_BASIC_INFORMATION
    {
        public int ExitStatus = 0;
        public IntPtr PebBaseAddress = (IntPtr)0;
        public IntPtr AffinityMask = (IntPtr)0;
        public int BasePriority = 0;
        public IntPtr UniqueProcessId = (IntPtr)0;
        public IntPtr InheritedFromUniqueProcessId = (IntPtr)0;
    }
                
    public enum PROCESSINFOCLASS                                                                    
    {                                                                                        
        ProcessBasicInformation,                                                             
        ProcessQuotaLimits,                                                                  
        ProcessIoCounters,                                                                   
        ProcessVmCounters,                                                                   
        ProcessTimes,                                                                        
        ProcessBasePriority,                                                                 
        ProcessRaisePriority,                                                                
        ProcessDebugPort,                                                                    
        ProcessExceptionPort,                                                                
        ProcessAccessToken,                                                                  
        ProcessLdtInformation,                                                               
        ProcessLdtSize,                                                                      
        ProcessDefaultHardErrorMode,                                                         
        ProcessIoPortHandlers,          // Note: this is kernel mode only                    
        ProcessPooledUsageAndLimits,                                                         
        ProcessWorkingSetWatch,                                                              
        ProcessUserModeIOPL,                                                                 
        ProcessEnableAlignmentFaultFixup,                                                    
        ProcessPriorityClass,                                                                
        ProcessWx86Information,                                                              
        ProcessHandleCount,                                                                  
        ProcessAffinityMask,                                                                 
        ProcessPriorityBoost,                                                                
        ProcessDeviceMap,                                                                    
        ProcessSessionInformation,                                                           
        ProcessForegroundInformation,                                                        
        ProcessWow64Information,                                                             
        ProcessImageFileName,                                                                
        ProcessLUIDDeviceMapsEnabled,                                                        
        ProcessBreakOnTermination,                                                           
        ProcessDebugObjectHandle,                                                            
        ProcessDebugFlags,                                                                   
        ProcessHandleTracing,                                                                
        ProcessUnusedSpare1,                                                                 
        ProcessExecuteFlags,                                                                 
        ProcessResourceManagement,                                                           
        ProcessCookie,                                                                       
        ProcessImageInformation,                                                             
        MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
    }    

    • Marked as answer by C2002 Thursday, July 30, 2020 11:30 AM
    Tuesday, July 28, 2020 8:09 PM
  • The crash/freeze is maybe because of pipes

    That's why I added the test on GrantedAccess, but the second one could be wrong

    You can find similar tests in several posts, like at  http://espresso3389.hatenablog.com/entry/2014/12/05/031051

    with

     if (shi.GrantedAccess == 0x0012019f   // seems mandatory (named pipes)
                  || shi.GrantedAccess == 0x001a019f   // blocking named pipe (not a file anyways)

    "

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 8:39 PM
  • As you wrote "I've been looking for a way to get a list of handles given a specific process."

    can't you just filter by the PID of this process, instead of scanning all PIDs ?

    • Marked as answer by C2002 Friday, July 31, 2020 2:37 PM
    Friday, July 31, 2020 2:36 PM
  • I'm not sure I understood, but if I want for example all open handles on Notepad only, I will do :

    System.Diagnostics.Process[] processNotepad = System.Diagnostics.Process.GetProcessesByName("notepad");
    int pIdNotepad = -1;
    if (processNotepad.Count() > 0)
        pIdNotepad = processNotepad[0].Id;

    then in the loop, I add a test on Notepad PID :

    for (int nIndex = 0; nIndex <= nCount; nIndex++)
    {
    	pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));                                                              
    	pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
            // Filter on Notepad                                                                                                              
    	if (pIdNotepad != -1 && pHandleInfo.ProcessId == pIdNotepad)                                                        
    	{  
    		// all the code ...  
    	}  
    }  

    • Marked as answer by C2002 Friday, July 31, 2020 4:04 PM
    Friday, July 31, 2020 3:14 PM
  • But I don't see the filter on the PID

    Listing just the handles of a unique PID is fast

    • Marked as answer by C2002 Friday, July 31, 2020 7:29 PM
    Friday, July 31, 2020 6:03 PM
  • I don't understand how it can be slow to list the handles just for the given process/PID

    When I test on Notepad, it takes less than 1 second, with a few dozens of handles, as all other PIDs are skipped

    • Marked as answer by C2002 Friday, July 31, 2020 7:29 PM
    Friday, July 31, 2020 7:25 PM
  • I tried to insert as PID 37976 and it took 46 minutes to list the handles.

    46 mn for 1 process ?!!!

    For Notepad, I get those handles (140), in 1-2 seconds (and most of the time is taken by Console.WriteLine)

    It is nearly as fast as handles listed by Process Explorer, which returns less handles

    (I added the process name from QueryFullProcessImageName)

    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x10 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x14 - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x18 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x24 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x34 - Type : Directory - Name : \KnownDlls
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x40 - Type : File - Name : \Device\HarddiskVolume4\Users\Christian
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x58 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x5C - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x60 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x64 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x68 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x6C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x70 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x74 - Type : File - Name : \Device\HarddiskVolume4\Program Files\WindowsApps\Microsoft.LanguageExperiencePackfr-FR_18362.26.83.0_neutral__8wekyb3d8bbwe\Windows\System32\fr-FR\notepad.exe.mui
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x7C - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Versions
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8C - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x90 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x94 - Type : IoCompletion - Name : 
    
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x98 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x9C - Type : Desktop - Name : \Default
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA0 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA4 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xAC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB0 - Type : File - Name : \Device\CNG
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB4 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB8 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xBC - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Ole
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC4 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings\Software\Microsoft
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC8 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xCC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xDC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xEC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF8 - Type : Directory - Name : \Sessions\1\BaseNamedObjects
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x128 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x12C - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x130 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x138 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x13C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x140 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x148 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x150 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x154 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x158 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x15C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x160 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x164 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x168 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x170 - Type : Event - Name : \KernelObjects\MaximumCommitCondition
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x174 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x178 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x17C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x180 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x188 - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x190 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x194 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x198 - Type : File - Name : \Device\HarddiskVolume4\Windows\SystemResources\notepad.exe.mun
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x19C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1A0 - Type : Section - Name : \Windows\Theme3372165587
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1AC - Type : Section - Name : \Sessions\1\Windows\Theme1817300183
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B0 - Type : File - Name : \Device\HarddiskVolume4\Windows\Fonts\StaticCache.dat
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B4 - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x200 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Session Manager
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x204 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x208 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x210 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x214 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\HwOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x218 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\ProviderOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x21C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x220 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x268 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x26C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x27C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x280 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x284 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x288 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x28C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x294 - Type : ALPC Port - Name : \RPC Control\OLEF8D468628B9656595E6360AB99DE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x298 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x29C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A4 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A8 - Type : File - Name : \Device\HarddiskVolume4\Windows\Registration\R000000000015.clb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2AC - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B0 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B4 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom\ClassIndex
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2BC - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C0 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C8 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2CC - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2D0 - Type : File - Name : \Device\DeviceApi
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x300 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x304 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Ids
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x308 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x30C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x314 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x318 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x31C - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x320 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x324 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x328 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x32C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x330 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x334 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x338 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x350 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x354 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x358 - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x35C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x360 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x364 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x368 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x36C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x370 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x374 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x378 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x37C - Type : IoCompletionReserve - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x380 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x384 - Type : ALPC Port - Name : \BaseNamedObjects\[CoreUI]-PID(4912)-TID(31772) 60e8da57-b536-4a70-a860-3a3f442cd252
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x388 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x390 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A4 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A8 - Type : Thread - Name : 



    • Edited by Castorix31 Friday, July 31, 2020 9:19 PM
    • Marked as answer by C2002 Friday, July 31, 2020 9:28 PM
    Friday, July 31, 2020 9:15 PM
  • I made a basic Process Viewer listing Handles, with a few changes  :

    It is only slow in Debug, but OK in Release (not as fast as Process Explorer, which uses a Driver)

    You can test the executable : CSharp_NtQuerySystemInformation2_exe.zip

    If it is not slow on your PCs, I will post the source, otherwise, it is useless...

    • Marked as answer by C2002 Monday, August 3, 2020 12:48 PM
    Monday, August 3, 2020 9:45 AM
  • The main function : GetHandlesFromPID

    =>

    (it mimics the "C++ way" and can certainly be improved/optimized)

    public class HandleClass
    {
        public string Handle { get; set; }
        public string Type { get; set; }
        public string Name { get; set; }
    }
    
    
    public List<HandleClass> GetHandlesFromPID(int nPID)
    { 
        List<HandleClass> handleList = new List<HandleClass>();
    
        int nStatus = STATUS_SUCCESS;
        IntPtr pLargeBuffer = IntPtr.Zero;
        int nCbLargeBuffer = 64 * 1024;
        int nReturnLength = 0;
        for (;;)
        {
            pLargeBuffer = Marshal.AllocHGlobal(nCbLargeBuffer);
            //nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);
            nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);                
            if ((nStatus == STATUS_SUCCESS))
            {
                break;
            }
            if ((nStatus == STATUS_INFO_LENGTH_MISMATCH))
            {
                Marshal.FreeHGlobal(pLargeBuffer);
                //nCbLargeBuffer += 8192;
                nCbLargeBuffer += nReturnLength;
            }
            else
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }
    
        int nCount = System.Convert.ToInt32(Marshal.PtrToStructure(pLargeBuffer, typeof(int)));
        IntPtr pLargeBufferNew = IntPtr.Zero;
        //pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int));
        pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int))*2;
        SYSTEM_HANDLE_INFORMATION_EX pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
        for (int nIndex = 0; nIndex <= nCount; nIndex++)
        {
            pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION_EX));
            pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
            if (nPID != -1 && pHandleInfo.UniqueProcessId == nPID)
            {
                string sType = "";
                string sName = "";
                IntPtr hDup = IntPtr.Zero;
                IntPtr hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, pHandleInfo.UniqueProcessId);
                if (hProcess != IntPtr.Zero)
                {
                    bool bReturn = DuplicateHandle(hProcess, (IntPtr)pHandleInfo.HandleValue, GetCurrentProcess(), ref hDup, 0, false, DUPLICATE_SAME_ACCESS);
                    if (hDup != IntPtr.Zero)
                    {
                        IntPtr pObjectType = IntPtr.Zero;
                        var oti = new OBJECT_TYPE_INFORMATION();
                        uint nLength = 0x1000;
                        pObjectType = Marshal.AllocHGlobal((int)nLength);
                        while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
                        //while (NtQueryObject((IntPtr)pHandleInfo.Handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                        {
                            Marshal.FreeHGlobal(pObjectType);
                            pObjectType = Marshal.AllocHGlobal((int)nLength);
                        }
                        oti = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(pObjectType, typeof(OBJECT_TYPE_INFORMATION));
                        sType = oti.TypeName.Buffer;
                        Marshal.FreeHGlobal(pObjectType);
    
                        if (sType == "Directory" || sType == "File" || sType == "Section" || sType == "Key" || sType == "WindowStation"
                            || sType == "Desktop" || sType == "Semaphore" || sType == "Mutant")
                        {
                            int nTId;
                            HTT htt = new HTT();
                            htt.handle = hDup;
                            IntPtr pHTT = Marshal.AllocHGlobal(Marshal.SizeOf(htt));
                            Marshal.StructureToPtr(htt, pHTT, false);
                            IntPtr hThread = CreateThread(IntPtr.Zero, 0, pThreadProc, pHTT, 0, out nTId);
                            if (WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT)
                            {
                                TerminateThread(hThread, 0);
                                sName = "<Locked>";
                            }
                            else
                            {
                                var httret = (HTT)Marshal.PtrToStructure(pHTT, typeof(HTT));
                                sName = httret.txt;
                            }
                            Marshal.FreeHGlobal(pHTT);
                        }
    
                        if (sType == "Process" && (sName == "" || sName == null))
                        {
                            PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                            nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
                            if (nStatus == 0)
                            {
                                //System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
                                //string sProcName = proc.ProcessName;
                                IntPtr hProcessForName = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, (uint)pbi.UniqueProcessId);
                                if (hProcessForName != IntPtr.Zero)
                                {
                                    uint nSize = 260;
                                    StringBuilder sProcessImageName = new StringBuilder((int)nSize);
                                    QueryFullProcessImageName(hProcessForName, 0, sProcessImageName, ref nSize);
                                    sName = sProcessImageName.ToString();
                                    CloseHandle(hProcessForName);
                                }
                                else
                                {
                                    int nError = Marshal.GetLastWin32Error();
                                }
                            }
                        }
                        CloseHandle(hDup);                           
                    }
                    else
                    {
                        int nError = Marshal.GetLastWin32Error();
                        if (nError == 5)
                            sType = "<Access denied>";
                        else
                        {
                          // ERROR_NOT_SUPPORTED  50(0x32)
                        }
                    }
                    CloseHandle(hProcess);
                }
                else
                {
                    int nError = Marshal.GetLastWin32Error();
                    if (nError == 5)
                        sType = "<Access denied>";
                }
    
                if (sType != "")
                { 
                    HandleClass handle = new HandleClass();
                    handle.Handle = string.Format("0x{0:x2}", pHandleInfo.HandleValue);
                    handle.Type = sType;
                    handle.Name = sName;
                    handleList.Add(handle);
                }
            }
        }
        Marshal.FreeHGlobal(pLargeBuffer);         
        return handleList;
    }  

    Declarations :

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct SYSTEM_HANDLE_INFORMATION_EX                      
    {                                                               
        public IntPtr Object;                                       
        public uint UniqueProcessId;                                
        public uint HandleValue;                                    
        public uint GrantedAccess;                                  
        public ushort CreatorBackTraceIndex;                        
        public ushort ObjectTypeIndex;                              
        public uint HandleAttributes;                               
        public uint Reserved;                                       
    }
            
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                                                                                    
    public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress,
        IntPtr lpParameter, int dwCreationFlags, out int lpThreadId);                                           
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);                           
                                                                                                        
    public const int WAIT_TIMEOUT = 258;                                                                        
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern bool TerminateThread(IntPtr hThread, int dwExitCode); 
    
    [StructLayout(LayoutKind.Sequential)]
    public struct HTT
    {
        public IntPtr handle;
        public string txt;
    }
    
    private delegate int PTHREAD_START_ROUTINE(IntPtr lpParameter);
    private static readonly PTHREAD_START_ROUTINE pThreadStartRoutine = ThreadProc;
    private static readonly IntPtr pThreadProc = Marshal.GetFunctionPointerForDelegate(pThreadStartRoutine);
    
    private static int ThreadProc(IntPtr lpParameter)
    {
        var htt = (HTT)Marshal.PtrToStructure(lpParameter, typeof(HTT));
        IntPtr pObjectName = IntPtr.Zero;
        var oni = new OBJECT_NAME_INFORMATION();
        uint nLength = 0x1000;
        pObjectName = Marshal.AllocHGlobal((int)nLength);
        while (NtQueryObject(htt.handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, pObjectName, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
        {
            Marshal.FreeHGlobal(pObjectName);
            pObjectName = Marshal.AllocHGlobal((int)nLength);
        }
        oni = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(pObjectName, typeof(OBJECT_NAME_INFORMATION));
        Marshal.FreeHGlobal(pObjectName);
        htt.txt = oni.Name.Buffer;
        Marshal.StructureToPtr(htt, lpParameter, false);
        return 0;            
    } 

    • Marked as answer by C2002 Monday, August 3, 2020 2:26 PM
    Monday, August 3, 2020 2:00 PM

All replies

  • Is this doable? Yes using the PSAPI and equivalent. Is this efficient? Not really. Searching every process to see if they have a specific handle open is going to be very, very expensive. Besides the fact that you have to enumerate all the processes (some of which you won't have access to) and then all the handles of the process, you then have to query each process to get information about it (because a handle is an opaque structure so it is useless by itself). On my machine that I just turned on a couple of minutes ago I have 98K handles open across 178 processes. It is going to take a long time to enumerate all these. I don't think your solution is going to be feasible.

    But to answer your question the first thing I think of is just using Handle from SysInternals. You can programmatically call this to find specific handles which would save you all the effort. Note that your reference to NtQuerySystemInformation should be evaluated carefully as this function has been deprecated for years. It was never designed to be used directly and was deprecated so code would not rely on it.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:08 PM
  • I thank you for your immediate response, but using Sysinternals Handle is not good in my case because my intention is to create a single executable that has the function of anticheat for a game, and then each player will have to use. What I would like my executable to do is something similar to searching for handles that is present in Sysinternals Process Explorer or other programs like Process Hacker, where I look for the name of the executable of the game and I find the handles opened by other programs on the game, so I can determine if something is wrong.

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    • Unmarked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:17 PM
  • You can create a single executable and use a separate process. In fact that is how Process Explorer works. Embed the console app as a resource. When your app runs extract to a temp folder and run it. This can be done in less than an hour in my opinion and may be a quick solution. Then take the time to figure out the Win32 calls (and all the interop structures you're going to need) to call the APIs directly. This is my recommendation.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:31 PM
  • I've already tried this solution, but during the search some users were doing everything to stop Handle execution and as a result you couldn't know if they were using third-party programs and since it's running a program external to mine, I can't know if an antivirus or something else is blocking it and so I can't take any action on the user. For this reason I wanted help to directly implement these functions in my program.
    Tuesday, July 28, 2020 2:50 PM
  • Ok, let me look around and find the code you'll need. But I'll point out 2 things that still make this less than useful.

    1. If users are smart enough to block handles then nothing will stop them from blocking your app as well. Therefore there is nothing you can do to ensure that your process runs.

    2. To work around the explicit block of handles you simply save the embedded resource using a temporary filename instead. This happens all the time with installers. You might save it as aba3514.exe one time and 14asdfa562.exe the next. This makes it a lot harder to block.

    Nevertheless let me look for some code. It might be a little bit though.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:28 PM
    Tuesday, July 28, 2020 2:57 PM
  • In the meantime I thank you for all the help you're giving me, also regarding point 1 I can always know if my process is started because it updates a database, and if the user continues to be connected but the database is no longer updated it means that my process has been closed and consequently the connection with the server is closed. Instead as for point 2, I already tried this too but they still managed to close it because some users had created a program that cycled all the processes looking for this (verifying the digital signature) and closed it.
    Tuesday, July 28, 2020 3:07 PM
  • A quick test enumerating all handles for all processes (very long...) that I adapted from old C++ code .

    To be improved...

    (add a button for the click)

    =>

    public partial class Form1 : Form
    {
        [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int ReturnLength);
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct SYSTEM_PROCESS_INFORMATION
        {
            public uint NextEntryOffset;
            public uint NumberOfThreads;
            public LARGE_INTEGER WorkingSetPrivateSize;
            public LARGE_INTEGER SpareLi2;
            public LARGE_INTEGER SpareLi3;
            public LARGE_INTEGER CreateTime;
            public LARGE_INTEGER UserTime;
            public LARGE_INTEGER KernelTime;
            public UNICODE_STRING ImageName;
            public int BasePriority;
            public int UniqueProcessId;
            public int InheritedFromUniqueProcessId;
            public uint HandleCount;
            public uint SessionId;
            public uint UniqueProcessKey;
            public uint PeakVirtualSize;
            public uint VirtualSize;
            public uint PageFaultCount;
            public uint PeakWorkingSetSize;
            public uint WorkingSetSize;
            public uint QuotaPeakPagedPoolUsage;
            public uint QuotaPagedPoolUsage;
            public uint QuotaPeakNonPagedPoolUsage;
            public uint QuotaNonPagedPoolUsage;
            public uint PagefileUsage;
            public uint PeakPagefileUsage;
            public uint PrivatePageCount;
            public LARGE_INTEGER ReadOperationCount;
            public LARGE_INTEGER WriteOperationCount;
            public LARGE_INTEGER OtherOperationCount;
            public LARGE_INTEGER ReadTransferCount;
            public LARGE_INTEGER WriteTransferCount;
            public LARGE_INTEGER OtherTransferCount;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        public struct LARGE_INTEGER
        {
            [FieldOffset(0)]
            public int LowPart;
    
            [FieldOffset(4)]
            public int HighPart;
    
            [FieldOffset(0)]
            public long QuadPart;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct UNICODE_STRING
        {
            public ushort Length;
            public ushort MaximumLength;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string Buffer;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct SYSTEM_HANDLE_INFORMATION
        {
            public uint ProcessId;
            public byte ObjectTypeNumber;
            public byte Flags;
            public ushort Handle;
            public IntPtr pObject;
            public int GrantedAccess;
        }
    
        public const int STATUS_SUCCESS = 0x0;
        public const int STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004);
    
        public enum SYSTEM_INFORMATION_CLASS
        {
            SystemBasicInformation,
            SystemProcessorInformation,
            SystemPerformanceInformation,
            SystemTimeOfDayInformation,
            SystemPathInformation,
            SystemProcessInformation,
            SystemCallCountInformation,
            SystemDeviceInformation,
            SystemProcessorPerformanceInformation,
            SystemFlagsInformation,
            SystemCallTimeInformation,
            SystemModuleInformation,
            SystemLocksInformation,
            SystemStackTraceInformation,
            SystemPagedPoolInformation,
            SystemNonPagedPoolInformation,
            SystemHandleInformation,
            SystemObjectInformation,
            SystemPageFileInformation,
            SystemVdmInstemulInformation,
            SystemVdmBopInformation,
            SystemFileCacheInformation,
            SystemPoolTagInformation,
            SystemInterruptInformation,
            SystemDpcBehaviorInformation,
            SystemFullMemoryInformation,
            SystemLoadGdiDriverInformation,
            SystemUnloadGdiDriverInformation,
            SystemTimeAdjustmentInformation,
            SystemSummaryMemoryInformation,
            SystemMirrorMemoryInformation,
            SystemPerformanceTraceInformation,
            SystemObsolete0,
            SystemExceptionInformation,
            SystemCrashDumpStateInformation,
            SystemKernelDebuggerInformation,
            SystemContextSwitchInformation,
            SystemRegistryQuotaInformation,
            SystemExtendServiceTableInformation,
            SystemPrioritySeperation,
            SystemVerifierAddDriverInformation,
            SystemVerifierRemoveDriverInformation,
            SystemProcessorIdleInformation,
            SystemLegacyDriverInformation,
            SystemCurrentTimeZoneInformation,
            SystemLookasideInformation,
            SystemTimeSlipNotification,
            SystemSessionCreate,
            SystemSessionDetach,
            SystemSessionInformation,
            SystemRangeStartInformation,
            SystemVerifierInformation,
            SystemVerifierThunkExtend,
            SystemSessionProcessInformation,
            SystemLoadGdiDriverInSystemSpace,
            SystemNumaProcessorMap,
            SystemPrefetcherInformation,
            SystemExtendedProcessInformation,
            SystemRecommendedSharedDataAlignment,
            SystemComPlusPackage,
            SystemNumaAvailableMemory,
            SystemProcessorPowerInformation,
            SystemEmulationBasicInformation,
            SystemEmulationProcessorInformation,
            SystemExtendedHandleInformation,
            SystemLostDelayedWriteInformation,
            SystemBigPoolInformation,
            SystemSessionPoolTagInformation,
            SystemSessionMappedViewInformation,
            SystemHotpatchInformation,
            SystemObjectSecurityMode,
            SystemWatchdogTimerHandler,
            SystemWatchdogTimerInformation,
            SystemLogicalProcessorInformation,
            SystemWow64SharedInformationObsolete,
            SystemRegisterFirmwareTableInformationHandler,
            SystemFirmwareTableInformation,
            SystemModuleInformationEx,
            SystemVerifierTriageInformation,
            SystemSuperfetchInformation,
            SystemMemoryListInformation,
            SystemFileCacheInformationEx,
            SystemThreadPriorityClientIdInformation,
            SystemProcessorIdleCycleTimeInformation,
            SystemVerifierCancellationInformation,
            SystemProcessorPowerInformationEx,
            SystemRefTraceInformation,
            SystemSpecialPoolInformation,
            SystemProcessIdInformation,
            SystemErrorPortInformation,
            SystemBootEnvironmentInformation,
            SystemHypervisorInformation,
            SystemVerifierInformationEx,
            SystemTimeZoneInformation,
            SystemImageFileExecutionOptionsInformation,
            SystemCoverageInformation,
            SystemPrefetchPatchInformation,
            SystemVerifierFaultsInformation,
            SystemSystemPartitionInformation,
            SystemSystemDiskInformation,
            SystemProcessorPerformanceDistribution,
            SystemNumaProximityNodeInformation,
            SystemDynamicTimeZoneInformation,
            SystemCodeIntegrityInformation,
            SystemProcessorMicrocodeUpdateInformation,
            SystemProcessorBrandString,
            SystemVirtualAddressInformation,
            SystemLogicalProcessorAndGroupInformation,
            SystemProcessorCycleTimeInformation,
            SystemStoreInformation,
            SystemRegistryAppendString,
            SystemAitSamplingValue,
            SystemVhdBootInformation,
            SystemCpuQuotaInformation,
            SystemNativeBasicInformation,
            SystemErrorPortTimeouts,
            SystemLowPriorityIoInformation,
            SystemBootEntropyInformation,
            SystemVerifierCountersInformation,
            SystemPagedPoolInformationEx,
            SystemSystemPtesInformationEx,
            SystemNodeDistanceInformation,
            SystemAcpiAuditInformation,
            SystemBasicPerformanceInformation,
            SystemQueryPerformanceCounterInformation,
            SystemSessionBigPoolInformation,
            SystemBootGraphicsInformation,
            SystemScrubPhysicalMemoryInformation,
            SystemBadPageInformation,
            SystemProcessorProfileControlArea,
            SystemCombinePhysicalMemoryInformation,
            SystemEntropyInterruptTimingInformation,
            SystemConsoleInformation,
            SystemPlatformBinaryInformation,
            SystemThrottleNotificationInformation,
            SystemHypervisorProcessorCountInformation,
            SystemDeviceDataInformation,
            SystemDeviceDataEnumerationInformation,
            SystemMemoryTopologyInformation,
            SystemMemoryChannelInformation,
            SystemBootLogoInformation,
            SystemProcessorPerformanceInformationEx,
            SystemSpare0,
            SystemSecureBootPolicyInformation,
            SystemPageFileInformationEx,
            SystemSecureBootInformation,
            SystemEntropyInterruptTimingRawInformation,
            SystemPortableWorkspaceEfiLauncherInformation,
            SystemFullProcessInformation,
            MaxSystemInfoClass // = 0x0095
        }
    
        [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern int NtQueryObject(IntPtr Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, IntPtr ObjectInformation, uint Length, ref uint ReturnLength);
    
        public enum OBJECT_INFORMATION_CLASS
        {
            ObjectBasicInformation,
            ObjectNameInformation,
            ObjectTypeInformation,
            ObjectTypesInformation,
            ObjectHandleFlagInformation,
            ObjectSessionInformation
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct GENERIC_MAPPING
        {
            public int GenericRead;
            public int GenericWrite;
            public int GenericExecute;
            public int GenericAll;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_TYPE_INFORMATION
        {
            public UNICODE_STRING TypeName;
            public int TotalNumberOfObjects;
            public int TotalNumberOfHandles;
            public int TotalPagedPoolUsage;
            public int TotalNonPagedPoolUsage;
            public int TotalNamePoolUsage;
            public int TotalHandleTableUsage;
            public int HighWaterNumberOfObjects;
            public int HighWaterNumberOfHandles;
            public int HighWaterPagedPoolUsage;
            public int HighWaterNonPagedPoolUsage;
            public int HighWaterNamePoolUsage;
            public int HighWaterHandleTableUsage;
            public int InvalidAttributes;
            public GENERIC_MAPPING GenericMapping;
            public int ValidAccessMask;
            public byte SecurityRequired;
            public byte MaintainHandleCount;
            public int PoolType;
            public int DefaultPagedPoolCharge;
            public int DefaultNonPagedPoolCharge;
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct OBJECT_NAME_INFORMATION
        {
            public UNICODE_STRING Name;
        }
    
        public const int DUPLICATE_CLOSE_SOURCE = 0x1;
        public const int DUPLICATE_SAME_ACCESS = 0x2;
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, ref IntPtr lpTargetHandle, int dwDesiredAccess, bool bInheritHandle, int dwOptions);
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetCurrentProcess();
    
        public const int SYNCHRONIZE = 0x100000;
        public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
    
        public const int PROCESS_VM_READ = (0x10);
        public const int PROCESS_VM_WRITE = (0x20);
        public const int PROCESS_DUP_HANDLE = (0x40);
        public const int PROCESS_CREATE_PROCESS = (0x80);
        public const int PROCESS_SET_QUOTA = (0x100);
        public const int PROCESS_SET_INFORMATION = (0x200);
        public const int PROCESS_QUERY_INFORMATION = (0x400);
        public const int PROCESS_SUSPEND_RESUME = (0x800);
        public const int PROCESS_QUERY_LIMITED_INFORMATION = (0x1000);
        public const int PROCESS_SET_LIMITED_INFORMATION = (0x2000);
        public const long PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF);
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
        
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr hObject);
    
    
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            int nStatus = STATUS_SUCCESS;
            IntPtr pLargeBuffer = IntPtr.Zero;
            int nCbLargeBuffer = 64 * 1024;
            int nReturnLength = 0;
    
            for (;;)
            {
                pLargeBuffer = Marshal.AllocHGlobal(nCbLargeBuffer);
                nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);
                if ((nStatus == STATUS_SUCCESS))
                {
                    break;
                }
                if ((nStatus == STATUS_INFO_LENGTH_MISMATCH))
                {
                    Marshal.FreeHGlobal(pLargeBuffer);
                    nCbLargeBuffer += 8192;
                }
                else
                {
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
            }
    
            int nCount = System.Convert.ToInt32(Marshal.PtrToStructure(pLargeBuffer, typeof(int)));
            IntPtr pLargeBufferNew = IntPtr.Zero;
            pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int));
            SYSTEM_HANDLE_INFORMATION pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
            for (int nIndex = 0; nIndex <= nCount; nIndex++)
            {
                pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));
                pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
     
                IntPtr hDup = IntPtr.Zero;
                IntPtr hProcess = OpenProcess(PROCESS_DUP_HANDLE, true, pHandleInfo.ProcessId);
                if (hProcess != IntPtr.Zero)
                {         
                    bool bReturn = DuplicateHandle(hProcess, (IntPtr)pHandleInfo.Handle, GetCurrentProcess(), ref hDup, 0, false, DUPLICATE_SAME_ACCESS);
                    if (hDup != IntPtr.Zero)
                    {
                        IntPtr pObjectType = IntPtr.Zero;
                        var oti = new OBJECT_TYPE_INFORMATION();
                        uint nLength = 0x1000;
                        pObjectType = Marshal.AllocHGlobal((int)nLength);
                        while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                        {
                            Marshal.FreeHGlobal(pObjectType);
                            pObjectType = Marshal.AllocHGlobal((int)nLength);
                        }
                        oti = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(pObjectType, typeof(OBJECT_TYPE_INFORMATION));
                        Marshal.FreeHGlobal(pObjectType);
    
                        string sName = "none";
                        if (pHandleInfo.GrantedAccess != 0x12019F && pHandleInfo.GrantedAccess != 0x120189)
                        {
                            IntPtr pObjectName = IntPtr.Zero;
                            var oni = new OBJECT_NAME_INFORMATION();
                            nLength = 0x1000;
                            pObjectName = Marshal.AllocHGlobal((int)nLength);
                            while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectNameInformation, pObjectName, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                            {
                                Marshal.FreeHGlobal(pObjectName);
                                pObjectName = Marshal.AllocHGlobal((int)nLength);
                            }
                            oni = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(pObjectName, typeof(OBJECT_NAME_INFORMATION));
                            Marshal.FreeHGlobal(pObjectName);
                            sName = oni.Name.Buffer;
                        }
    
                        Console.WriteLine("pid = {0} - Handle : 0x{1:X} - Type : {2} - Name : {3}", pHandleInfo.ProcessId, pHandleInfo.Handle, oti.TypeName.Buffer, sName);
                        CloseHandle(hDup);
                    }
                   CloseHandle(hProcess);
                }
            }
        }
    }

    • Marked as answer by C2002 Thursday, July 30, 2020 11:29 AM
    • Unmarked as answer by C2002 Friday, July 31, 2020 2:31 PM
    • Marked as answer by C2002 Friday, July 31, 2020 2:31 PM
    Tuesday, July 28, 2020 3:16 PM
  • Okay, so I tried it, but after processing a large number of handles, the program crashes. I even tried running it as an administrator.
    Tuesday, July 28, 2020 3:47 PM
  • You have to wrap each process in a try-catch. There are processes that you do not have privileges to even if admin. It will crash with a security exception in those cases.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:04 PM
  • Okay, I also tried inserting the entire contents of the for loop into a Try block but it keeps crashing.
    Tuesday, July 28, 2020 4:13 PM
  • Each process has to be try-catch separately. Your app will get all processes whether you have access to them or not. Then you will trigger a call to get data and it'll blow up. You need to wrap each iteration of the loop in a try-catch. Of course if you gave us the exception that occurs it would help narrow down if this is the problem.

    //For loop expression looks wrong in the original by the way
    for (int nIndex = 0; nIndex < nCount; ++nIndex)
    {
       try
       {
       } catch
       { /* ignore this process */ }
    }

    Note that the for loop second expression looks wrong. I think it should be < but I didn't look at how `nCount` is calculated.

    Also it is possible to blow up while enumerating the handles so you might want a try-catch within the while loop as well.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:18 PM
  • Okay, so I tried it, but after processing a large number of handles, the program crashes. I even tried running it as an administrator.

    At which line of code ?
    Which error/exception is returned ?

    I let it enumerate  handles for ~10 minutes and I could not make it crash

    (compiled with "Any CPU", on Windows 10 64-bit, .NET 4.7.2)

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:23 PM
  • Yeah, I've tried that before, but it doesn't work. Anyway, in order to make a quick test I have made sure that it returns me the handles of a specific process:

    for (int nIndex = 0; nIndex <= nCount; nIndex++)
                {
                    try
                    {
                        pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));
                        pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
    
                        IntPtr hDup = IntPtr.Zero;
    
                        if (pHandleInfo.ProcessId == 13020)
                        {
                           //-------------
    }
                        else
                        {
                            continue;
                        }
                    }
                    catch
                    {
                        continue;
                    }
                }
    

    But now the problem is something else. That is, it lists all the handles including a process (the game I'd like to protect), but it doesn't tell me the name of this process, so I can't know if it's really going on there.


    Tuesday, July 28, 2020 4:25 PM
  • Okay, so I tried it, but after processing a large number of handles, the program crashes. I even tried running it as an administrator.

    At which line of code ?
    Which error/exception is returned ?

    I let it enumerate  handles for ~10 minutes and I could not make it crash

    (compiled with "Any CPU", on Windows 10 64-bit, .NET 4.7.2)

    The following interruption occurs (sorry if it is mistranslated but I have Visual Studio in Italian):

    ContextSwitchDeadlock' managed debugging assistant 
      Message=Assistant to managed debugging 'ContextSwitchDeadlock' : 'CLR failed to switch from COM 0x15466b8 context to COM 0x1546600 context for 60 seconds. The thread to which the target context/apartment belongs is probably waiting without distribution or processing a long run operation that does not distribute Windows messages. This situation typically has a negative impact on performance and can cause the application to fail to respond or to accumulate memory usage over time. To avoid this problem, all single-threaded apartment threads must use primitive waiting with distribution (e.g., CoWaitForMultipleHandles) and routinely distributed messages during extended-execution operations. 

    Tuesday, July 28, 2020 4:34 PM

  • But now the problem is something else. That is, it lists all the handles including a process (the game I'd like to protect), but it doesn't tell me the name of this process, so I can't know if it's really going on there.


    Just use APIs like QueryFullProcessImageName

    to get the process name

            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool QueryFullProcessImageName(IntPtr hProcess, int dwFlags, StringBuilder lpExeName, ref uint lpdwSize);

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:34 PM
  • Are you calling this on a UI thread? That isn't going to work out. You blocked the UI so long that it caused timeout errors in a COM object you seem to be using. You need to move this logic to a separate thread (possibly an async task) so that it doesn't freeze the UI thread.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 4:47 PM
  • I tried, but it still won't return any names.

    if (oti.TypeName.Buffer == "Process")
                                    {
                                        const int maxVal = 1024 * 2014;
    
                                        var buffer = new StringBuilder(255);
    
                                        do
                                        {
                                            int size = buffer.Capacity;
                                            bool success = QueryFullProcessImageName(hProcess, 0, buffer, ref size);
                                            if (success)
                                            {
                                                sName = buffer.ToString();
                                                break;
                                            }
                                            buffer.Capacity = buffer.Capacity * 2;
                                        }
                                        while (buffer.Capacity < maxVal);
                                    }

    Tuesday, July 28, 2020 5:03 PM
  • Are you calling this on a UI thread? That isn't going to work out. You blocked the UI so long that it caused timeout errors in a COM object you seem to be using. You need to move this logic to a separate thread (possibly an async task) so that it doesn't freeze the UI thread.

    Michael Taylor http://www.michaeltaylorp3.net

    I tried putting it in a background worker but after a while it still stops.
    Tuesday, July 28, 2020 5:08 PM
  • Stops or throws an exception? Please post your updated code including how you're calling it.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:11 PM
  • Stops or throws an exception? Please post your updated code including how you're calling it.

    Michael Taylor http://www.michaeltaylorp3.net

    It stops by not giving any kind of exception.

            public Form1()
            {
                InitializeComponent();
    
                backgroundWorker1.WorkerReportsProgress = true;
                backgroundWorker1.WorkerSupportsCancellation = true;
                backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync();
            }
    
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                //-----------
            }
    


    Tuesday, July 28, 2020 5:26 PM
  • How do you know it stops? Are you listening for the completion event? Are you printing out UI updates in the report progress handler? Have you stepped through the DoWork handler to see what it is doing?

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:36 PM
  • I notice it because it stops the output of the handles also the CPU usage by the process goes to 0 and also always from the debug console I see the threads that end.
    Tuesday, July 28, 2020 5:42 PM
  • Possible causes:

    1) The code finishes and a bug is preventing you from finding the handle you want. Step through the code to debug this.

    2) Your output logic is wrong. Please post the relevant code that runs inside DoWork handler that does your output.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 5:52 PM
  • Possible causes:

    1) The code finishes and a bug is preventing you from finding the handle you want. Step through the code to debug this.

    2) Your output logic is wrong. Please post the relevant code that runs inside DoWork handler that does your output.


    Michael Taylor http://www.michaeltaylorp3.net

    The code that is in the background worker is the same code that was in button1_Click in Castorix31's code. I just moved it.
    Tuesday, July 28, 2020 5:57 PM
  • The only output line in that original code was a call to Console.WriteLine which isn't applicable to Winforms apps. You don't have a UI element that is going to be updated in your UI with the output from this method?

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:01 PM
  • The only output line in that original code was a call to Console.WriteLine which isn't applicable to Winforms apps. You don't have a UI element that is going to be updated in your UI with the output from this method?

    Michael Taylor http://www.michaeltaylorp3.net

    I replaced Console.Writeline with Debug.Writeline, so I could see the output in the Debug console.
    Tuesday, July 28, 2020 6:04 PM
  • Got it. So does it run for a fixed period of time and then stop or does it simply stop. Simply stopping doesn't make sense unless there is an exception (and the original code doesn't have any error handling you and only provided snippets of your error handling version). Wrapping the entire function in a try-catch and writing out the exception will help identify any exception errors.

    If there are no exceptions then the code must be done and it didn't find anything. I would recommend that you start up the process that you're looking for, set a conditional breakpoint inside the process loop function to break when the given process ID is found and then step through the remaining code to identify why it isn't returning a result.


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:09 PM
  • Got it. So does it run for a fixed period of time and then stop or does it simply stop. Simply stopping doesn't make sense unless there is an exception (and the original code doesn't have any error handling you and only provided snippets of your error handling version). Wrapping the entire function in a try-catch and writing out the exception will help identify any exception errors.

    If there are no exceptions then the code must be done and it didn't find anything. I would recommend that you start up the process that you're looking for, set a conditional breakpoint inside the process loop function to break when the given process ID is found and then step through the remaining code to identify why it isn't returning a result.


    Michael Taylor http://www.michaeltaylorp3.net

    Before I do this I'm trying to get the name of the processes, because it doesn't give back the name of any process.

    Tuesday, July 28, 2020 6:27 PM
  • FYI since it appears that all you need the process for is the handle you can also simply use Process.GetProcesses from .NET to get all the processes. This gives you the name automatically (but note that security prevents you from reading any properties of a process so make sure it is in a try-catch). Given the Process object you have the handle needed for other calls. Note that I'm not sure if this handle works in the other system calls but for other OS calls I've never had an issue. This might solve your current problem.

    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:34 PM
  • I tried, but it still won't return any names.

    Ah sorry, I thought you wanted the process name from the current PID....

    Then you can use NtQueryInformationProcess and ProcessBasicInformation to get the PID to identify the process (from hDup)

    I just tested but it only worked as Admin (I added a Manifest)

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 6:38 PM
  • I tried, but it still won't return any names.

    Ah sorry, I thought you wanted the process name from the current PID....

    Then you can use NtQueryInformationProcess and ProcessBasicInformation to get the PID to identify the process (from hDup)

    I just tested but it only worked as Admin (I added a Manifest)

    I really appreciate the help you're both giving me. Anyway, I tried it this way, but it still doesn't give me anything back.

            [DllImport("ntdll.dll", SetLastError = true)]
            static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref PROCESS_BASIC_INFORMATION processInformation, int processInformationLength, out int returnLength);
    
                         //------------------------
    
                                    if (oti.TypeName.Buffer == "Process")
                                    {
                                        var pbi = new PROCESS_BASIC_INFORMATION();
                                        int returnLength;
                                        var status = NtQueryInformationProcess(hProcess, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
    
                                        sName = Process.GetProcessById((int)pbi.UniqueProcessId).MainWindowTitle;
                                    }
    
                        //------------------------

    Tuesday, July 28, 2020 7:25 PM
  • This works for me, as Admin =>

    PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
    nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
    if (nStatus == 0)
    {
        System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
        string sProcName = proc.ProcessName;
    
    } 

    with :

    [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]                                                                                                                                 
    public static extern int NtQueryInformationProcess(IntPtr ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PROCESS_BASIC_INFORMATION info, int ProcessInformationLength, int[] ReturnLength);
    
    [StructLayout(LayoutKind.Sequential)]
    public class PROCESS_BASIC_INFORMATION
    {
        public int ExitStatus = 0;
        public IntPtr PebBaseAddress = (IntPtr)0;
        public IntPtr AffinityMask = (IntPtr)0;
        public int BasePriority = 0;
        public IntPtr UniqueProcessId = (IntPtr)0;
        public IntPtr InheritedFromUniqueProcessId = (IntPtr)0;
    }
                
    public enum PROCESSINFOCLASS                                                                    
    {                                                                                        
        ProcessBasicInformation,                                                             
        ProcessQuotaLimits,                                                                  
        ProcessIoCounters,                                                                   
        ProcessVmCounters,                                                                   
        ProcessTimes,                                                                        
        ProcessBasePriority,                                                                 
        ProcessRaisePriority,                                                                
        ProcessDebugPort,                                                                    
        ProcessExceptionPort,                                                                
        ProcessAccessToken,                                                                  
        ProcessLdtInformation,                                                               
        ProcessLdtSize,                                                                      
        ProcessDefaultHardErrorMode,                                                         
        ProcessIoPortHandlers,          // Note: this is kernel mode only                    
        ProcessPooledUsageAndLimits,                                                         
        ProcessWorkingSetWatch,                                                              
        ProcessUserModeIOPL,                                                                 
        ProcessEnableAlignmentFaultFixup,                                                    
        ProcessPriorityClass,                                                                
        ProcessWx86Information,                                                              
        ProcessHandleCount,                                                                  
        ProcessAffinityMask,                                                                 
        ProcessPriorityBoost,                                                                
        ProcessDeviceMap,                                                                    
        ProcessSessionInformation,                                                           
        ProcessForegroundInformation,                                                        
        ProcessWow64Information,                                                             
        ProcessImageFileName,                                                                
        ProcessLUIDDeviceMapsEnabled,                                                        
        ProcessBreakOnTermination,                                                           
        ProcessDebugObjectHandle,                                                            
        ProcessDebugFlags,                                                                   
        ProcessHandleTracing,                                                                
        ProcessUnusedSpare1,                                                                 
        ProcessExecuteFlags,                                                                 
        ProcessResourceManagement,                                                           
        ProcessCookie,                                                                       
        ProcessImageInformation,                                                             
        MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
    }    

    • Marked as answer by C2002 Thursday, July 30, 2020 11:30 AM
    Tuesday, July 28, 2020 8:09 PM
  • This works for me, as Admin =>

    PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
    nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
    if (nStatus == 0)
    {
        System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
        string sProcName = proc.ProcessName;
    
    } 

    with :

    [DllImport("NtDll.dll", SetLastError = true, CharSet = CharSet.Auto)]                                                                                                                                 
    public static extern int NtQueryInformationProcess(IntPtr ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PROCESS_BASIC_INFORMATION info, int ProcessInformationLength, int[] ReturnLength);
    
    [StructLayout(LayoutKind.Sequential)]
    public class PROCESS_BASIC_INFORMATION
    {
        public int ExitStatus = 0;
        public IntPtr PebBaseAddress = (IntPtr)0;
        public IntPtr AffinityMask = (IntPtr)0;
        public int BasePriority = 0;
        public IntPtr UniqueProcessId = (IntPtr)0;
        public IntPtr InheritedFromUniqueProcessId = (IntPtr)0;
    }
                
    public enum PROCESSINFOCLASS                                                                    
    {                                                                                        
        ProcessBasicInformation,                                                             
        ProcessQuotaLimits,                                                                  
        ProcessIoCounters,                                                                   
        ProcessVmCounters,                                                                   
        ProcessTimes,                                                                        
        ProcessBasePriority,                                                                 
        ProcessRaisePriority,                                                                
        ProcessDebugPort,                                                                    
        ProcessExceptionPort,                                                                
        ProcessAccessToken,                                                                  
        ProcessLdtInformation,                                                               
        ProcessLdtSize,                                                                      
        ProcessDefaultHardErrorMode,                                                         
        ProcessIoPortHandlers,          // Note: this is kernel mode only                    
        ProcessPooledUsageAndLimits,                                                         
        ProcessWorkingSetWatch,                                                              
        ProcessUserModeIOPL,                                                                 
        ProcessEnableAlignmentFaultFixup,                                                    
        ProcessPriorityClass,                                                                
        ProcessWx86Information,                                                              
        ProcessHandleCount,                                                                  
        ProcessAffinityMask,                                                                 
        ProcessPriorityBoost,                                                                
        ProcessDeviceMap,                                                                    
        ProcessSessionInformation,                                                           
        ProcessForegroundInformation,                                                        
        ProcessWow64Information,                                                             
        ProcessImageFileName,                                                                
        ProcessLUIDDeviceMapsEnabled,                                                        
        ProcessBreakOnTermination,                                                           
        ProcessDebugObjectHandle,                                                            
        ProcessDebugFlags,                                                                   
        ProcessHandleTracing,                                                                
        ProcessUnusedSpare1,                                                                 
        ProcessExecuteFlags,                                                                 
        ProcessResourceManagement,                                                           
        ProcessCookie,                                                                       
        ProcessImageInformation,                                                             
        MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
    }    

    Thank you very much. Now that I can also get the name of the process, all that remains for me to do is to solve this problem of the search that stops after finding a certain number of handles, so that I can cycle all the processes.
    Tuesday, July 28, 2020 8:22 PM
  • The crash/freeze is maybe because of pipes

    That's why I added the test on GrantedAccess, but the second one could be wrong

    You can find similar tests in several posts, like at  http://espresso3389.hatenablog.com/entry/2014/12/05/031051

    with

     if (shi.GrantedAccess == 0x0012019f   // seems mandatory (named pipes)
                  || shi.GrantedAccess == 0x001a019f   // blocking named pipe (not a file anyways)

    "

    • Marked as answer by C2002 Friday, July 31, 2020 2:29 PM
    Tuesday, July 28, 2020 8:39 PM
  • Okay, I modified that part and it seems to be working properly now. Now I just have to filter the processes because there are too many handles to examine. Thank you so much for your help.
    Wednesday, July 29, 2020 12:29 PM
  • Hi Christian2002,
    I am glad you have got your solution,we suggest that you mark it as the answer. So it can help other people who have the same problem find a solution quickly.
    Best Regards,
    Daniel Zhang


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, July 30, 2020 2:33 AM
  • The crash/freeze is maybe because of pipes

    That's why I added the test on GrantedAccess, but the second one could be wrong

    You can find similar tests in several posts, like at  http://espresso3389.hatenablog.com/entry/2014/12/05/031051

    with

     if (shi.GrantedAccess == 0x0012019f   // seems mandatory (named pipes)
                  || shi.GrantedAccess == 0x001a019f   // blocking named pipe (not a file anyways)

    "

    I modified this part but after a while it still stops. To get around this problem (which I think occurs with processes that have greater privileges), I've made it list only handles executed according to the Windows username in use, and it seems to work. The problem is that this operation never seems to end, because of the huge number of handles (~500k). Since I only need "Process" type handles, is there a way to reduce the time (a few minutes) without having a driver?
    Friday, July 31, 2020 2:24 PM
  • As you wrote "I've been looking for a way to get a list of handles given a specific process."

    can't you just filter by the PID of this process, instead of scanning all PIDs ?

    • Marked as answer by C2002 Friday, July 31, 2020 2:37 PM
    Friday, July 31, 2020 2:36 PM
  • As you wrote "I've been looking for a way to get a list of handles given a specific process."

    can't you just filter by the PID of this process, instead of scanning all PIDs ?

    My intention was to create a function where given as a parameter a process, it gave me a list of all the other processes that had an open handle on it. I can't filter through PID, because the program doesn't know which process currently has an open handle on the process I want to protect.

    • Edited by C2002 Friday, July 31, 2020 2:47 PM
    Friday, July 31, 2020 2:40 PM
  • I'm not sure I understood, but if I want for example all open handles on Notepad only, I will do :

    System.Diagnostics.Process[] processNotepad = System.Diagnostics.Process.GetProcessesByName("notepad");
    int pIdNotepad = -1;
    if (processNotepad.Count() > 0)
        pIdNotepad = processNotepad[0].Id;

    then in the loop, I add a test on Notepad PID :

    for (int nIndex = 0; nIndex <= nCount; nIndex++)
    {
    	pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));                                                              
    	pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
            // Filter on Notepad                                                                                                              
    	if (pIdNotepad != -1 && pHandleInfo.ProcessId == pIdNotepad)                                                        
    	{  
    		// all the code ...  
    	}  
    }  

    • Marked as answer by C2002 Friday, July 31, 2020 4:04 PM
    Friday, July 31, 2020 3:14 PM
  • I'm not sure I understood, but if I want for example all open handles on Notepad only, I will do :

    System.Diagnostics.Process[] processNotepad = System.Diagnostics.Process.GetProcessesByName("notepad");
    int pIdNotepad = -1;
    if (processNotepad.Count() > 0)
        pIdNotepad = processNotepad[0].Id;


    then in the loop, I add a test on Notepad PID :

    for (int nIndex = 0; nIndex <= nCount; nIndex++)
    {
    	pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION));                                                              
    	pHandleInfo = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION));
            // Filter on Notepad                                                                                                              
    	if (pIdNotepad != -1 && pHandleInfo.ProcessId == pIdNotepad)                                                        
    	{  
    		// all the code ...  
    	}  
    }  

    public List<uint> getProcessesWithOpenHandleOn (string processName)

    { List<uint> procsPIDs = new List<uint>; //The code that was in the "button1_click" event ... PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null); if (nStatus == 0) { System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId); sName = proc.ProcessName; } if (oti.TypeName.Buffer == "Process") { if (sName + ".exe" == processName) { procsPIDs.Add(pHandleInfo.ProcessId); } } //Code end ... return procsPIDs; {

    I'd like to do something like that, but it takes a long time.

    Friday, July 31, 2020 4:00 PM
  • I've also tried to do something like that as testing, but it's still very slow and deadlocks continue to occur.

            private void button1_Click(object sender, EventArgs e)
            {
                foreach (Process item in Process.GetProcesses())
                {
                    if (GetProcessUser(item) == "HelloWorld")
                    {
                        getProcessesWithOpenHandleBy(item.Id);
                    }
                }
            }
    
            public void getProcessesWithOpenHandleBy(int id)
            {
                int nStatus = STATUS_SUCCESS;
                IntPtr pLargeBuffer = IntPtr.Zero;
    
                // ... other code ...
    
                                    PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                                    nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
                                    if (nStatus == 0)
                                    {
                                        System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
                                        sName = proc.ProcessName;
                                    }
    
                                    if (oti.TypeName.Buffer == "Process")
                                    {
                                        Debug.WriteLine("pid = {0} - Handle : 0x{1:X} - Type : {2} - Name : {3}", pHandleInfo.ProcessId, pHandleInfo.Handle, oti.TypeName.Buffer, sName);
                                    }
    
                // ... other code ...
    
             }

    Friday, July 31, 2020 5:46 PM
  • But I don't see the filter on the PID

    Listing just the handles of a unique PID is fast

    • Marked as answer by C2002 Friday, July 31, 2020 7:29 PM
    Friday, July 31, 2020 6:03 PM
  • But I don't see the filter on the PID

    Listing just the handles of a unique PID is fast

    Yes I forgot to enter it here, but in the code I entered "if (pHandleInfo.ProcessId == id)", but it still remains slow. In any case, I always have to perform this operation on all processes.
    Friday, July 31, 2020 6:21 PM
  • -

    • Edited by C2002 Sunday, August 2, 2020 5:43 PM
    Friday, July 31, 2020 6:36 PM
  • I don't understand how it can be slow to list the handles just for the given process/PID

    When I test on Notepad, it takes less than 1 second, with a few dozens of handles, as all other PIDs are skipped

    • Marked as answer by C2002 Friday, July 31, 2020 7:29 PM
    Friday, July 31, 2020 7:25 PM
  • I don't understand how it can be slow to list the handles just for the given process/PID

    When I test on Notepad, it takes less than 1 second, with a few dozens of handles, as all other PIDs are skipped

    I don't know, if I input a random PID, it takes a long time, almost a minute.
    Friday, July 31, 2020 7:29 PM
  • I tried to insert as PID 37976 and it took 46 minutes to list the handles.
    Friday, July 31, 2020 9:04 PM
  • I tried to insert as PID 37976 and it took 46 minutes to list the handles.

    46 mn for 1 process ?!!!

    For Notepad, I get those handles (140), in 1-2 seconds (and most of the time is taken by Console.WriteLine)

    It is nearly as fast as handles listed by Process Explorer, which returns less handles

    (I added the process name from QueryFullProcessImageName)

    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x10 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x14 - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x18 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x24 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x34 - Type : Directory - Name : \KnownDlls
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x40 - Type : File - Name : \Device\HarddiskVolume4\Users\Christian
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x58 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x5C - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x60 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x64 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x68 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x6C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x70 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x74 - Type : File - Name : \Device\HarddiskVolume4\Program Files\WindowsApps\Microsoft.LanguageExperiencePackfr-FR_18362.26.83.0_neutral__8wekyb3d8bbwe\Windows\System32\fr-FR\notepad.exe.mui
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x7C - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Versions
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8C - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x90 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x94 - Type : IoCompletion - Name : 
    
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x98 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x9C - Type : Desktop - Name : \Default
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA0 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA4 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xAC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB0 - Type : File - Name : \Device\CNG
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB4 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB8 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xBC - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Ole
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC4 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings\Software\Microsoft
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC8 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xCC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xDC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xEC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF8 - Type : Directory - Name : \Sessions\1\BaseNamedObjects
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x128 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x12C - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x130 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x138 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x13C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x140 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x148 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x150 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x154 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x158 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x15C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x160 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x164 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x168 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x170 - Type : Event - Name : \KernelObjects\MaximumCommitCondition
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x174 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x178 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x17C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x180 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x188 - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x190 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x194 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x198 - Type : File - Name : \Device\HarddiskVolume4\Windows\SystemResources\notepad.exe.mun
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x19C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1A0 - Type : Section - Name : \Windows\Theme3372165587
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1AC - Type : Section - Name : \Sessions\1\Windows\Theme1817300183
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B0 - Type : File - Name : \Device\HarddiskVolume4\Windows\Fonts\StaticCache.dat
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B4 - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x200 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Session Manager
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x204 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x208 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x210 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x214 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\HwOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x218 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\ProviderOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x21C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x220 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x268 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x26C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x27C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x280 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x284 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x288 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x28C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x294 - Type : ALPC Port - Name : \RPC Control\OLEF8D468628B9656595E6360AB99DE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x298 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x29C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A4 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A8 - Type : File - Name : \Device\HarddiskVolume4\Windows\Registration\R000000000015.clb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2AC - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B0 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B4 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom\ClassIndex
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2BC - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C0 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C8 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2CC - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2D0 - Type : File - Name : \Device\DeviceApi
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x300 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x304 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Ids
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x308 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x30C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x314 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x318 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x31C - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x320 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x324 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x328 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x32C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x330 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x334 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x338 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x350 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x354 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x358 - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x35C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x360 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x364 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x368 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x36C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x370 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x374 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x378 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x37C - Type : IoCompletionReserve - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x380 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x384 - Type : ALPC Port - Name : \BaseNamedObjects\[CoreUI]-PID(4912)-TID(31772) 60e8da57-b536-4a70-a860-3a3f442cd252
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x388 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x390 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A4 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A8 - Type : Thread - Name : 



    • Edited by Castorix31 Friday, July 31, 2020 9:19 PM
    • Marked as answer by C2002 Friday, July 31, 2020 9:28 PM
    Friday, July 31, 2020 9:15 PM
  • I don't know where the problem is, to make it quicker I simply added "if (pHandleInfo.ProcessId == 37976)", but it's very slow.
    Friday, July 31, 2020 9:29 PM
  • At this point I'm starting to believe that it's impossible to do this in C#. From what I've understood programs able to search for a handle through the name are equipped with a specially written driver. I give up.
    Friday, July 31, 2020 11:11 PM
  • I tried to insert as PID 37976 and it took 46 minutes to list the handles.

    46 mn for 1 process ?!!!

    For Notepad, I get those handles (140), in 1-2 seconds (and most of the time is taken by Console.WriteLine)

    It is nearly as fast as handles listed by Process Explorer, which returns less handles

    (I added the process name from QueryFullProcessImageName)

    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x10 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x14 - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x18 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x24 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x34 - Type : Directory - Name : \KnownDlls
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x40 - Type : File - Name : \Device\HarddiskVolume4\Users\Christian
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x4C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x58 - Type : IoCompletion - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x5C - Type : TpWorkerFactory - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x60 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x64 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x68 - Type : IRTimer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x6C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x70 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x74 - Type : File - Name : \Device\HarddiskVolume4\Program Files\WindowsApps\Microsoft.LanguageExperiencePackfr-FR_18362.26.83.0_neutral__8wekyb3d8bbwe\Windows\System32\fr-FR\notepad.exe.mui
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x7C - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Versions
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x8C - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x90 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x94 - Type : IoCompletion - Name : 
    
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x98 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x9C - Type : Desktop - Name : \Default
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA0 - Type : WindowStation - Name : \Sessions\1\Windows\WindowStations\WinSta0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xA4 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xAC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB0 - Type : File - Name : \Device\CNG
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB4 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xB8 - Type : Key - Name : \REGISTRY\MACHINE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xBC - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\Ole
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC4 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings\Software\Microsoft
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xC8 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes\Local Settings
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xCC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xDC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xE8 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xEC - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0xF8 - Type : Directory - Name : \Sessions\1\BaseNamedObjects
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x128 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x12C - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x130 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:304:WilStaging_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x138 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x13C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x140 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x148 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x150 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x154 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x158 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x15C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x160 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x164 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x168 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x170 - Type : Event - Name : \KernelObjects\MaximumCommitCondition
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x174 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x178 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x17C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x180 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x188 - Type : Mutant - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x190 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x194 - Type : Semaphore - Name : \Sessions\1\BaseNamedObjects\SM0:4912:120:WilError_02_p0h
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x198 - Type : File - Name : \Device\HarddiskVolume4\Windows\SystemResources\notepad.exe.mun
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x19C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1A0 - Type : Section - Name : \Windows\Theme3372165587
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1AC - Type : Section - Name : \Sessions\1\Windows\Theme1817300183
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B0 - Type : File - Name : \Device\HarddiskVolume4\Windows\Fonts\StaticCache.dat
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x1B4 - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x200 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Session Manager
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x204 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x208 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x20C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x210 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x214 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\HwOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x218 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\ProviderOrder
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x21C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x220 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x268 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x26C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x27C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x280 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x284 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x288 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x28C - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x294 - Type : ALPC Port - Name : \RPC Control\OLEF8D468628B9656595E6360AB99DE
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x298 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x29C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A4 - Type : Section - Name : \BaseNamedObjects\__ComCatalogCache__
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2A8 - Type : File - Name : \Device\HarddiskVolume4\Windows\Registration\R000000000015.clb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2AC - Type : Section - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B0 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2B4 - Type : Key - Name : \REGISTRY\MACHINE\SOFTWARE\Classes\PackagedCom\ClassIndex
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2BC - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C0 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C4 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2C8 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2CC - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x2D0 - Type : File - Name : \Device\DeviceApi
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x300 - Type : File - Name : \Device\HarddiskVolume4\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.959_none_e6c7bbbf130c62bb
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x304 - Type : Key - Name : \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Nls\Sorting\Ids
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x308 - Type : Key - Name : \REGISTRY\USER\S-1-5-21-3423049853-1102793660-1424913857-1001_Classes
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x30C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x314 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x318 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x31C - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x320 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x324 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x328 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x32C - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x330 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x334 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x338 - Type : Semaphore - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x350 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x354 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x358 - Type : Timer - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x35C - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x360 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x364 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x368 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x36C - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x370 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x374 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x378 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x37C - Type : IoCompletionReserve - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x380 - Type : Thread - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x384 - Type : ALPC Port - Name : \BaseNamedObjects\[CoreUI]-PID(4912)-TID(31772) 60e8da57-b536-4a70-a860-3a3f442cd252
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x388 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x38C - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x390 - Type : WaitCompletionPacket - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A0 - Type : Event - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A4 - Type : ALPC Port - Name : 
    pid = 4912 - Name = C:\Windows\System32\notepad.exe - Handle : 0x3A8 - Type : Thread - Name : 



    I have done other tests also on other PCs but the result in terms of speed is more or less the same (about 4-5 minutes for a process with about 500 handles), thank you for your help!

    Saturday, August 1, 2020 4:44 PM
  • I made a basic Process Viewer listing Handles, with a few changes  :

    It is only slow in Debug, but OK in Release (not as fast as Process Explorer, which uses a Driver)

    You can test the executable : CSharp_NtQuerySystemInformation2_exe.zip

    If it is not slow on your PCs, I will post the source, otherwise, it is useless...

    • Marked as answer by C2002 Monday, August 3, 2020 12:48 PM
    Monday, August 3, 2020 9:45 AM
  • I made a basic Process Viewer listing Handles, with a few changes  :

    It is only slow in Debug, but OK in Release (not as fast as Process Explorer, which uses a Driver)

    You can test the executable : CSharp_NtQuerySystemInformation2_exe.zip

    If it is not slow on your PCs, I will post the source, otherwise, it is useless...

    Yes, it's fast, I don't notice much difference with other similar programs. Sorry if it's too much to ask, but could you add the "Find handles" function so that you can find the handles by object name? Thank you so much for helping me.
    Monday, August 3, 2020 12:54 PM
  • The main function : GetHandlesFromPID

    =>

    (it mimics the "C++ way" and can certainly be improved/optimized)

    public class HandleClass
    {
        public string Handle { get; set; }
        public string Type { get; set; }
        public string Name { get; set; }
    }
    
    
    public List<HandleClass> GetHandlesFromPID(int nPID)
    { 
        List<HandleClass> handleList = new List<HandleClass>();
    
        int nStatus = STATUS_SUCCESS;
        IntPtr pLargeBuffer = IntPtr.Zero;
        int nCbLargeBuffer = 64 * 1024;
        int nReturnLength = 0;
        for (;;)
        {
            pLargeBuffer = Marshal.AllocHGlobal(nCbLargeBuffer);
            //nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);
            nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);                
            if ((nStatus == STATUS_SUCCESS))
            {
                break;
            }
            if ((nStatus == STATUS_INFO_LENGTH_MISMATCH))
            {
                Marshal.FreeHGlobal(pLargeBuffer);
                //nCbLargeBuffer += 8192;
                nCbLargeBuffer += nReturnLength;
            }
            else
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }
    
        int nCount = System.Convert.ToInt32(Marshal.PtrToStructure(pLargeBuffer, typeof(int)));
        IntPtr pLargeBufferNew = IntPtr.Zero;
        //pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int));
        pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int))*2;
        SYSTEM_HANDLE_INFORMATION_EX pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
        for (int nIndex = 0; nIndex <= nCount; nIndex++)
        {
            pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION_EX));
            pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
            if (nPID != -1 && pHandleInfo.UniqueProcessId == nPID)
            {
                string sType = "";
                string sName = "";
                IntPtr hDup = IntPtr.Zero;
                IntPtr hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, pHandleInfo.UniqueProcessId);
                if (hProcess != IntPtr.Zero)
                {
                    bool bReturn = DuplicateHandle(hProcess, (IntPtr)pHandleInfo.HandleValue, GetCurrentProcess(), ref hDup, 0, false, DUPLICATE_SAME_ACCESS);
                    if (hDup != IntPtr.Zero)
                    {
                        IntPtr pObjectType = IntPtr.Zero;
                        var oti = new OBJECT_TYPE_INFORMATION();
                        uint nLength = 0x1000;
                        pObjectType = Marshal.AllocHGlobal((int)nLength);
                        while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
                        //while (NtQueryObject((IntPtr)pHandleInfo.Handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                        {
                            Marshal.FreeHGlobal(pObjectType);
                            pObjectType = Marshal.AllocHGlobal((int)nLength);
                        }
                        oti = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(pObjectType, typeof(OBJECT_TYPE_INFORMATION));
                        sType = oti.TypeName.Buffer;
                        Marshal.FreeHGlobal(pObjectType);
    
                        if (sType == "Directory" || sType == "File" || sType == "Section" || sType == "Key" || sType == "WindowStation"
                            || sType == "Desktop" || sType == "Semaphore" || sType == "Mutant")
                        {
                            int nTId;
                            HTT htt = new HTT();
                            htt.handle = hDup;
                            IntPtr pHTT = Marshal.AllocHGlobal(Marshal.SizeOf(htt));
                            Marshal.StructureToPtr(htt, pHTT, false);
                            IntPtr hThread = CreateThread(IntPtr.Zero, 0, pThreadProc, pHTT, 0, out nTId);
                            if (WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT)
                            {
                                TerminateThread(hThread, 0);
                                sName = "<Locked>";
                            }
                            else
                            {
                                var httret = (HTT)Marshal.PtrToStructure(pHTT, typeof(HTT));
                                sName = httret.txt;
                            }
                            Marshal.FreeHGlobal(pHTT);
                        }
    
                        if (sType == "Process" && (sName == "" || sName == null))
                        {
                            PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                            nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
                            if (nStatus == 0)
                            {
                                //System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
                                //string sProcName = proc.ProcessName;
                                IntPtr hProcessForName = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, (uint)pbi.UniqueProcessId);
                                if (hProcessForName != IntPtr.Zero)
                                {
                                    uint nSize = 260;
                                    StringBuilder sProcessImageName = new StringBuilder((int)nSize);
                                    QueryFullProcessImageName(hProcessForName, 0, sProcessImageName, ref nSize);
                                    sName = sProcessImageName.ToString();
                                    CloseHandle(hProcessForName);
                                }
                                else
                                {
                                    int nError = Marshal.GetLastWin32Error();
                                }
                            }
                        }
                        CloseHandle(hDup);                           
                    }
                    else
                    {
                        int nError = Marshal.GetLastWin32Error();
                        if (nError == 5)
                            sType = "<Access denied>";
                        else
                        {
                          // ERROR_NOT_SUPPORTED  50(0x32)
                        }
                    }
                    CloseHandle(hProcess);
                }
                else
                {
                    int nError = Marshal.GetLastWin32Error();
                    if (nError == 5)
                        sType = "<Access denied>";
                }
    
                if (sType != "")
                { 
                    HandleClass handle = new HandleClass();
                    handle.Handle = string.Format("0x{0:x2}", pHandleInfo.HandleValue);
                    handle.Type = sType;
                    handle.Name = sName;
                    handleList.Add(handle);
                }
            }
        }
        Marshal.FreeHGlobal(pLargeBuffer);         
        return handleList;
    }  

    Declarations :

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct SYSTEM_HANDLE_INFORMATION_EX                      
    {                                                               
        public IntPtr Object;                                       
        public uint UniqueProcessId;                                
        public uint HandleValue;                                    
        public uint GrantedAccess;                                  
        public ushort CreatorBackTraceIndex;                        
        public ushort ObjectTypeIndex;                              
        public uint HandleAttributes;                               
        public uint Reserved;                                       
    }
            
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                                                                                    
    public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress,
        IntPtr lpParameter, int dwCreationFlags, out int lpThreadId);                                           
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);                           
                                                                                                        
    public const int WAIT_TIMEOUT = 258;                                                                        
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern bool TerminateThread(IntPtr hThread, int dwExitCode); 
    
    [StructLayout(LayoutKind.Sequential)]
    public struct HTT
    {
        public IntPtr handle;
        public string txt;
    }
    
    private delegate int PTHREAD_START_ROUTINE(IntPtr lpParameter);
    private static readonly PTHREAD_START_ROUTINE pThreadStartRoutine = ThreadProc;
    private static readonly IntPtr pThreadProc = Marshal.GetFunctionPointerForDelegate(pThreadStartRoutine);
    
    private static int ThreadProc(IntPtr lpParameter)
    {
        var htt = (HTT)Marshal.PtrToStructure(lpParameter, typeof(HTT));
        IntPtr pObjectName = IntPtr.Zero;
        var oni = new OBJECT_NAME_INFORMATION();
        uint nLength = 0x1000;
        pObjectName = Marshal.AllocHGlobal((int)nLength);
        while (NtQueryObject(htt.handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, pObjectName, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
        {
            Marshal.FreeHGlobal(pObjectName);
            pObjectName = Marshal.AllocHGlobal((int)nLength);
        }
        oni = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(pObjectName, typeof(OBJECT_NAME_INFORMATION));
        Marshal.FreeHGlobal(pObjectName);
        htt.txt = oni.Name.Buffer;
        Marshal.StructureToPtr(htt, lpParameter, false);
        return 0;            
    } 

    • Marked as answer by C2002 Monday, August 3, 2020 2:26 PM
    Monday, August 3, 2020 2:00 PM
  • The main function : GetHandlesFromPID

    =>

    (it mimics the "C++ way" and can certainly be improved/optimized)

    public class HandleClass
    {
        public string Handle { get; set; }
        public string Type { get; set; }
        public string Name { get; set; }
    }
    
    
    public List<HandleClass> GetHandlesFromPID(int nPID)
    { 
        List<HandleClass> handleList = new List<HandleClass>();
    
        int nStatus = STATUS_SUCCESS;
        IntPtr pLargeBuffer = IntPtr.Zero;
        int nCbLargeBuffer = 64 * 1024;
        int nReturnLength = 0;
        for (;;)
        {
            pLargeBuffer = Marshal.AllocHGlobal(nCbLargeBuffer);
            //nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);
            nStatus = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, pLargeBuffer, nCbLargeBuffer, ref nReturnLength);                
            if ((nStatus == STATUS_SUCCESS))
            {
                break;
            }
            if ((nStatus == STATUS_INFO_LENGTH_MISMATCH))
            {
                Marshal.FreeHGlobal(pLargeBuffer);
                //nCbLargeBuffer += 8192;
                nCbLargeBuffer += nReturnLength;
            }
            else
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }
    
        int nCount = System.Convert.ToInt32(Marshal.PtrToStructure(pLargeBuffer, typeof(int)));
        IntPtr pLargeBufferNew = IntPtr.Zero;
        //pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int));
        pLargeBufferNew = pLargeBuffer + Marshal.SizeOf(typeof(int))*2;
        SYSTEM_HANDLE_INFORMATION_EX pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
        for (int nIndex = 0; nIndex <= nCount; nIndex++)
        {
            pLargeBufferNew += Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION_EX));
            pHandleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pLargeBufferNew, typeof(SYSTEM_HANDLE_INFORMATION_EX));
            if (nPID != -1 && pHandleInfo.UniqueProcessId == nPID)
            {
                string sType = "";
                string sName = "";
                IntPtr hDup = IntPtr.Zero;
                IntPtr hProcess = OpenProcess(PROCESS_DUP_HANDLE, false, pHandleInfo.UniqueProcessId);
                if (hProcess != IntPtr.Zero)
                {
                    bool bReturn = DuplicateHandle(hProcess, (IntPtr)pHandleInfo.HandleValue, GetCurrentProcess(), ref hDup, 0, false, DUPLICATE_SAME_ACCESS);
                    if (hDup != IntPtr.Zero)
                    {
                        IntPtr pObjectType = IntPtr.Zero;
                        var oti = new OBJECT_TYPE_INFORMATION();
                        uint nLength = 0x1000;
                        pObjectType = Marshal.AllocHGlobal((int)nLength);
                        while (NtQueryObject(hDup, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
                        //while (NtQueryObject((IntPtr)pHandleInfo.Handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, pObjectType, nLength, ref nLength) == (int)STATUS_INFO_LENGTH_MISMATCH)
                        {
                            Marshal.FreeHGlobal(pObjectType);
                            pObjectType = Marshal.AllocHGlobal((int)nLength);
                        }
                        oti = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(pObjectType, typeof(OBJECT_TYPE_INFORMATION));
                        sType = oti.TypeName.Buffer;
                        Marshal.FreeHGlobal(pObjectType);
    
                        if (sType == "Directory" || sType == "File" || sType == "Section" || sType == "Key" || sType == "WindowStation"
                            || sType == "Desktop" || sType == "Semaphore" || sType == "Mutant")
                        {
                            int nTId;
                            HTT htt = new HTT();
                            htt.handle = hDup;
                            IntPtr pHTT = Marshal.AllocHGlobal(Marshal.SizeOf(htt));
                            Marshal.StructureToPtr(htt, pHTT, false);
                            IntPtr hThread = CreateThread(IntPtr.Zero, 0, pThreadProc, pHTT, 0, out nTId);
                            if (WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT)
                            {
                                TerminateThread(hThread, 0);
                                sName = "<Locked>";
                            }
                            else
                            {
                                var httret = (HTT)Marshal.PtrToStructure(pHTT, typeof(HTT));
                                sName = httret.txt;
                            }
                            Marshal.FreeHGlobal(pHTT);
                        }
    
                        if (sType == "Process" && (sName == "" || sName == null))
                        {
                            PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                            nStatus = NtQueryInformationProcess(hDup, PROCESSINFOCLASS.ProcessBasicInformation, pbi, (int)Marshal.SizeOf(pbi), null);
                            if (nStatus == 0)
                            {
                                //System.Diagnostics.Process proc = System.Diagnostics.Process.GetProcessById((int)pbi.UniqueProcessId);
                                //string sProcName = proc.ProcessName;
                                IntPtr hProcessForName = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, (uint)pbi.UniqueProcessId);
                                if (hProcessForName != IntPtr.Zero)
                                {
                                    uint nSize = 260;
                                    StringBuilder sProcessImageName = new StringBuilder((int)nSize);
                                    QueryFullProcessImageName(hProcessForName, 0, sProcessImageName, ref nSize);
                                    sName = sProcessImageName.ToString();
                                    CloseHandle(hProcessForName);
                                }
                                else
                                {
                                    int nError = Marshal.GetLastWin32Error();
                                }
                            }
                        }
                        CloseHandle(hDup);                           
                    }
                    else
                    {
                        int nError = Marshal.GetLastWin32Error();
                        if (nError == 5)
                            sType = "<Access denied>";
                        else
                        {
                          // ERROR_NOT_SUPPORTED  50(0x32)
                        }
                    }
                    CloseHandle(hProcess);
                }
                else
                {
                    int nError = Marshal.GetLastWin32Error();
                    if (nError == 5)
                        sType = "<Access denied>";
                }
    
                if (sType != "")
                { 
                    HandleClass handle = new HandleClass();
                    handle.Handle = string.Format("0x{0:x2}", pHandleInfo.HandleValue);
                    handle.Type = sType;
                    handle.Name = sName;
                    handleList.Add(handle);
                }
            }
        }
        Marshal.FreeHGlobal(pLargeBuffer);         
        return handleList;
    }  

    Declarations :

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct SYSTEM_HANDLE_INFORMATION_EX                      
    {                                                               
        public IntPtr Object;                                       
        public uint UniqueProcessId;                                
        public uint HandleValue;                                    
        public uint GrantedAccess;                                  
        public ushort CreatorBackTraceIndex;                        
        public ushort ObjectTypeIndex;                              
        public uint HandleAttributes;                               
        public uint Reserved;                                       
    }
            
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                                                                                    
    public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress,
        IntPtr lpParameter, int dwCreationFlags, out int lpThreadId);                                           
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);                           
                                                                                                        
    public const int WAIT_TIMEOUT = 258;                                                                        
                                                                                                        
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]                                 
    public static extern bool TerminateThread(IntPtr hThread, int dwExitCode); 
    
    [StructLayout(LayoutKind.Sequential)]
    public struct HTT
    {
        public IntPtr handle;
        public string txt;
    }
    
    private delegate int PTHREAD_START_ROUTINE(IntPtr lpParameter);
    private static readonly PTHREAD_START_ROUTINE pThreadStartRoutine = ThreadProc;
    private static readonly IntPtr pThreadProc = Marshal.GetFunctionPointerForDelegate(pThreadStartRoutine);
    
    private static int ThreadProc(IntPtr lpParameter)
    {
        var htt = (HTT)Marshal.PtrToStructure(lpParameter, typeof(HTT));
        IntPtr pObjectName = IntPtr.Zero;
        var oni = new OBJECT_NAME_INFORMATION();
        uint nLength = 0x1000;
        pObjectName = Marshal.AllocHGlobal((int)nLength);
        while (NtQueryObject(htt.handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, pObjectName, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH)
        {
            Marshal.FreeHGlobal(pObjectName);
            pObjectName = Marshal.AllocHGlobal((int)nLength);
        }
        oni = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(pObjectName, typeof(OBJECT_NAME_INFORMATION));
        Marshal.FreeHGlobal(pObjectName);
        htt.txt = oni.Name.Buffer;
        Marshal.StructureToPtr(htt, lpParameter, false);
        return 0;            
    } 

    Ok I tried it and it actually gives me all the handles back in 1 second. But the problem comes again when I have to get all the handles of all the processes on the PC to search among them the one with the name I want.
    Monday, August 3, 2020 8:41 PM
  • I've tried it again by running it outside Visual Studio, on other PCs and with higher privileges just to try but when it comes to having to look for a handle between all the processes it takes an eternity even if it's very fast for every single process.
    Thursday, August 6, 2020 8:04 PM