模拟用户时LogonUserW创建的二次令牌访问资源被拒绝的原因咨询
嵌套模拟用户时资源访问被拒绝问题分析
问题描述
我开发了一个程序,通过LogonUserW创建用户令牌并模拟该用户调用RegOpenKeyW。首次执行时RegOpenKeyW调用成功,但先模拟第一个令牌,再创建第二个令牌并模拟它时,RegOpenKeyW调用失败,错误码为0x5(访问被拒绝)。
示例代码
#include <Windows.h> #include <iostream> void Test() { HKEY key; auto status{ RegOpenKeyW(HKEY_CLASSES_ROOT, L"*", &key) }; std::wcout << L"RegOpenKeyW: "; if (status == ERROR_SUCCESS) { std::wcout << L"Succeeded"; RegCloseKey(key); } else { std::wcout << L"Failed (0x" << std::hex << status << L")"; } std::wcout << std::endl; } int main() { // Logon a user, impersonate them, then run a test HANDLE token1; if (LogonUserW(USER, L".", PASSWORD, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &token1)) { if (ImpersonateLoggedOnUser(token1)) { Test(); // While still impersonating the user, run the same actions HANDLE token2; if (LogonUserW(USER, L".", PASSWORD, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &token2)) { if (ImpersonateLoggedOnUser(token2)) { Test(); } CloseHandle(token2); } } CloseHandle(token1); } }
程序输出
RegOpenKeyW: Succeeded RegOpenKeyW: Failed (0x5)
尝试过使用相同或不同账号调用LogonUserW,更换登录类型或登录提供者,均出现此问题;若在第二次调用LogonUserW前调用RevertToSelf,则两次RegOpenKeyW调用均成功。此外,修改Test函数访问LsaOpenPolicy等其他资源时,也存在首次成功、二次失败的现象。
原因分析
这种现象的核心是Windows安全模型对嵌套模拟场景的权限限制:
- 嵌套模拟的权限交集规则:当在已模拟用户(token1)的上下文里创建并模拟新令牌(token2)时,系统会将两次模拟的权限集取交集作为最终有效权限。即使token2本身拥有访问资源的权限,只要token1的权限不足以访问该资源,最终就会触发访问被拒绝。
- 令牌的身份上下文继承:在模拟状态下调用
LogonUserW创建的新令牌,会继承当前模拟用户的身份验证上下文,而非进程原始身份的上下文。这会导致新令牌在访问系统资源时,无法通过完整的权限校验,因为系统会将其视为“低权限上下文中生成的令牌”进行权限过滤。 - RevertToSelf的作用:调用该函数会恢复进程的原始身份上下文,此时创建的新令牌基于原始身份生成,拥有完整的权限集,模拟后访问资源自然不会被拒绝。
解决方案
- 必须在创建新令牌前调用
RevertToSelf,恢复到进程原始身份,再执行LogonUserW和ImpersonateLoggedOnUser操作。 - 避免在模拟上下文内嵌套创建并模拟新令牌,这是Windows安全模型明确限制的场景,无法通过修改登录类型或提供者绕过。
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

