调用SetTokenInformation修改令牌完整性级别遇0x5拒绝访问问题
调整复制主令牌完整性级别时ERROR_ACCESS_DENIED(0x5)的解决方法
问题背景
尝试对当前进程的复制主令牌调用SetTokenInformation调整强制完整性级别时,始终返回ERROR_ACCESS_DENIED(0x5)。已执行以下操作仍未解决:
- 启用所有权限排除权限问题
- 以
PROCESS_ALL_ACCESS打开当前进程,TOKEN_ALL_ACCESS打开进程令牌 - 获取当前进程的复制主令牌
- 验证函数调用及参数有效性、更换各类进程/令牌访问标识
怀疑SID构造存在问题,但未找到明确规则。
错误原因分析
- 令牌访问权限不足:
DuplicateTokenEx调用时使用MAXIMUM_ALLOWED无法确保获得修改令牌完整性级别的必要权限,需要明确指定TOKEN_ADJUST_DEFAULT权限。 - 完整性标签属性缺失:
TOKEN_MANDATORY_LABEL的Label.Attributes仅设置SE_GROUP_INTEGRITY,缺少SE_GROUP_MANDATORY属性,导致系统拒绝修改。 - 冗余权限干扰:启用大量不必要的权限(如
SeTcbPrivilege)不仅无效,还可能引入额外的权限检查问题。
修复方案
- 明确复制令牌的权限:在
DuplicateTokenEx中指定TOKEN_ADJUST_DEFAULT | TOKEN_QUERY权限,确保拥有修改令牌信息的权限。 - 修正完整性标签属性:将
Label.Attributes设置为SE_GROUP_INTEGRITY | SE_GROUP_MANDATORY。 - 正确构造目标完整性SID:根据需要的完整性级别选择对应的RID(如低完整性用
SECURITY_MANDATORY_LOW_RID)。 - 清理冗余权限:仅启用必要的权限(如
SeDebugPrivilege用于打开进程令牌)。
修正后的代码
MinimalMain.cpp
// TokenMinimalExample.cpp : This file contains the 'main' function. Program execution begins and ends there. #include <windows.h> #include <stdio.h> #include "token_example.h" int main() { // 仅启用必要权限 if (!SetThreadProcessPrivilege(L"SeDebugPrivilege", true)) { printf("Failed to enable SeDebugPrivilege: %d\n", GetLastError()); return 1; } // 获取当前进程的复制主令牌 HANDLE hToken = GetCurrentProcessPrimaryToken(); if (hToken == INVALID_HANDLE_VALUE) { printf("Failed to get a duplicate token for the current process: %d\n", GetLastError()); return 1; } // 创建低完整性SID SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_MANDATORY_LABEL_AUTHORITY; PSID pSid = NULL; if(!AllocateAndInitializeSid(&SIDAuth, 1, SECURITY_MANDATORY_LOW_RID, 0, 0, 0, 0, 0, 0, 0, &pSid)) { printf("Failed to create a mandatory low integrity SID: %d\n", GetLastError()); CloseHandle(hToken); system("PAUSE"); return 1; } // 设置令牌完整性级别 TOKEN_MANDATORY_LABEL tml; tml.Label.Attributes = SE_GROUP_INTEGRITY | SE_GROUP_MANDATORY; // 修正属性 tml.Label.Sid = pSid; if (!SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof(tml))) { printf("Failed to set token information: %d\n", GetLastError()); FreeSid(pSid); CloseHandle(hToken); system("PAUSE"); return 1; } printf("Token integrity level set successfully!\n"); FreeSid(pSid); CloseHandle(hToken); system("PAUSE"); return 0; }
token_example.h
#pragma once #include <Windows.h> #include <stdio.h> // 调整进程/线程权限的辅助函数 bool SetThreadProcessPrivilege(LPCWSTR PrivilegeName, bool Enable) { HANDLE Token = NULL; TOKEN_PRIVILEGES TokenPrivs = {0}; LUID TempLuid; if (!LookupPrivilegeValueW(NULL, PrivilegeName, &TempLuid)) { printf("LookupPrivilegeValueW failed: %d\n", GetLastError()); return false; } // 优先打开线程令牌,失败则打开进程令牌 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &Token)) { if (GetLastError() != ERROR_NO_TOKEN) { printf("OpenThreadToken failed: %d\n", GetLastError()); return false; } if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token)) { printf("OpenProcessToken failed: %d\n", GetLastError()); return false; } } TokenPrivs.PrivilegeCount = 1; TokenPrivs.Privileges[0].Luid = TempLuid; TokenPrivs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0; BOOL result = AdjustTokenPrivileges(Token, FALSE, &TokenPrivs, sizeof(TOKEN_PRIVILEGES), NULL, NULL); DWORD lastErr = GetLastError(); if (!result || lastErr != ERROR_SUCCESS) { printf("AdjustTokenPrivileges failed: %d\n", lastErr); CloseHandle(Token); return false; } CloseHandle(Token); return true; } // 获取当前进程的复制主令牌 HANDLE GetCurrentProcessPrimaryToken() { HANDLE hProcess = NULL; HANDLE hOriginalToken = NULL; HANDLE hDuplicateToken = NULL; // 打开当前进程 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); if (!hProcess) { printf("OpenProcess failed: %d\n", GetLastError()); goto Cleanup; } // 打开进程令牌(需要TOKEN_DUPLICATE权限) if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hOriginalToken)) { printf("OpenProcessToken failed: %d\n", GetLastError()); goto Cleanup; } // 复制主令牌,明确指定修改所需权限 SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE }; if (!DuplicateTokenEx( hOriginalToken, TOKEN_ADJUST_DEFAULT | TOKEN_QUERY, // 明确必要权限 &sa, SecurityImpersonation, TokenPrimary, &hDuplicateToken)) { printf("DuplicateTokenEx failed: %d\n", GetLastError()); goto Cleanup; } Cleanup: if (hProcess) CloseHandle(hProcess); if (hOriginalToken) CloseHandle(hOriginalToken); return hDuplicateToken ? hDuplicateToken : INVALID_HANDLE_VALUE; }
额外说明
- 完整性级别RID对应关系:
- 低完整性:
SECURITY_MANDATORY_LOW_RID(0x00001000) - 中完整性:
SECURITY_MANDATORY_MEDIUM_RID(0x00002000) - 高完整性:
SECURITY_MANDATORY_HIGH_RID(0x00003000) - 系统完整性:
SECURITY_MANDATORY_SYSTEM_RID(0x00004000)
- 低完整性:
- 修改令牌完整性级别后,该令牌仅可用于创建新进程,无法修改当前进程的完整性级别(当前进程的完整性级别不可动态调整)。
内容的提问来源于stack exchange,提问作者Pulpo
相关产品推荐
相关产品推荐

