编写一个函数以查询进程的线程状态。
bool IterateOverThreads() {
NTSTATUS status;
PSYSTEM_PROCESS_INFORMATION spi;
ULONG lBufferSize = 0;
status = ::NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS::SystemProcessInformation, 0, 0, & lBufferSize);
if (0xC0000004L != status || 0 == lBufferSize)
return false;
unique_ptr<byte[]> pMemory(new byte[lBufferSize]);
spi = (PSYSTEM_PROCESS_INFORMATION)pMemory.get();
// get System Information
if (!NT_SUCCESS(status = ::NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS::SystemProcessInformation, spi, lBufferSize, & lBufferSize)))
return false;
// Loop over the list until we reach the last entry
while (spi->NextEntryDelta) {
// Calculate the address of the next entry.
spi = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)spi + spi->NextEntryDelta);
// iterate over threads
for (size_t ii = 0; ii < spi->ThreadCount; ++ii) {
// do whatever with thread attributes
spi->Threads[ii].State;
spi->Threads[ii].WaitReason;
}
}
return true;
}
我的解决方案/项目必须使用Microsoft SDK版本7.1。
SYSTEM_PROCESS_INFORMATION
结构在以下两个SDK版本之间进行了更改:
Microsoft SDKs\Windows\v7.1A\Include\winternl.h
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
BYTE Reserved1[52];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
BYTE Reserved1[48];
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
PVOID Reserved2;
ULONG HandleCount;
ULONG SessionId;
PVOID Reserved3;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG Reserved4;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
PVOID Reserved5;
SIZE_T QuotaPagedPoolUsage;
PVOID Reserved6;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;
因此,我无法使用NumberOfThreads
(或其他)等成员来“享受”。
SYSTEM_PROCESS_INFORMATION
我自己
我的应用程序在大于XP的所有Windows上运行。
我的代码安全吗?意思是,访问spi->ThreadCount
是否安全?我可以假设那里的字节有效吗?在较旧的Windows版本上从我自己定义的结构中读取字节是否会有风险?
答案 0 :(得分:1)
目前是SYSTEM_PROCESS_INFORMATION
的最佳(我认为)定义之一
现在对所有当前Windows版本(包括XP)有效。
访问spi-> ThreadCount安全吗?
是的,安全。当前所有版本的最小数量。 (例如,xp不会更改)。在将来的构建中安全吗(结构未更改)已经是另一个问题了。
我的代码安全吗?
不,错了。最低2分。首先,在您第一次调用lBufferSize
后获得NtQuerySystemInformation
之后,再在第二次调用中使用它之前-所需大小可以更改(增长)-因此,实际上确实需要对NtQuerySystemInformation
进行单个调用直到您获得STATUS_INFO_LENGTH_MISMATCH
。您的代码可以工作,但有时会失败。
// Loop over the list until we reach the last entry while (spi->NextEntryDelta) {
这始终是错误-您丢失了最后一个包含NextEntryDelta == 0
的条目
返回布尔不是实现函数的最佳方法,最好返回NTSTATUS
。
最小正确的代码看起来像
NTSTATUS IterateOverThreads()
{
NTSTATUS status;
PVOID buf;
ULONG cb = 0x1000;
do
{
if (buf = LocalAlloc(0, cb))
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION spi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
DbgPrint("%wZ\n", &spi->ImageName);
if (ULONG NumberOfThreads = spi->NumberOfThreads)
{
PSYSTEM_THREAD_INFORMATION TH = spi->TH;
do
{
DbgPrint("\t%p %x %x\n", TH->ClientId.UniqueThread, TH->ThreadState, TH->WaitReason);
} while (TH++, --NumberOfThreads);
}
} while (NextEntryOffset = spi->NextEntryOffset);
}
LocalFree(buf);
}
else
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}