@@ -72,6 +72,104 @@ typedef NTSTATUS (NTAPI *pNtQueryInformationProcess)(HANDLE, UINT, PVOID, ULONG,
7272typedef NTSTATUS (NTAPI *pNtWow64ReadVirtualMemory64)(HANDLE, ULONG64, PVOID, ULONG64, PULONG64);
7373typedef NTSTATUS (NTAPI *pNtWow64QueryInformationProcess64)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
7474
75+ #ifndef NT_SUCCESS
76+ #define NT_SUCCESS (x ) ((x) >= 0 )
77+ #endif
78+
79+ #ifndef STATUS_INFO_LENGTH_MISMATCH
80+ #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
81+ #endif
82+
83+ #ifndef SystemHandleInformation
84+ #define SystemHandleInformation 16
85+ #endif
86+
87+ #ifndef ObjectBasicInformation
88+ #define ObjectBasicInformation 0
89+ #endif
90+
91+ #ifndef ObjectNameInformation
92+ #define ObjectNameInformation 1
93+ #endif
94+
95+ #ifndef ObjectTypeInformation
96+ #define ObjectTypeInformation 2
97+ #endif
98+
99+ typedef struct _SYSTEM_HANDLE {
100+ ULONG ProcessId;
101+ BYTE ObjectTypeNumber;
102+ BYTE Flags;
103+ USHORT Handle;
104+ PVOID Object;
105+ ACCESS_MASK GrantedAccess;
106+ } SYSTEM_HANDLE, *PSYSTEM_HANDLE;
107+
108+ typedef struct _SYSTEM_HANDLE_INFORMATION {
109+ ULONG HandleCount;
110+ SYSTEM_HANDLE Handles[1 ];
111+ } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
112+
113+ typedef enum _POOL_TYPE {
114+ NonPagedPool,
115+ PagedPool,
116+ NonPagedPoolMustSucceed,
117+ DontUseThisType,
118+ NonPagedPoolCacheAligned,
119+ PagedPoolCacheAligned,
120+ NonPagedPoolCacheAlignedMustS
121+ } POOL_TYPE, *PPOOL_TYPE;
122+
123+ typedef struct _OBJECT_TYPE_INFORMATION {
124+ UNICODE_STRING Name;
125+ ULONG TotalNumberOfObjects;
126+ ULONG TotalNumberOfHandles;
127+ ULONG TotalPagedPoolUsage;
128+ ULONG TotalNonPagedPoolUsage;
129+ ULONG TotalNamePoolUsage;
130+ ULONG TotalHandleTableUsage;
131+ ULONG HighWaterNumberOfObjects;
132+ ULONG HighWaterNumberOfHandles;
133+ ULONG HighWaterPagedPoolUsage;
134+ ULONG HighWaterNonPagedPoolUsage;
135+ ULONG HighWaterNamePoolUsage;
136+ ULONG HighWaterHandleTableUsage;
137+ ULONG InvalidAttributes;
138+ GENERIC_MAPPING GenericMapping;
139+ ULONG ValidAccess;
140+ BOOLEAN SecurityRequired;
141+ BOOLEAN MaintainHandleCount;
142+ USHORT MaintainTypeList;
143+ POOL_TYPE PoolType;
144+ ULONG PagedPoolUsage;
145+ ULONG NonPagedPoolUsage;
146+ } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
147+
148+ typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
149+ SYSTEM_INFORMATION_CLASS SystemInformationClass,
150+ PVOID SystemInformation,
151+ ULONG SystemInformationLength,
152+ PULONG ReturnLength
153+ );
154+
155+ typedef NTSTATUS (NTAPI *_NtDuplicateObject)(
156+ HANDLE SourceProcessHandle,
157+ HANDLE SourceHandle,
158+ HANDLE TargetProcessHandle,
159+ PHANDLE TargetHandle,
160+ ACCESS_MASK DesiredAccess,
161+ ULONG Attributes,
162+ ULONG Options
163+ );
164+
165+ typedef NTSTATUS (NTAPI *_NtQueryObject)(
166+ HANDLE ObjectHandle,
167+ OBJECT_INFORMATION_CLASS ObjectInformationClass,
168+ PVOID ObjectInformation,
169+ ULONG ObjectInformationLength,
170+ PULONG ReturnLength
171+ );
172+
75173/*
76174
77175This is a Windows version of the tool witr, which is a utility for finding details about specific processes.
@@ -1489,6 +1587,225 @@ return WideToString(stringBuffer);
14891587 }
14901588#endif
14911589}
1590+ PVOID GetLibraryProcAddress (const char * LibraryName, const char * ProcName) {
1591+ HMODULE hMod = GetModuleHandleA (LibraryName);
1592+ if (!hMod) {
1593+ hMod = LoadLibraryA (LibraryName);
1594+ if (!hMod) return nullptr ;
1595+ }
1596+ return (PVOID)GetProcAddress (hMod, ProcName);
1597+ }
1598+
1599+ _NtQuerySystemInformation pfnNtQuerySystemInformation =
1600+ (_NtQuerySystemInformation)GetLibraryProcAddress(" ntdll.dll" , " NtQuerySystemInformation" );
1601+ _NtDuplicateObject pfnNtDuplicateObject =
1602+ (_NtDuplicateObject)GetLibraryProcAddress(" ntdll.dll" , " NtDuplicateObject" );
1603+ _NtQueryObject pfnNtQueryObject =
1604+ (_NtQueryObject)GetLibraryProcAddress(" ntdll.dll" , " NtQueryObject" );
1605+
1606+
1607+
1608+ void ListProcHandles (HANDLE hproc, DWORD pid) {
1609+ // this is so that we can get the handles of a process
1610+ // the cool thing is, that the original witr doesn't actually display
1611+ // handles because either the AI that vibe coded didn't know how to get
1612+ // or perhaps it just isn't even possible using Go
1613+ // so C++ for the win
1614+ // for the win-DOWS!! Haha get it
1615+
1616+ // if you're wondering why this code looks like C... that's because...
1617+ // because it is. i just stole it from this random old obscure forum by a guy
1618+ // who did the same thing i needed in 2013
1619+
1620+ // https://cplusplus.com/forum/windows/95774/
1621+ // one thing i've learned while coding this is that when you want to do
1622+ // some weird obscure thing that you're sure nobody has done before, the most likely thing
1623+ // is that the same weird obscure thing has been done before, but it's just really obscure
1624+
1625+ _NtQuerySystemInformation pfnNtQuerySystemInformation =
1626+ (_NtQuerySystemInformation)GetLibraryProcAddress (" ntdll.dll" , " NtQuerySystemInformation" );
1627+ _NtDuplicateObject pfnNtDuplicateObject =
1628+ (_NtDuplicateObject)GetLibraryProcAddress (" ntdll.dll" , " NtDuplicateObject" );
1629+ _NtQueryObject pfnNtQueryObject =
1630+ (_NtQueryObject)GetLibraryProcAddress (" ntdll.dll" , " NtQueryObject" );
1631+ NTSTATUS status;
1632+ PSYSTEM_HANDLE_INFORMATION handleInfo;
1633+ ULONG handleInfoSize = 0x10000 ;
1634+ ULONG i;
1635+
1636+
1637+
1638+
1639+
1640+
1641+
1642+ handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc (handleInfoSize);
1643+
1644+ /* NtQuerySystemInformation won't give us the correct buffer size,
1645+ so we guess by doubling the buffer size. */
1646+ while ((status = pfnNtQuerySystemInformation (
1647+ (SYSTEM_INFORMATION_CLASS)SystemHandleInformation,
1648+ handleInfo,
1649+ handleInfoSize,
1650+ NULL
1651+ )) == STATUS_INFO_LENGTH_MISMATCH)
1652+ handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc (handleInfo, handleInfoSize *= 2 );
1653+
1654+ /* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */
1655+ if (!NT_SUCCESS (status))
1656+ {
1657+ printf (" NtQuerySystemInformation failed!\n " );
1658+ return ;
1659+ }
1660+
1661+ for (i = 0 ; i < handleInfo->HandleCount ; i++)
1662+ {
1663+ SYSTEM_HANDLE handle = handleInfo->Handles [i];
1664+ HANDLE dupHandle = NULL ;
1665+ POBJECT_TYPE_INFORMATION objectTypeInfo;
1666+ PVOID objectNameInfo;
1667+ UNICODE_STRING objectName;
1668+ ULONG returnLength;
1669+
1670+ /* Check if this handle belongs to the PID the user specified. */
1671+ if (handle.ProcessId != pid)
1672+ continue ;
1673+
1674+ /* Duplicate the handle so we can query it. */
1675+ if (!NT_SUCCESS (pfnNtDuplicateObject (
1676+ hproc,
1677+ (HANDLE)(ULONG_PTR)handle.Handle ,
1678+ GetCurrentProcess (),
1679+ &dupHandle,
1680+ 0 ,
1681+ 0 ,
1682+ DUPLICATE_SAME_ACCESS
1683+ )))
1684+ {
1685+ printf (" [%#x] Error!\n " , handle.Handle );
1686+ continue ;
1687+ }
1688+
1689+ /* Query the object type. */
1690+ objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc (0x1000 );
1691+ if (!NT_SUCCESS (pfnNtQueryObject (
1692+ dupHandle,
1693+ (OBJECT_INFORMATION_CLASS)ObjectTypeInformation,
1694+ objectTypeInfo,
1695+ 0x1000 ,
1696+ NULL
1697+ )))
1698+ {
1699+ printf (" [%#x] Error!\n " , handle.Handle );
1700+ CloseHandle (dupHandle);
1701+ continue ;
1702+ }
1703+ /* Query the object type first */
1704+ objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc (0x1000 );
1705+ if (!NT_SUCCESS (pfnNtQueryObject (dupHandle, (OBJECT_INFORMATION_CLASS)ObjectTypeInformation, objectTypeInfo, 0x1000 , NULL ))) {
1706+ printf (" [%#x] Error!\n " , handle.Handle );
1707+ CloseHandle (dupHandle);
1708+ continue ;
1709+ }
1710+
1711+ /* Check if this type is known to hang on name queries */
1712+ WCHAR typeName[64 ];
1713+ wcsncpy_s (typeName, 64 , objectTypeInfo->Name .Buffer , objectTypeInfo->Name .Length / 2 );
1714+ typeName[objectTypeInfo->Name .Length / 2 ] = L' \0 ' ;
1715+
1716+ if (wcscmp (typeName, L" File" ) == 0 || wcscmp (typeName, L" ALPC Port" ) == 0 ) {
1717+ printf (" [%#x] %.*S: (name query skipped)\n " , handle.Handle ,
1718+ objectTypeInfo->Name .Length / 2 , objectTypeInfo->Name .Buffer );
1719+ free (objectTypeInfo);
1720+ CloseHandle (dupHandle);
1721+ continue ;
1722+ }
1723+ /* Query the object name (unless it has an access of
1724+ 0x0012019f, on which NtQueryObject could hang. */
1725+ if (handle.GrantedAccess == 0x0012019f )
1726+ {
1727+ /* We have the type, so display that. */
1728+ printf (
1729+ " [%#x] %.*S: (did not get name)\n " ,
1730+ handle.Handle ,
1731+ objectTypeInfo->Name .Length / 2 ,
1732+ objectTypeInfo->Name .Buffer
1733+ );
1734+ free (objectTypeInfo);
1735+ CloseHandle (dupHandle);
1736+ continue ;
1737+ }
1738+
1739+
1740+ objectNameInfo = malloc (0x1000 );
1741+ if (!NT_SUCCESS (pfnNtQueryObject (
1742+ dupHandle,
1743+ (OBJECT_INFORMATION_CLASS)ObjectNameInformation,
1744+ objectNameInfo,
1745+ 0x1000 ,
1746+ &returnLength
1747+ )))
1748+ {
1749+ /* Reallocate the buffer and try again. */
1750+ objectNameInfo = realloc (objectNameInfo, returnLength);
1751+ if (!NT_SUCCESS (pfnNtQueryObject (
1752+ dupHandle,
1753+ (OBJECT_INFORMATION_CLASS)ObjectNameInformation,
1754+ objectNameInfo,
1755+ returnLength,
1756+ NULL
1757+ )))
1758+ {
1759+ /* We have the type name, so just display that. */
1760+ printf (
1761+ " [%#x] %.*S: (could not get name)\n " ,
1762+ handle.Handle ,
1763+ objectTypeInfo->Name .Length / 2 ,
1764+ objectTypeInfo->Name .Buffer
1765+ );
1766+ free (objectTypeInfo);
1767+ free (objectNameInfo);
1768+ CloseHandle (dupHandle);
1769+ continue ;
1770+ }
1771+ }
1772+
1773+ /* Cast our buffer into an UNICODE_STRING. */
1774+ objectName = *(PUNICODE_STRING)objectNameInfo;
1775+
1776+ /* Print the information! */
1777+ if (objectName.Length )
1778+ {
1779+ /* The object has a name. */
1780+ printf (
1781+ " [%#x] %.*S: %.*S\n " ,
1782+ handle.Handle ,
1783+ objectTypeInfo->Name .Length / 2 ,
1784+ objectTypeInfo->Name .Buffer ,
1785+ objectName.Length / 2 ,
1786+ objectName.Buffer
1787+ );
1788+ }
1789+ else
1790+ {
1791+ /* Print something else. */
1792+ printf (
1793+ " [%#x] %.*S: (unnamed)\n " ,
1794+ handle.Handle ,
1795+ objectTypeInfo->Name .Length / 2 ,
1796+ objectTypeInfo->Name .Buffer
1797+ );
1798+ }
1799+
1800+ free (objectTypeInfo);
1801+ free (objectNameInfo);
1802+ CloseHandle (dupHandle);
1803+ }
1804+
1805+ free (handleInfo);
1806+
1807+ }
1808+
14921809
14931810void PrintAncestry (DWORD pid) {
14941811 // now we're geting the name
@@ -1747,7 +2064,7 @@ void PIDinspect(DWORD pid) { // ooh guys look i'm in the void
17472064
17482065
17492066
1750- HANDLE hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE , pid);
2067+ HANDLE hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE , FALSE , pid);
17512068 // The above little handle opener is currently a somwehat "agressive" flag, since it
17522069 // Requests read access directly to the process' actual memory. This can get us rejected if called
17532070 // on a very high privilege process, such as lsass.exe This means that we can't read the memory
@@ -1927,6 +2244,7 @@ std::string FRAM = ""; // fram means formatted ram, i'm so creative at var namin
19272244 PrintAncestry (pid);
19282245
19292246 FindProcessPorts (pid);
2247+ ListProcHandles (hProcess, pid);
19302248
19312249
19322250
0 commit comments