从会话 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(),即通常只有系统服务或系统服务上下文中的应用程序 运行 可以使用它。 (我不确定模拟本地系统是否足够。我怀疑不是。)