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

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

关键修复点

  1. 重置dwNameLen:在每次循环调用LookupPrivilegeName前,将dwNameLen重置为缓冲区的总大小(使用_countof(name_buffer)确保正确的TCHAR单位长度),这样函数会重新覆盖整个缓冲区,避免旧数据残留。
  2. 添加错误处理:对所有API调用添加返回值检查,便于调试定位问题。
  3. 修复LUID输出:采用HighPart-LowPart的格式输出,避免数值拼接混乱。
  4. 资源清理:添加goto Cleanup统一释放堆内存和关闭句柄,防止资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:33:14