SYSTEM服务启动用户会话高权限进程失败,设置SeDebugPrivilege报错ERROR_NOT_ALL_ASSIGNED
SYSTEM服务启动用户会话高权限进程失败,设置SeDebugPrivilege报错ERROR_NOT_ALL_ASSIGNED
哥们,你踩了个常见的坑——你现在是在用户的token上尝试设置SeDebugPrivilege,但普通用户的token本身根本没有这个权限,所以AdjustTokenPrivileges才会返回ERROR_NOT_ALL_ASSIGNED。
问题根源
SeDebugPrivilege是系统级权限,只有SYSTEM这类系统账号默认拥有,但你调用SetPrivilege时传的是WTSQueryUserToken拿到的用户会话token,这个token属于登录的普通用户,默认是没有SeDebugPrivilege的,自然设置失败。
正确的解决步骤
你需要先给服务自身的SYSTEM进程token启用SeDebugPrivilege,再去处理用户会话的token:
启用服务自身的SeDebugPrivilege
SYSTEM账号默认持有SeDebugPrivilege,只是这个权限默认处于未启用状态。你需要先打开当前服务进程的token,手动启用这个权限。处理用户的受限token
WTSQueryUserToken拿到的用户token通常是受限token(filtered token),如果要启动高权限进程,得先通过GetLinkedToken获取用户的完整提升token。调用CreateProcessAsUser创建进程
用处理好的用户完整token,配合正确参数调用CreateProcessAsUser,记得及时清理环境块和各种句柄。
修正后的代码示例
// 封装一个启用当前进程SeDebugPrivilege的函数 bool EnableDebugPrivilege() { HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { debugFile << "OpenProcessToken failed: " << GetLastError() << std::endl; return false; } LUID luid; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { debugFile << "LookupPrivilegeValue failed: " << GetLastError() << std::endl; CloseHandle(hToken); return false; } TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { debugFile << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl; CloseHandle(hToken); return false; } CloseHandle(hToken); return true; } bool runPrivilegedProcess(ULONG sessionId) { // 第一步:先给当前SYSTEM服务进程启用SeDebugPrivilege if (!EnableDebugPrivilege()) { debugFile << "Failed to enable SeDebugPrivilege on SYSTEM token" << std::endl; return false; } HANDLE userToken; if (WTSQueryUserToken(sessionId, &userToken) == FALSE) { debugFile << "WTSQueryUserToken failed: " << GetLastError() << std::endl; return false; } // 检查用户token是否是受限的,如果是,获取完整的提升token HANDLE fullUserToken = NULL; TOKEN_ELEVATION_TYPE elevationType; DWORD dwSize = sizeof(elevationType); if (GetTokenInformation(userToken, TokenElevationType, &elevationType, dwSize, &dwSize)) { if (elevationType == TokenElevationTypeLimited) { if (!GetLinkedToken(userToken, &fullUserToken)) { debugFile << "GetLinkedToken failed: " << GetLastError() << std::endl; CloseHandle(userToken); return false; } // 替换为完整token,关闭原受限token CloseHandle(userToken); userToken = fullUserToken; } } // 创建用户环境块 LPVOID envBlock = NULL; if (!CreateEnvironmentBlock(&envBlock, userToken, FALSE)) { debugFile << "CreateEnvironmentBlock failed: " << GetLastError() << std::endl; CloseHandle(userToken); return false; } STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(STARTUPINFO); // 指定用户会话的桌面,否则进程可能在后台运行无法显示 si.lpDesktop = L"WinSta0\\Default"; // 调用CreateProcessAsUser启动高权限进程 BOOL result = CreateProcessAsUser( userToken, L"C:\\Your\\Path\\To\\ElevatedApp.exe", // 替换为你的目标程序路径 NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, envBlock, NULL, &si, &pi ); if (!result) { debugFile << "CreateProcessAsUser failed: " << GetLastError() << std::endl; } else { // 关闭进程和线程句柄 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } // 清理资源 DestroyEnvironmentBlock(envBlock); CloseHandle(userToken); return result != FALSE; }
额外注意点
- 如果你要启动的是需要UAC提升的程序,确保用户账号本身具备管理员权限,或者已经获取到完整的管理员token
CreateProcessAsUser的桌面参数必须指定为WinSta0\\Default,否则进程可能无法在用户会话中正常显示- 所有打开的句柄都要记得关闭,避免资源泄漏
备注:内容来源于stack exchange,提问作者Mustafa Chelik
相关产品推荐
相关产品推荐

