已提权进程无凭据时,如何启动非管理员权限的原程序?
问题解答
核心结论
可以在无登录凭据的提权进程中启动非管理员权限的程序,核心是通过创建并使用受限用户令牌,移除管理员权限组的权限,从而回到原用户的非管理员上下文。
实现步骤
1. 获取当前提权进程的主令牌
提权进程拥有当前用户的完整访问令牌,首先需要打开这个令牌以进行后续操作:
HANDLE hCurrentToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &hCurrentToken)) { // 处理错误,可调用GetLastError()获取错误码 return FALSE; }
2. 定位并标记管理员组SID为禁用
从令牌的组信息中找到管理员组的SID,将其设置为SE_GROUP_USE_FOR_DENY_ONLY,这样后续生成的受限令牌会自动排除管理员权限:
// 先获取令牌组信息的内存大小 DWORD dwBufferSize = 0; GetTokenInformation(hCurrentToken, TokenGroups, NULL, 0, &dwBufferSize); PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS)LocalAlloc(LPTR, dwBufferSize); if (!GetTokenInformation(hCurrentToken, TokenGroups, pTokenGroups, dwBufferSize, &dwBufferSize)) { // 清理资源并处理错误 LocalFree(pTokenGroups); CloseHandle(hCurrentToken); return FALSE; } // 初始化管理员组SID SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; PSID pAdminSid = NULL; if (!AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSid)) { LocalFree(pTokenGroups); CloseHandle(hCurrentToken); return FALSE; } // 遍历组信息,标记管理员组为禁用 for (DWORD i = 0; i < pTokenGroups->GroupCount; i++) { if (EqualSid(pTokenGroups->Groups[i].Sid, pAdminSid)) { pTokenGroups->Groups[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY; break; } } FreeSid(pAdminSid);
3. 创建受限令牌
用处理后的组信息生成受限令牌,这个令牌会移除原令牌中的管理员权限:
HANDLE hRestrictedToken = NULL; if (!CreateRestrictedToken(hCurrentToken, 0, 0, NULL, 0, NULL, pTokenGroups, &hRestrictedToken)) { LocalFree(pTokenGroups); CloseHandle(hCurrentToken); return FALSE; } // 清理临时资源 LocalFree(pTokenGroups); CloseHandle(hCurrentToken);
4. 使用受限令牌启动非管理员程序
通过CreateProcessWithTokenW调用受限令牌启动目标程序,确保程序运行在原用户的非管理员上下文:
STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; // 替换为你的原程序路径和启动参数 LPCWSTR szProgramPath = L"C:\\Path\\To\\Your\\OriginalProgram.exe"; LPCWSTR szCommandLine = L"C:\\Path\\To\\Your\\OriginalProgram.exe"; if (!CreateProcessWithTokenW(hRestrictedToken, LOGON_WITH_PROFILE, szProgramPath, (LPWSTR)szCommandLine, 0, NULL, NULL, &si, &pi)) { CloseHandle(hRestrictedToken); return FALSE; } // 清理句柄资源 CloseHandle(hRestrictedToken); CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
关键注意事项
- 无需登录凭据:所有操作基于当前提权进程的令牌调整,不需要输入用户名/密码
- 上下文一致性:生成的受限令牌属于原用户,仅移除管理员权限,程序会运行在原用户的桌面和环境变量中
- 路径权限:确保原程序的路径对非管理员用户有执行权限(比如ProgramFiles下的程序默认允许普通用户执行)
- 错误处理:所有Windows API调用都需要检查返回值,通过
GetLastError()排查具体问题
内容的提问来源于stack exchange,提问作者HeartWare
相关产品推荐
相关产品推荐

