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

如何获取访问令牌中的已禁用权限列表?

获取进程访问令牌中已禁用权限列表的方案

你当前使用的PrivilegeCheck()仅能验证指定权限是否已启用,要获取令牌中所有已存在但未启用的可激活禁用权限,需通过Windows API的GetTokenInformation()函数,指定TokenPrivileges参数读取令牌的完整权限列表。

核心思路

  • 打开目标进程的访问令牌(需TOKEN_QUERY权限)
  • 调用GetTokenInformation()两次:第一次获取存储权限列表的缓冲区大小,第二次读取实际权限数据
  • 遍历返回的TOKEN_PRIVILEGES结构体条目,通过权限属性判断是否为禁用状态
  • 用LookupPrivilegeName()将权限的LUID转换为可读名称,筛选出禁用权限

代码实现示例

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

BOOL GetDisabledPrivileges(HANDLE hToken, LPTSTR* ppPrivilegeNames, DWORD* pCount)
{
    DWORD dwSize = 0;
    TOKEN_PRIVILEGES* pPrivileges = NULL;
    BOOL bResult = FALSE;

    // 第一次调用获取缓冲区大小
    if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        pPrivileges = (TOKEN_PRIVILEGES*)LocalAlloc(LPTR, dwSize);
        if (pPrivileges == NULL)
            goto Cleanup;

        // 第二次调用读取完整权限列表
        if (GetTokenInformation(hToken, TokenPrivileges, pPrivileges, dwSize, &dwSize))
        {
            *pCount = pPrivileges->PrivilegeCount;
            *ppPrivilegeNames = (LPTSTR)LocalAlloc(LPTR, *pCount * MAX_PATH * sizeof(TCHAR));
            if (*ppPrivilegeNames == NULL)
                goto Cleanup;

            LPTSTR pCurrentName = *ppPrivilegeNames;
            for (DWORD i = 0; i < pPrivileges->PrivilegeCount; i++)
            {
                DWORD cchName = MAX_PATH;
                // 将LUID转换为权限名称
                if (LookupPrivilegeName(NULL, &pPrivileges->Privilege[i].Luid, pCurrentName, &cchName))
                {
                    // 筛选未启用的权限(属性不含SE_PRIVILEGE_ENABLED)
                    if (!(pPrivileges->Privilege[i].Attributes & SE_PRIVILEGE_ENABLED))
                    {
                        pCurrentName += cchName;
                    }
                    else
                    {
                        // 跳过已启用权限,调整计数
                        (*pCount)--;
                    }
                }
            }
            bResult = TRUE;
        }
    }

Cleanup:
    if (pPrivileges != NULL)
        LocalFree(pPrivileges);
    return bResult;
}

int _tmain(int argc, TCHAR* argv[])
{
    if (argc != 2)
    {
        _tprintf(_T("Usage: %s <PID>\n"), argv[0]);
        return 1;
    }

    DWORD PID = _ttoi(argv[1]);
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID);
    if (hProcess == NULL)
    {
        _tprintf(_T("OpenProcess failed, error: %d\n"), GetLastError());
        return 1;
    }

    HANDLE hToken = NULL;
    if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
    {
        _tprintf(_T("OpenProcessToken failed, error: %d\n"), GetLastError());
        CloseHandle(hProcess);
        return 1;
    }

    LPTSTR pPrivNames = NULL;
    DWORD dwCount = 0;
    if (GetDisabledPrivileges(hToken, &pPrivNames, &dwCount))
    {
        _tprintf(_T("Disabled privileges for PID %d:\n"), PID);
        LPTSTR pCurrent = pPrivNames;
        for (DWORD i = 0; i < dwCount; i++)
        {
            _tprintf(_T("- %s\n"), pCurrent);
            pCurrent += _tcslen(pCurrent) + 1;
        }
    }
    else
    {
        _tprintf(_T("GetDisabledPrivileges failed, error: %d\n"), GetLastError());
    }

    // 清理资源
    if (pPrivNames != NULL)
        LocalFree(pPrivNames);
    CloseHandle(hToken);
    CloseHandle(hProcess);
    return 0;
}

关键说明

  • TOKEN_PRIVILEGES结构体包含令牌中所有权限的LUID_AND_ATTRIBUTES数组,Attributes字段标记状态:
    • SE_PRIVILEGE_ENABLED:权限已启用
    • 无此标记:权限存在但处于禁用状态(即你需要的可激活权限)
  • 必须先调用GetTokenInformation()获取缓冲区大小,不同进程令牌的权限数量不固定
  • 代码使用LocalAlloc分配内存,完成后需用LocalFree释放,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 04:37:33