LookupPrivilegeName对不同LUID返回相同权限名称的问题排查
问题分析与修复
核心问题原因
你的代码中权限名称显示错误的直接原因是循环调用LookupPrivilegeName时未重置dwNameLen变量。
LookupPrivilegeName函数会将dwNameLen参数修改为实际写入缓冲区的字符数(以TCHAR为单位,不包含终止符)。当后续查询的权限名称长度小于之前的名称时,缓冲区中未被覆盖的旧字符会残留下来,导致显示错误的权限名称(比如你遇到的SeShutdownPrivilege残留覆盖了SeChangeNotifyPrivilege的情况)。
此外代码还存在其他潜在问题:
- 未检查所有API调用的返回值,无法排查调用失败的情况
- LUID输出格式错误,直接拼接HighPart和LowPart会导致数值混乱
- 未释放堆内存、未关闭打开的句柄,存在资源泄漏
修复后的代码
#include <windows.h> #include <iostream> #include <tchar.h> VOID CheckWindowsPrivileges(DWORD PID) { HANDLE hProcess = NULL; HANDLE hToken = NULL; PTOKEN_PRIVILEGES pPrivileges = NULL; // 打开进程,获取查询信息权限 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID); if (hProcess == NULL) { wcout << L"OpenProcess 失败,错误码: " << GetLastError() << L"\n"; goto Cleanup; } // 打开进程令牌,获取查询权限 if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &hToken)) { wcout << L"OpenProcessToken 失败,错误码: " << GetLastError() << L"\n"; goto Cleanup; } // 获取TOKEN_PRIVILEGES结构所需的大小 DWORD bufSize = 0; GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &bufSize); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { wcout << L"GetTokenInformation 获取大小失败,错误码: " << GetLastError() << L"\n"; goto Cleanup; } // 分配堆内存 pPrivileges = (PTOKEN_PRIVILEGES)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize); if (pPrivileges == NULL) { wcout << L"HeapAlloc 失败,错误码: " << GetLastError() << L"\n"; goto Cleanup; } // 获取令牌权限信息 if (!GetTokenInformation(hToken, TokenPrivileges, pPrivileges, bufSize, &bufSize)) { wcout << L"GetTokenInformation 获取权限失败,错误码: " << GetLastError() << L"\n"; goto Cleanup; } // 遍历并输出所有权限 TCHAR name_buffer[64]; for (DWORD i = 0; i < pPrivileges->PrivilegeCount; i++) { // 每次调用前重置dwNameLen为缓冲区总大小(以TCHAR为单位) DWORD dwNameLen = _countof(name_buffer); if (LookupPrivilegeName(NULL, &pPrivileges->Privileges[i].Luid, name_buffer, &dwNameLen)) { // 输出权限名称与属性 wcout << name_buffer << L" " << pPrivileges->Privileges[i].Attributes << L"\n"; // 正确输出LUID格式 wcout << L"LUID: " << pPrivileges->Privileges[i].Luid.HighPart << L"-" << pPrivileges->Privileges[i].Luid.LowPart << L"\n"; } else { wcout << L"LookupPrivilegeName 失败,错误码: " << GetLastError() << L"\n"; } } Cleanup: // 释放资源 if (pPrivileges != NULL) HeapFree(GetProcessHeap(), 0, pPrivileges); if (hToken != NULL) CloseHandle(hToken); if (hProcess != NULL) CloseHandle(hProcess); }
关键修复点
- 重置dwNameLen:在每次循环调用
LookupPrivilegeName前,将dwNameLen重置为缓冲区的总大小(使用_countof(name_buffer)确保正确的TCHAR单位长度),这样函数会重新覆盖整个缓冲区,避免旧数据残留。 - 添加错误处理:对所有API调用添加返回值检查,便于调试定位问题。
- 修复LUID输出:采用
HighPart-LowPart的格式输出,避免数值拼接混乱。 - 资源清理:添加
goto Cleanup统一释放堆内存和关闭句柄,防止资源泄漏。
内容的提问来源于stack exchange,提问作者DarkH4mster
相关产品推荐
相关产品推荐

