最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How do I get all the open handles of a process using PowerShell? - Stack Overflow

programmeradmin1浏览0评论

When investigating what files a process is currently actively working with, I can use tools from Sysinternals like handle.exe or procexp.exe and then look for names looking like file patterns.

But when I query for the open handles of a process using PowerShell, I can only seem to get the number of handles. Not the actual handle references itself.

Get-Process -Id $SomePid | select Handles

The same goes for using .Net calls

[System.Diagnostics.Process]::GetProcessById($SomePid).Handles

And WMI will also strike out, only providing me with the amount of handles...

Get-CimSession Win32_Process -Filter "Process = $SomePid" | select HandleCount

When investigating what files a process is currently actively working with, I can use tools from Sysinternals like handle.exe or procexp.exe and then look for names looking like file patterns.

But when I query for the open handles of a process using PowerShell, I can only seem to get the number of handles. Not the actual handle references itself.

Get-Process -Id $SomePid | select Handles

The same goes for using .Net calls

[System.Diagnostics.Process]::GetProcessById($SomePid).Handles

And WMI will also strike out, only providing me with the amount of handles...

Get-CimSession Win32_Process -Filter "Process = $SomePid" | select HandleCount

Share Improve this question edited Jan 30 at 3:31 Santiago Squarzon 62k5 gold badges24 silver badges54 bronze badges asked Jan 29 at 17:56 DennisDennis 1,9072 gold badges17 silver badges41 bronze badges 7
  • 1 This will be a painful chunk of p/invoke code, which is one good reason why handle.exe already exist. – Santiago Squarzon Commented Jan 29 at 18:05
  • Yes, but I can't use handle.exe if I can't distribute it with my script everywhere I'd like to look for handles (which I can't :/ ) – Dennis Commented Jan 29 at 18:23
  • I found this old article, Enum HANDLEs for current process , but it's written in C++ – Dennis Commented Jan 29 at 18:31
  • Don't even know if this is possible with p/invoke, meaning not possible from PowerShell. – Santiago Squarzon Commented Jan 29 at 18:34
  • Seems like that :/ – Dennis Commented Jan 29 at 21:13
 |  Show 2 more comments

2 Answers 2

Reset to default 1

As stated in comments, it would be a big chunk of P/Invoke code, hopefully this help you giving you a start.

The current implementation will list all open handles in your system using NtQuerySystemInformation function. You can later use PowerShell to filter by the UniqueProcessId property of these objects. However, note this implementation provides limited information, see the SystemHandle class in the code.

To get the handle TypeName the implementation uses NtQueryObject function, however from here gets more complex as you need handle each type differently and call different Win APIs. For example, for File handles, you would use GetFileInformationByHandleEx function and so on.

Usage

Put the code below in a file, call it whatever you want (in this example HandleStuff.cs), and then you can do:

$code = Get-Content .\HandleStuff.cs -Raw
Add-Type $code -IgnoreWarnings -WA 0

[HandleStuff.Native]::GetSystemHandles()

You can also inline the code in the same PowerShell file if you want, or, in PowerShell 5.1 you can use Add-Type ... -OutputAssembly <path> if you want to have a compiled version in a .dll to faster loading.

Code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace HandleStuff
{
    public class SystemHandle
    {
        private readonly SYSTEM_HANDLE _handle;
        private readonly string _type;
        public string TypeName
        {
            get { return _type; }
        }
        public IntPtr Object
        {
            get { return _handle.Object; }
        }
        public IntPtr UniqueProcessId
        {
            get { return _handle.UniqueProcessId; }
        }
        public IntPtr HandleValue
        {
            get { return _handle.HandleValue; }
        }
        public uint GrantedAccess
        {
            get { return _handle.GrantedAccess; }
        }
        public ushort ObjectTypeIndex
        {
            get { return _handle.ObjectTypeIndex; }
        }
        public uint HandleAttributes
        {
            get { return _handle.HandleAttributes; }
        }

        internal SystemHandle(string type, SYSTEM_HANDLE handle)
        {
            _type = type;
            _handle = handle;
        }
    }

    internal enum OBJECT_INFORMATION_CLASS
    {
        ObjectTypeInformation = 2
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct PUBLIC_OBJECT_TYPE_INFORMATION
    {
        internal UNICODE_STRING TypeName;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
        internal uint[] Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct UNICODE_STRING
    {
        internal ushort Length;
        internal ushort MaximumLength;
        internal IntPtr Buffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SYSTEM_HANDLE
    {
        internal IntPtr Object;
        internal IntPtr UniqueProcessId;
        internal IntPtr HandleValue;
        internal uint GrantedAccess;
        internal ushort CreatorBackTraceIndex;
        internal ushort ObjectTypeIndex;
        internal uint HandleAttributes;
        internal uint Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SYSTEM_HANDLE_INFORMATION_EX
    {
        internal UIntPtr HandleCount;
        internal UIntPtr Reserved;
        internal SYSTEM_HANDLE Handles;
    }

    internal enum SYSTEM_INFORMATION_CLASS
    {
        SystemExtendedHandleInformation = 64
    }

    public static class Native
    {
        [DllImport("ntdll.dll")]
        private static extern uint NtQuerySystemInformation(
            [In] SYSTEM_INFORMATION_CLASS SystemInformationClass,
            [Out] IntPtr SystemInformation,
            [In] int SystemInformationLength,
            [Out] out int ReturnLength);

        [DllImport("ntdll.dll")]
        private static extern uint RtlNtStatusToDosError(
            [In] uint Status);

        [DllImport("ntdll.dll")]
        private static extern uint NtQueryObject(
            [In] IntPtr Handle,
            [In] OBJECT_INFORMATION_CLASS ObjectInformationClass,
            [Out] IntPtr ObjectInformation,
            [In] int ObjectInformationLength,
            [Out] out int ReturnLength);

        public static SystemHandle[] GetSystemHandles()
        {
            List<SystemHandle> handles;
            IntPtr sysInfo = IntPtr.Zero;

            try
            {
                sysInfo = GetSysHandleInfo();

                SYSTEM_HANDLE_INFORMATION_EX handleInfo = Marshal
                    .PtrToStructure<SYSTEM_HANDLE_INFORMATION_EX>(sysInfo);

                IntPtr handlesPtr = IntPtr.Add(
                    sysInfo,
                    Marshal.OffsetOf<SYSTEM_HANDLE_INFORMATION_EX>("Handles").ToInt32());

                uint handleCount = handleInfo.HandleCount.ToUInt32();
                int handleSize = Marshal.SizeOf<SYSTEM_HANDLE>();
                handles = new List<SystemHandle>((int)handleCount);

                for (int i = 0; i < handleCount; i++)
                {
                    IntPtr handlePtr = IntPtr.Add(handlesPtr, i * handleSize);
                    SYSTEM_HANDLE handle = Marshal.PtrToStructure<SYSTEM_HANDLE>(handlePtr);
                    handles.Add(new SystemHandle(GetHandleTypeName(handle.HandleValue), handle));
                }
            }
            finally
            {
                if (sysInfo != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(sysInfo);
                }
            }

            return handles.ToArray();
        }

        private static IntPtr GetSysHandleInfo()
        {
            int size = 512;
            IntPtr sysInfo = IntPtr.Zero;

            while (true)
            {
                if (sysInfo != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(sysInfo);
                }

                sysInfo = Marshal.AllocHGlobal(size);

                uint status = NtQuerySystemInformation(
                    SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation,
                    sysInfo,
                    size,
                    out size);

                if (status == 0)
                {
                    break;
                }

                if (status != 0xc0000004)
                {
                    throw new Win32Exception((int)RtlNtStatusToDosError(status));
                }

                size *= 2;
            }

            return sysInfo;
        }

        private static string GetHandleTypeName(IntPtr handle)
        {
            int size = 512;
            IntPtr objectInfoBuffer = IntPtr.Zero;

            try
            {
                while (true)
                {
                    if (objectInfoBuffer != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(objectInfoBuffer);
                    }

                    objectInfoBuffer = Marshal.AllocHGlobal(size);

                    uint status = NtQueryObject(
                        handle,
                        OBJECT_INFORMATION_CLASS.ObjectTypeInformation,
                        objectInfoBuffer,
                        size,
                        out size);

                    if (status == 0)
                    {
                        PUBLIC_OBJECT_TYPE_INFORMATION info = Marshal
                            .PtrToStructure<PUBLIC_OBJECT_TYPE_INFORMATION>(objectInfoBuffer);

                        if (info.TypeName.Buffer == IntPtr.Zero)
                        {
                            return string.Empty;
                        }

                        return Marshal.PtrToStringUni(info.TypeName.Buffer, info.TypeName.Length / 2);
                    }

                    if (status != 0xc0000004)
                    {
                        return string.Empty;
                    }

                    size *= 2;
                }
            }
            finally
            {
                if (objectInfoBuffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(objectInfoBuffer);
                }
            }
        }
    }
}

Did you look at the Modules property of Get-Process?
Get-Process <process name> | Select -expand Modules

It outputs like this:

PS C:\Windows\System32> get-process vds | Select -ExpandProperty modules

   Size(K) ModuleName                     FileName
   ------- ----------                     -------- 
       692 vds.exe                        C:\windows\System32\vds.exe
      1976 ntdll.dll                      C:\windows\SYSTEM32\ntdll.dll
       716 KERNEL32.DLL                   C:\windows\System32\KERNEL32.DLL
      2676 KERNELBASE.dll                 C:\windows\System32\KERNELBASE.dll
       672 ADVAPI32.DLL                   C:\windows\System32\ADVAPI32.DLL
       632 msvcrt.dll                     C:\windows\System32\msvcrt.dll
...
发布评论

评论列表(0)

  1. 暂无评论