调用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 thePROCESS_BASIC_INFORMATIONstruct. This tiny buffer leads to incomplete or empty data being returned. - Misused
PROCESSINFOCLASS: You initializedinfoto an empty struct (which technically matchesProcessBasicInformation, the correct enum value), but explicitly using the enum name makes the code clearer and avoids accidental errors. - Invalid
ret_lengthpointer: Castingret_lengthtoPULONGinstead of passing its address&ret_lengthcauses the function to write to invalid memory, leading to data corruption or crashes. - Missing
OpenProcesserror checks: You don't handle cases whereOpenProcessreturnsNULL(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->SessionIdrequires a correctly definedPEBstruct (layout varies by Windows version), which you likely didn't have properly set up. - Memory leak: You
newaPROCESS_BASIC_INFORMATIONbut neverdeleteit, 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
- 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. - Explicit info class: Using
ProcessBasicInformationmakes the code intent clear and avoids enum value mistakes. - Valid return length pointer: Passing
&retLengthlets the function write the actual bytes returned, which aids debugging. - Handle management: We skip inaccessible processes and close handles properly to avoid leaks.
- Full enumeration: Instead of returning early, we collect all valid results in a vector and return them at the end.
- Proper struct definitions: The
PROCESS_BASIC_INFORMATIONandPEBstructs match Windows' layout, so we can safely accessSessionId. - 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
相关产品推荐
相关产品推荐

