You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用NtQueryInformationProcess后PROCESS_BASIC_INFORMATION结果为空,无法获取进程SessionID求助

Fixing Your NtQueryInformationProcess & SessionID Retrieval Issues

Let's break down the problems in your code that are causing empty PROCESS_BASIC_INFORMATION and failed SessionID reads, then fix them step by step:

Key Issues in Your Code

  • Incorrect buffer size: sizeof(pBasicInfo) returns the size of a pointer (4/8 bytes), not the full size of the PROCESS_BASIC_INFORMATION struct. This tiny buffer leads to incomplete or empty data being returned.
  • Misused PROCESSINFOCLASS: You initialized info to an empty struct (which technically matches ProcessBasicInformation, the correct enum value), but explicitly using the enum name makes the code clearer and avoids accidental errors.
  • Invalid ret_length pointer: Casting ret_length to PULONG instead of passing its address &ret_length causes the function to write to invalid memory, leading to data corruption or crashes.
  • Missing OpenProcess error checks: You don't handle cases where OpenProcess returns NULL (common for protected system processes), leading to invalid handle usage.
  • Early return in loop: You return immediately after the first valid PID, so you'll never enumerate more than one process.
  • PEB struct access issues: Directly reading PebBaseAddress->SessionId requires a correctly defined PEB struct (layout varies by Windows version), which you likely didn't have properly set up.
  • Memory leak: You new a PROCESS_BASIC_INFORMATION but never delete it, leading to memory leaks over time.

Corrected Code Example

First, ensure you have the correct struct definitions (aligned with modern Windows layouts):

#include <windows.h>
#include <psapi.h>
#include <iostream>
#include <vector>

// Link against psapi.lib (add this if your compiler needs it)
#pragma comment(lib, "psapi.lib")

// Correct PROCESS_BASIC_INFORMATION definition
typedef struct _PROCESS_BASIC_INFORMATION {
    PVOID Reserved1;
    PVOID PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;

// Simplified PEB definition for SessionId access (valid for Windows 7+)
typedef struct _PEB {
    UCHAR Reserved1[2];
    UCHAR BeingDebugged;
    UCHAR Reserved2[1];
    PVOID Reserved3[2];
    PVOID Ldr;
    PVOID ProcessParameters;
    UCHAR Reserved4[36];
    ULONG SessionId;
} PEB, *PPEB;

// Your enum results struct (extended to include SessionId)
struct enum_results {
    int pid;
    HANDLE process;
    ULONG sessionId;
};

std::vector<enum_results> enum_proc() {
    typedef NTSTATUS(WINAPI* PNtQueryInformationProcess)(
        IN HANDLE ProcessHandle,
        IN PROCESSINFOCLASS ProcessInformationClass,
        OUT PVOID ProcessInformation,
        IN ULONG ProcessInformationLength,
        OUT PULONG ReturnLength OPTIONAL
    );

    // Load ntdll and get the function pointer
    HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
    if (!hNtdll) {
        std::cout << "Failed to load ntdll.dll\n";
        return {};
    }

    PNtQueryInformationProcess pNtQueryInformationProcess = 
        reinterpret_cast<PNtQueryInformationProcess>(GetProcAddress(hNtdll, "NtQueryInformationProcess"));
    
    if (!pNtQueryInformationProcess) {
        std::cout << "Failed to get NtQueryInformationProcess address\n";
        return {};
    }

    DWORD procs[1024];
    DWORD cbNeeded;
    if (!EnumProcesses(procs, sizeof(procs), &cbNeeded)) {
        std::cout << "Couldn't retrieve process list\n";
        return {};
    }

    int cProcesses = cbNeeded / sizeof(DWORD);
    std::vector<enum_results> results;

    for (int i = 0; i < cProcesses; ++i) {
        DWORD pid = procs[i];
        if (pid == 0) continue;

        // Open process with minimal required permissions
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
        if (!hProcess) {
            // Skip processes we don't have access to
            continue;
        }

        PROCESS_BASIC_INFORMATION pBasicInfo{};
        ULONG retLength = 0;
        NTSTATUS status = pNtQueryInformationProcess(
            hProcess,
            ProcessBasicInformation, // Explicitly use the correct info class
            &pBasicInfo, // Use stack-allocated struct to avoid leaks
            sizeof(PROCESS_BASIC_INFORMATION), // Correct struct size
            &retLength // Pass address of retLength
        );

        if (NT_SUCCESS(status)) {
            // Cast PEB base address to valid pointer
            PPEB pPeb = reinterpret_cast<PPEB>(pBasicInfo.PebBaseAddress);
            ULONG sessionId = pPeb->SessionId;

            enum_results res;
            res.pid = pid;
            res.process = hProcess; // Remember to close this handle later!
            res.sessionId = sessionId;
            results.push_back(res);

            std::cout << "PID: " << pid << ", Session ID: " << sessionId << "\n";
        } else {
            std::cout << "NtQueryInformationProcess failed for PID " << pid << ", status: 0x" << std::hex << status << "\n";
            CloseHandle(hProcess); // Close handle if query fails
        }
    }

    return results;
}

// Example usage
int main() {
    auto results = enum_proc();
    // Clean up process handles when done
    for (auto& res : results) {
        CloseHandle(res.process);
    }
    return 0;
}

Key Fixes Explained

  1. Correct buffer size: We use sizeof(PROCESS_BASIC_INFORMATION) to pass the full size of the struct to the function, ensuring all data is returned.
  2. Explicit info class: Using ProcessBasicInformation makes the code intent clear and avoids enum value mistakes.
  3. Valid return length pointer: Passing &retLength lets the function write the actual bytes returned, which aids debugging.
  4. Handle management: We skip inaccessible processes and close handles properly to avoid leaks.
  5. Full enumeration: Instead of returning early, we collect all valid results in a vector and return them at the end.
  6. Proper struct definitions: The PROCESS_BASIC_INFORMATION and PEB structs match Windows' layout, so we can safely access SessionId.
  7. No memory leaks: Using a stack-allocated struct eliminates the need for new/delete.

Important reminder: Always call CloseHandle on the process handles returned in enum_results to avoid handle leaks.

内容的提问来源于stack exchange,提问作者L10N L10N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:57:40