代码之家  ›  专栏  ›  技术社区  ›  idanshmu

_系统进程信息结构向后兼容性

  •  -1
  • idanshmu  · 技术社区  · 6 年前

    目标

    编写函数查询进程的线程状态。

    解决方案

    使用这个有用的帖子: Unique Technique for Iterating Through Processes 并形成初始函数:

    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;
    }
    

    问题1

    我的解决方案/项目必须使用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;
    

    记录在 NtQuerySystemInformation

    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 (或其他)。

    修复问题1:

    定义 系统处理信息 我自己的代码,基于 documentation

    问题2

    我的应用程序在所有大于xp的窗口上运行。

    问题

    我的密码安全吗?意思是,正在访问 spi->ThreadCount 安全吗?我可以假设那里的字节是有效的吗?在旧的Windows版本上从我自己定义的结构中读取字节会有风险吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   RbMm    6 年前

    目前我认为是对 SYSTEM_PROCESS_INFORMATION

    现在它对所有当前的Windows版本(包括XP)都有效。

    访问SPI->线程计数安全吗?

    是的,安全。所有当前版本的最小值。(假设xp已经不会改变)。这在将来的构建中是否安全(结构是否未更改)已经是另一个问题了。

    我的密码安全吗?

    不,它错了。最少2分。刚开始的时候 lBufferSize 第一次呼叫 NtQuerySystemInformation 在第二次调用中使用它之前-所需大小可以更改(增长)-因此需要真正执行单个调用 NtQuerySystemInformation(查询系统信息) 但在你得到 STATUS_INFO_LENGTH_MISMATCH . 您的代码可以工作,但有时会失败。

    // Loop over the list until we reach the last entry  
    while (spi->NextEntryDelta) {
    

    这始终是错误的-您丢失了最后一个条目, NextEntryDelta == 0

    返回bool不是函数的最佳想法,返回更好 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;
    }