非管理员权限下GetTokenInformation返回ERROR_NOACCESS问题排查
问题分析与修复
核心错误点
未分配内存给
TOKEN_USER结构体
你声明了PTOKEN_USER user = NULL;但从未为其分配内存,第二次调用GetTokenInformation时传入NULL指针,导致写入操作触发内存访问错误(ERROR_NOACCESS)。第一次调用GetTokenInformation仅用于获取所需缓冲区大小,必须根据返回的returnLength分配内存后再执行第二次调用。进程句柄有效性判断逻辑错误
代码中if (OGHandle != NULL || OGHandle != INVALID_HANDLE_VALUE)的逻辑永远为真(一个句柄不可能同时等于NULL和INVALID_HANDLE_VALUE),应改为&&:if (OGHandle != NULL && OGHandle != INVALID_HANDLE_VALUE),否则会对无效句柄执行后续操作。进程打开权限不匹配
使用PROCESS_QUERY_LIMITED_INFORMATION打开进程时,该权限仅能获取受限进程信息,无法满足打开进程令牌的需求。应使用PROCESS_QUERY_INFORMATION权限(非管理员对同权限进程可正常获取)。
修复后的代码
#include <windows.h> #include <tlhelp32.h> #include <stdio.h> #include <malloc.h> int main() { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { printf("Could not open handle via CreateToolhelp32Snapshot()\n"); return 1; } PROCESSENTRY32 pe = { sizeof(pe) }; if (!Process32First(hSnapshot, &pe)) { printf("Process32First failed\n"); CloseHandle(hSnapshot); return 1; } do { // 使用PROCESS_QUERY_INFORMATION确保能打开进程令牌 HANDLE OGHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe.th32ProcessID); HANDLE tokenHandle = NULL; DWORD returnLength = 0; PTOKEN_USER user = NULL; if (OGHandle != NULL && OGHandle != INVALID_HANDLE_VALUE) { // 打开令牌只需TOKEN_QUERY权限 if (OpenProcessToken(OGHandle, TOKEN_QUERY, &tokenHandle)) { // 第一次调用获取缓冲区大小 if (!GetTokenInformation(tokenHandle, TokenUser, NULL, 0, &returnLength)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // 分配对应大小的内存 user = (PTOKEN_USER)LocalAlloc(LPTR, returnLength); if (user != NULL) { // 第二次调用获取令牌信息 if (GetTokenInformation(tokenHandle, TokenUser, user, returnLength, &returnLength)) { // 可选:将SID转换为字符串打印 WCHAR sidStr[256]; if (ConvertSidToStringSidW(user->User.Sid, &sidStr)) { printf("Process ID: %d, SID: %ws\n", pe.th32ProcessID, sidStr); LocalFree(sidStr); } } else { printf("GetTokenInfo() failed with error code %d\n", GetLastError()); } LocalFree(user); } else { printf("Failed to allocate memory for TOKEN_USER\n"); } } else { printf("First GetTokenInfo() failed with error code %d\n", GetLastError()); } } } else { printf("OpenProcessToken failed with error code %d\n", GetLastError()); } } printf("Process ID: %d , PPID: %d , Path: %ws \n", pe.th32ProcessID, pe.th32ParentProcessID, pe.szExeFile ); if (OGHandle != NULL) CloseHandle(OGHandle); if (tokenHandle != NULL) CloseHandle(tokenHandle); } while (Process32Next(hSnapshot, &pe)); CloseHandle(hSnapshot); return 0; }
额外说明
- 内存分配使用
LocalAlloc+LocalFree是Windows API标准做法,也可使用malloc但需确保内存对齐。 - 非管理员权限下,仅能获取与当前进程权限层级相同或更低的进程SID,系统核心进程(如system、csrss等)无法访问,属于正常权限限制。
OpenProcessToken只需TOKEN_QUERY权限,无需额外添加TOKEN_QUERY_SOURCE,除非需要查询令牌来源信息。
内容的提问来源于stack exchange,提问作者user2494337
相关产品推荐
相关产品推荐

