Skip to content

Instantly share code, notes, and snippets.

@santisq
Last active January 31, 2025 21:17
Show Gist options
  • Select an option

  • Save santisq/28b79c0ae6b9fc974772c04e41ba6c32 to your computer and use it in GitHub Desktop.

Select an option

Save santisq/28b79c0ae6b9fc974772c04e41ba6c32 to your computer and use it in GitHub Desktop.

Revisions

  1. santisq revised this gist Jan 31, 2025. 1 changed file with 45 additions and 34 deletions.
    79 changes: 45 additions & 34 deletions handles.cs
    Original file line number Diff line number Diff line change
    @@ -98,8 +98,8 @@ public static class Native
    private static extern uint NtQuerySystemInformation(
    [In] SYSTEM_INFORMATION_CLASS SystemInformationClass,
    [Out] IntPtr SystemInformation,
    [In] uint SystemInformationLength,
    [Out] out uint ReturnLength);
    [In] int SystemInformationLength,
    [Out] out int ReturnLength);

    [DllImport("ntdll.dll")]
    private static extern uint RtlNtStatusToDosError(
    @@ -115,43 +115,18 @@ private static extern uint NtQueryObject(

    public static SystemHandle[] GetSystemHandles()
    {
    uint size = (uint)Marshal.SizeOf<SYSTEM_HANDLE_INFORMATION_EX>();
    IntPtr pHandleInfo = IntPtr.Zero;
    List<SystemHandle> handles;
    IntPtr sysInfo = IntPtr.Zero;

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

    pHandleInfo = Marshal.AllocHGlobal((int)size);

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

    if (status == 0)
    {
    break;
    }

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

    size *= 2;
    }
    sysInfo = GetSysHandleInfo();

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

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

    uint handleCount = handleInfo.HandleCount.ToUInt32();
    @@ -167,18 +142,54 @@ public static SystemHandle[] GetSystemHandles()
    }
    finally
    {
    if (pHandleInfo != IntPtr.Zero)
    if (sysInfo != IntPtr.Zero)
    {
    Marshal.FreeHGlobal(pHandleInfo);
    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 = Marshal.SizeOf<PUBLIC_OBJECT_TYPE_INFORMATION>();
    int size = 512;
    IntPtr objectInfoBuffer = IntPtr.Zero;

    try
  2. santisq revised this gist Jan 31, 2025. 1 changed file with 136 additions and 107 deletions.
    243 changes: 136 additions & 107 deletions handles.cs
    Original file line number Diff line number Diff line change
    @@ -5,92 +5,86 @@

    namespace HandleStuff
    {
    public class ResultObject
    public class SystemHandle
    {
    public OBJECT_TYPE_INFORMATION Information { get; set; }
    public SYSTEM_HANDLE SystemHandle { get; set; }
    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 ResultObject(OBJECT_TYPE_INFORMATION info, SYSTEM_HANDLE handle)
    internal SystemHandle(string type, SYSTEM_HANDLE handle)
    {
    Information = info;
    SystemHandle = handle;
    _type = type;
    _handle = handle;
    }
    }

    public enum OBJECT_INFORMATION_CLASS
    internal enum OBJECT_INFORMATION_CLASS
    {
    ObjectTypeInformation = 2
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct OBJECT_TYPE_INFORMATION
    {
    public UNICODE_STRING TypeName;
    public ulong TotalNumberOfObjects;
    public ulong TotalNumberOfHandles;
    public ulong TotalPagedPoolUsage;
    public ulong TotalNonPagedPoolUsage;
    public ulong TotalNamePoolUsage;
    public ulong TotalHandleTableUsage;
    public ulong HighWaterNumberOfObjects;
    public ulong HighWaterNumberOfHandles;
    public ulong HighWaterPagedPoolUsage;
    public ulong HighWaterNonPagedPoolUsage;
    public ulong HighWaterNamePoolUsage;
    public ulong HighWaterHandleTableUsage;
    public uint InvalidAttributes;
    public GENERIC_MAPPING GenericMapping;
    public uint ValidAccessMask;
    public bool SecurityRequired;
    public bool MaintainHandleCount;
    public uint PoolType;
    public uint DefaultPagedPoolCharge;
    public uint DefaultNonPagedPoolCharge;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UNICODE_STRING
    internal struct PUBLIC_OBJECT_TYPE_INFORMATION
    {
    public ushort Length;
    public ushort MaximumLength;
    private readonly IntPtr buffer;
    public string Buffer
    {
    get
    {
    return buffer == IntPtr.Zero ? string.Empty : Marshal.PtrToStringUni(buffer);
    }
    }
    internal UNICODE_STRING TypeName;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
    internal uint[] Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct GENERIC_MAPPING
    internal struct UNICODE_STRING
    {
    public uint GenericRead;
    public uint GenericWrite;
    public uint GenericExecute;
    public uint GenericAll;
    internal ushort Length;
    internal ushort MaximumLength;
    internal IntPtr Buffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEM_HANDLE
    internal struct SYSTEM_HANDLE
    {
    public IntPtr Object;
    public IntPtr UniqueProcessId;
    public IntPtr HandleValue;
    public uint GrantedAccess;
    public ushort CreatorBackTraceIndex;
    public ushort ObjectTypeIndex;
    public uint HandleAttributes;
    public uint Reserved;
    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
    {
    public UIntPtr HandleCount;
    public UIntPtr Reserved;
    public SYSTEM_HANDLE Handles;
    internal UIntPtr HandleCount;
    internal UIntPtr Reserved;
    internal SYSTEM_HANDLE Handles;
    }

    internal enum SYSTEM_INFORMATION_CLASS
    @@ -103,90 +97,72 @@ public static class Native
    [DllImport("ntdll.dll")]
    private static extern uint NtQuerySystemInformation(
    [In] SYSTEM_INFORMATION_CLASS SystemInformationClass,
    IntPtr SystemInformation,
    uint SystemInformationLength,
    out uint ReturnLength);
    [Out] IntPtr SystemInformation,
    [In] uint SystemInformationLength,
    [Out] out uint ReturnLength);

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

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

    public static OBJECT_TYPE_INFORMATION GetObjectType(IntPtr handle)
    {
    int returnLength;
    IntPtr objectInfoBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OBJECT_TYPE_INFORMATION)));
    try
    {
    uint status = NtQueryObject(
    handle,
    OBJECT_INFORMATION_CLASS.ObjectTypeInformation,
    objectInfoBuffer,
    Marshal.SizeOf(typeof(OBJECT_TYPE_INFORMATION)),
    out returnLength);

    return (OBJECT_TYPE_INFORMATION)Marshal
    .PtrToStructure(objectInfoBuffer, typeof(OBJECT_TYPE_INFORMATION));
    }
    finally
    {
    Marshal.FreeHGlobal(objectInfoBuffer);
    }
    }
    [In] IntPtr Handle,
    [In] OBJECT_INFORMATION_CLASS ObjectInformationClass,
    [Out] IntPtr ObjectInformation,
    [In] int ObjectInformationLength,
    [Out] out int ReturnLength);

    public static ResultObject[] GetSystemHandles()
    public static SystemHandle[] GetSystemHandles()
    {
    uint len = 20;
    uint status;
    uint size = (uint)Marshal.SizeOf<SYSTEM_HANDLE_INFORMATION_EX>();
    IntPtr pHandleInfo = IntPtr.Zero;
    List<ResultObject> handles;
    List<SystemHandle> handles;

    try
    {
    do
    while (true)
    {
    len *= 2;
    if (pHandleInfo != IntPtr.Zero)
    {
    Marshal.FreeHGlobal(pHandleInfo);
    }

    pHandleInfo = Marshal.AllocHGlobal((int)len);
    status = NtQuerySystemInformation(
    pHandleInfo = Marshal.AllocHGlobal((int)size);

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

    if (status != 0x00000000 && status != 0xc0000004)
    if (status == 0)
    {
    break;
    }

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

    size *= 2;
    }
    while (status == 0xc0000004);

    SYSTEM_HANDLE_INFORMATION_EX handleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal
    .PtrToStructure(pHandleInfo, typeof(SYSTEM_HANDLE_INFORMATION_EX));
    SYSTEM_HANDLE_INFORMATION_EX handleInfo = Marshal
    .PtrToStructure<SYSTEM_HANDLE_INFORMATION_EX>(pHandleInfo);

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

    uint handleCount = handleInfo.HandleCount.ToUInt32();
    int handleSize = Marshal.SizeOf<SYSTEM_HANDLE>();
    handles = new List<ResultObject>((int)handleCount);
    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);
    OBJECT_TYPE_INFORMATION info = GetObjectType(handle.HandleValue);
    handles.Add(new ResultObject(info, handle));
    handles.Add(new SystemHandle(GetHandleTypeName(handle.HandleValue), handle));
    }
    }
    finally
    @@ -199,5 +175,58 @@ public static ResultObject[] GetSystemHandles()

    return handles.ToArray();
    }

    private static string GetHandleTypeName(IntPtr handle)
    {
    int size = Marshal.SizeOf<PUBLIC_OBJECT_TYPE_INFORMATION>();
    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);
    }
    }
    }
    }
    }
  3. santisq created this gist Jan 30, 2025.
    203 changes: 203 additions & 0 deletions handles.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,203 @@
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.InteropServices;

    namespace HandleStuff
    {
    public class ResultObject
    {
    public OBJECT_TYPE_INFORMATION Information { get; set; }
    public SYSTEM_HANDLE SystemHandle { get; set; }

    internal ResultObject(OBJECT_TYPE_INFORMATION info, SYSTEM_HANDLE handle)
    {
    Information = info;
    SystemHandle = handle;
    }
    }

    public enum OBJECT_INFORMATION_CLASS
    {
    ObjectTypeInformation = 2
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct OBJECT_TYPE_INFORMATION
    {
    public UNICODE_STRING TypeName;
    public ulong TotalNumberOfObjects;
    public ulong TotalNumberOfHandles;
    public ulong TotalPagedPoolUsage;
    public ulong TotalNonPagedPoolUsage;
    public ulong TotalNamePoolUsage;
    public ulong TotalHandleTableUsage;
    public ulong HighWaterNumberOfObjects;
    public ulong HighWaterNumberOfHandles;
    public ulong HighWaterPagedPoolUsage;
    public ulong HighWaterNonPagedPoolUsage;
    public ulong HighWaterNamePoolUsage;
    public ulong HighWaterHandleTableUsage;
    public uint InvalidAttributes;
    public GENERIC_MAPPING GenericMapping;
    public uint ValidAccessMask;
    public bool SecurityRequired;
    public bool MaintainHandleCount;
    public uint PoolType;
    public uint DefaultPagedPoolCharge;
    public uint DefaultNonPagedPoolCharge;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct UNICODE_STRING
    {
    public ushort Length;
    public ushort MaximumLength;
    private readonly IntPtr buffer;
    public string Buffer
    {
    get
    {
    return buffer == IntPtr.Zero ? string.Empty : Marshal.PtrToStringUni(buffer);
    }
    }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct GENERIC_MAPPING
    {
    public uint GenericRead;
    public uint GenericWrite;
    public uint GenericExecute;
    public uint GenericAll;
    }

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

    [StructLayout(LayoutKind.Sequential)]
    internal struct SYSTEM_HANDLE_INFORMATION_EX
    {
    public UIntPtr HandleCount;
    public UIntPtr Reserved;
    public 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,
    IntPtr SystemInformation,
    uint SystemInformationLength,
    out uint ReturnLength);

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

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

    public static OBJECT_TYPE_INFORMATION GetObjectType(IntPtr handle)
    {
    int returnLength;
    IntPtr objectInfoBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(OBJECT_TYPE_INFORMATION)));
    try
    {
    uint status = NtQueryObject(
    handle,
    OBJECT_INFORMATION_CLASS.ObjectTypeInformation,
    objectInfoBuffer,
    Marshal.SizeOf(typeof(OBJECT_TYPE_INFORMATION)),
    out returnLength);

    return (OBJECT_TYPE_INFORMATION)Marshal
    .PtrToStructure(objectInfoBuffer, typeof(OBJECT_TYPE_INFORMATION));
    }
    finally
    {
    Marshal.FreeHGlobal(objectInfoBuffer);
    }
    }

    public static ResultObject[] GetSystemHandles()
    {
    uint len = 20;
    uint status;
    IntPtr pHandleInfo = IntPtr.Zero;
    List<ResultObject> handles;

    try
    {
    do
    {
    len *= 2;
    if (pHandleInfo != IntPtr.Zero)
    {
    Marshal.FreeHGlobal(pHandleInfo);
    }

    pHandleInfo = Marshal.AllocHGlobal((int)len);
    status = NtQuerySystemInformation(
    SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation,
    pHandleInfo, len, out len);

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

    SYSTEM_HANDLE_INFORMATION_EX handleInfo = (SYSTEM_HANDLE_INFORMATION_EX)Marshal
    .PtrToStructure(pHandleInfo, typeof(SYSTEM_HANDLE_INFORMATION_EX));

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

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

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

    return handles.ToArray();
    }
    }
    }