для этого существует PROCESS_EXTENDED_BASIC_INFORMATION
- значение флагов, описанных в этом ответе . Вам нужен флаг IsFrozen
. поэтому вам нужен открытый процесс с доступом PROCESS_QUERY_LIMITED_INFORMATION
(для этого нужно включить все процессы SE_DEBUG_PRIVILEGE
в токене). и вызовите NtQuerySystemInformation
с ProcessBasicInformation
и PROCESS_EXTENDED_BASIC_INFORMATION
в качестве ввода. для перечисления всех процессов мы можем использовать NtQuerySystemInformation
с SystemProcessInformation
. конечно можно и использовать CreateToolhelp32Snapshot
+ Process32First
+ Process32Next
но этот API очень неэффективен, сравните прямой вызов с NtQuerySystemInformation
также возможно перечислить все потоки в процессе и проверить его состояние, а если состояние ждать - причина ожидания. это очень просто, потому что вся эта информация уже возвращена за один вызов NtQuerySystemInformation
с SystemProcessInformation
. При этом нам не нужны открытые процессы. обычно оба эти способа дают одинаковый результат (для приостановленных / замороженных) процессов, но, тем не менее, использование IsFrozen
является наиболее правильным решением.
void PrintSuspended()
{
BOOLEAN b;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
ULONG cb = 0x1000;
NTSTATUS status;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PBYTE buf = new BYTE[cb])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PBYTE pb;
SYSTEM_PROCESS_INFORMATION* spi;
};
pb = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
if (!spi->UniqueProcessId)
{
continue;
}
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
(ULONG)(ULONG_PTR)spi->UniqueProcessId))
{
PROCESS_EXTENDED_BASIC_INFORMATION pebi;
if (0 <= NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), 0) &&
pebi.Size >= sizeof(pebi))
{
if (pebi.IsFrozen)
{
DbgPrint("f:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
}
}
CloseHandle(hProcess);
}
if (ULONG NumberOfThreads = spi->NumberOfThreads)
{
SYSTEM_THREAD_INFORMATION* TH = spi->TH;
do
{
if (TH->ThreadState != StateWait || TH->WaitReason != Suspended)
{
break;
}
} while (TH++, --NumberOfThreads);
if (!NumberOfThreads)
{
DbgPrint("s:%x %wZ\n", spi->UniqueProcessId, spi->ImageName);
}
}
} while (NextEntryOffset = spi->NextEntryOffset);
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
}