@@ -1604,6 +1604,59 @@ _NtQueryObject pfnNtQueryObject =
16041604 (_NtQueryObject)GetLibraryProcAddress(" ntdll.dll" , " NtQueryObject" );
16051605
16061606
1607+ // Structure to pass data to the worker thread
1608+ struct QueryObjectThreadData {
1609+ _NtQueryObject pfnNtQueryObject;
1610+ HANDLE handle;
1611+ PVOID buffer;
1612+ ULONG bufferSize;
1613+ NTSTATUS status;
1614+ volatile BOOL completed;
1615+ };
1616+
1617+ // Worker thread function
1618+ DWORD WINAPI QueryObjectThreadProc (LPVOID param) {
1619+ QueryObjectThreadData* data = (QueryObjectThreadData*)param;
1620+
1621+ data->status = data->pfnNtQueryObject (
1622+ data->handle ,
1623+ (OBJECT_INFORMATION_CLASS)ObjectNameInformation,
1624+ data->buffer ,
1625+ data->bufferSize ,
1626+ NULL
1627+ );
1628+
1629+ data->completed = TRUE ;
1630+ return 0 ;
1631+ }
1632+
1633+ // Safe query with 1ms timeout
1634+ bool QueryObjectNameSafe (_NtQueryObject pfnNtQueryObject, HANDLE handle,
1635+ PVOID buffer, ULONG bufferSize, NTSTATUS* outStatus) {
1636+ QueryObjectThreadData threadData = {0 };
1637+ threadData.pfnNtQueryObject = pfnNtQueryObject;
1638+ threadData.handle = handle;
1639+ threadData.buffer = buffer;
1640+ threadData.bufferSize = bufferSize;
1641+ threadData.completed = FALSE ;
1642+
1643+ HANDLE hThread = CreateThread (NULL , 0 , QueryObjectThreadProc, &threadData, 0 , NULL );
1644+ if (!hThread) return false ;
1645+
1646+ // Wait for 1ms
1647+ DWORD waitResult = WaitForSingleObject (hThread, 1 );
1648+
1649+ if (waitResult == WAIT_TIMEOUT) {
1650+ // Hung! Kill the thread (leaks the thread but keeps us fast)
1651+ TerminateThread (hThread, 1 );
1652+ CloseHandle (hThread);
1653+ return false ; // Timed out
1654+ }
1655+
1656+ *outStatus = threadData.status ;
1657+ CloseHandle (hThread);
1658+ return true ; // Success
1659+ }
16071660
16081661void ListProcHandles (HANDLE hproc, DWORD pid) {
16091662 // this is so that we can get the handles of a process
@@ -1708,33 +1761,19 @@ _NtQueryObject pfnNtQueryObject =
17081761 continue ;
17091762 }
17101763
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- }
1764+ NTSTATUS status;
1765+ if (!QueryObjectNameSafe (pfnNtQueryObject, dupHandle, objectNameInfo, 0x1000 , &status)) {
1766+ // Timed out after 1ms - likely a blocking handle
1767+ printf (" [%#x] %.*S: (query timed out)\n " ,
1768+ handle.Handle ,
1769+ objectTypeInfo->Name .Length / 2 ,
1770+ objectTypeInfo->Name .Buffer );
1771+ free (objectTypeInfo);
1772+ CloseHandle (dupHandle);
1773+ continue ;
1774+ }
1775+
1776+
17381777
17391778
17401779 objectNameInfo = malloc (0x1000 );
0 commit comments