如何获取访问令牌中的已禁用权限列表?
获取进程访问令牌中已禁用权限列表的方案
你当前使用的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
相关产品推荐
相关产品推荐

