从会话 ID 获取正确的令牌
Getting correct Token from session id
当进程以管理员身份在非管理员用户(windows 登录用户)下运行时,我想要实现的是来自会话 ID 的实际令牌句柄。
DWORD dwSessionId = 0;
if (false == ProcessIdToSessionId(dwProcessId, &dwSessionId))
{
LOG_ERROR(L"Failed obtaining session id");
return false;
}
HANDLE hToken
if (false == WTSQueryUserToken(dwSessionId, &hToken))
{
LOG_ERROR(L"Failed to obtain session's handle");
return false;
}
当我调用 WTSQueryUserToken 时出现问题,它失败并出现错误 1314,这意味着我需要授予调用令牌 SE_TCB_NAME 权限。
所以我尝试使用以下代码这样做:
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bool bSuccess = DynamicAPI::AdjustTokenPrivileges(
%%WHICH_TOKEN_EXACTLLY%%,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)nullptr,
(DWORD)nullptr);
但我不完全确定应该准确提供哪个令牌。我用 %%WHICH_TOKEN_EXACTLLY%% 占位符标记了它。对于我的测试,我尝试 AdjustTokenPriviliges 我的进程的令牌(管理员权限),但它也没有帮助。
如果需要调整权限的线程是模拟用户,使用OpenThreadToken(GetCurrentThread())
to get the impersonated token. Otherwise, use OpenProcessToken(GetCurrentProcess())
获取调用进程的token。
您通常需要在您的进程令牌中启用权限,您可以使用 GetProcessToken() 函数获得该权限。例外情况是,如果您打算在模拟时使用该特权,那么您应该改为在模拟令牌中启用该特权。
我使用此代码启用恢复权限:
DWORD enable_restore()
{
// This allows us to override security to delete files
HANDLE token;
BOOL flag;
struct {
DWORD count;
LUID_AND_ATTRIBUTES privilege;
} token_privileges;
token_privileges.count = 1;
token_privileges.privilege.Attributes = SE_PRIVILEGE_ENABLED;
flag = LookupPrivilegeValue(0, SE_RESTORE_NAME, &token_privileges.privilege.Luid);
if (!flag) return GetLastError();
flag = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
if (!flag) return GetLastError();
flag = AdjustTokenPrivileges(token, 0, (PTOKEN_PRIVILEGES)&token_privileges, 0, 0, 0);
if (!flag) return GetLastError();
return 0;
}
请注意,此代码不会检查权限是否实际被授予。为此,请在调用 AdjustTokenPrivileges() 后检查 GetLastError() - 这是少数情况之一,即使函数报告成功,最后的错误代码也有意义。
注意:这是您尝试使用进程令牌失败的最可能原因;如果您没有 运行 将代码设置为本地系统,并且没有重新配置 Windows 以授予您使用的帐户 SE_TCB_NAME 特权,则对 AdjustTokenPrivileges() 的调用将报告成功,但是没有效果。
此外,请记住,无论您是否拥有 SE_TCB_NAME 权限,如果您在本地系统上下文中 运行ning,则只能使用 WTSQueryUserToken(),即通常只有系统服务或系统服务上下文中的应用程序 运行 可以使用它。 (我不确定模拟本地系统是否足够。我怀疑不是。)
当进程以管理员身份在非管理员用户(windows 登录用户)下运行时,我想要实现的是来自会话 ID 的实际令牌句柄。
DWORD dwSessionId = 0;
if (false == ProcessIdToSessionId(dwProcessId, &dwSessionId))
{
LOG_ERROR(L"Failed obtaining session id");
return false;
}
HANDLE hToken
if (false == WTSQueryUserToken(dwSessionId, &hToken))
{
LOG_ERROR(L"Failed to obtain session's handle");
return false;
}
当我调用 WTSQueryUserToken 时出现问题,它失败并出现错误 1314,这意味着我需要授予调用令牌 SE_TCB_NAME 权限。
所以我尝试使用以下代码这样做:
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bool bSuccess = DynamicAPI::AdjustTokenPrivileges(
%%WHICH_TOKEN_EXACTLLY%%,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)nullptr,
(DWORD)nullptr);
但我不完全确定应该准确提供哪个令牌。我用 %%WHICH_TOKEN_EXACTLLY%% 占位符标记了它。对于我的测试,我尝试 AdjustTokenPriviliges 我的进程的令牌(管理员权限),但它也没有帮助。
如果需要调整权限的线程是模拟用户,使用OpenThreadToken(GetCurrentThread())
to get the impersonated token. Otherwise, use OpenProcessToken(GetCurrentProcess())
获取调用进程的token。
您通常需要在您的进程令牌中启用权限,您可以使用 GetProcessToken() 函数获得该权限。例外情况是,如果您打算在模拟时使用该特权,那么您应该改为在模拟令牌中启用该特权。
我使用此代码启用恢复权限:
DWORD enable_restore()
{
// This allows us to override security to delete files
HANDLE token;
BOOL flag;
struct {
DWORD count;
LUID_AND_ATTRIBUTES privilege;
} token_privileges;
token_privileges.count = 1;
token_privileges.privilege.Attributes = SE_PRIVILEGE_ENABLED;
flag = LookupPrivilegeValue(0, SE_RESTORE_NAME, &token_privileges.privilege.Luid);
if (!flag) return GetLastError();
flag = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token);
if (!flag) return GetLastError();
flag = AdjustTokenPrivileges(token, 0, (PTOKEN_PRIVILEGES)&token_privileges, 0, 0, 0);
if (!flag) return GetLastError();
return 0;
}
请注意,此代码不会检查权限是否实际被授予。为此,请在调用 AdjustTokenPrivileges() 后检查 GetLastError() - 这是少数情况之一,即使函数报告成功,最后的错误代码也有意义。
注意:这是您尝试使用进程令牌失败的最可能原因;如果您没有 运行 将代码设置为本地系统,并且没有重新配置 Windows 以授予您使用的帐户 SE_TCB_NAME 特权,则对 AdjustTokenPrivileges() 的调用将报告成功,但是没有效果。
此外,请记住,无论您是否拥有 SE_TCB_NAME 权限,如果您在本地系统上下文中 运行ning,则只能使用 WTSQueryUserToken(),即通常只有系统服务或系统服务上下文中的应用程序 运行 可以使用它。 (我不确定模拟本地系统是否足够。我怀疑不是。)