【问题标题】:WTSQueryUserToken throws error 1008, even when running under LocalSystemWTSQueryUserToken 抛出错误 1008,即使在 LocalSystem 下运行时也是如此
【发布时间】:2020-11-05 10:55:32
【问题描述】:

我遇到了与WTSQueryUserToken always throws "An attempt was made to reference a token that does not exist" on Windows 7 in C# 中讨论的几乎相同的问题,但与该问题的 OP 不同,我在 Windows 10 上使用 C++ 并在开始编写我的解决方案之前正确阅读了文档。所以我的服务肯定是在LocalSystem 帐户下运行的。

这是我的SvcInit() 函数的相关部分:

    HANDLE hToken;

    // Returns 1, just like in the linked question
    DWORD sessionId = WTSGetActiveConsoleSessionId();

    if (!WTSQueryUserToken(sessionId, &hToken)) {
        // LogError() takes the name of an error-causing function and calls
        // GetLastError() and FormatMessage() to get the system-defined error
        // message, then logs all of that to a file
        LogError("WTSQueryUserToken");
        return;
    }

文档还提到您的服务进程需要拥有SE_TCB_NAME 权限。其他问题引用的同一段:

获取会话 ID 指定的登录用户的主要访问令牌。要成功调用此函数,调用应用程序必须在 LocalSystem 帐户的上下文中运行并具有 SE_TCB_NAME 权限。

但是通过阅读https://docs.microsoft.com/en-us/windows/win32/services/localsystem-account,在我看来,在LocalSystem 帐户下运行的任何进程都会自动拥有此特权:

LocalSystem 帐户具有以下权限:

  • SE_ASSIGNPRIMARYTOKEN_NAME(已禁用)
  • SE_AUDIT_NAME(已启用)
  • SE_BACKUP_NAME(已禁用)
  • ...许多其他人
  • SE_TCB_NAME(已启用)

那么我是否需要明确地将此权限添加到我的进程中?还有什么可能是我的问题的原因?大都会! :-)

【问题讨论】:

  • ERROR_NO_TOKEN - 令牌查询是针对没有用户登录的会话。例如,当会话处于空闲状态或 SessionId 为零时,就会发生这种情况。
  • @RbMm 你从哪里得到的描述?根据docs.microsoft.com/en-us/windows/win32/debug/…,错误1008的描述是“试图引用一个不存在的令牌”,这也是我从FormatMessage()得到的以及链接问题的状态。但是该描述并没有真正解释 为什么 令牌不存在,或者我应该错误地引用它。我将在问题中添加一个代码 sn-p,希望能提供更多见解。
  • i.imgur.com/UcUOPpv.png - 更好地展示你的相关代码
  • 会话 1 中的 csrss.exewinlogon.exe 已经启动。所以终端 1 会话已经存在。但还没有任何登录用户。并简单地提问-此时您需要什么用户令牌?如果系统中存在多个用户 - 您认为必须获得哪个具体的用户令牌?只有这个问题显示设计错误。你需要开始的关键问题 - 你需要一些用户令牌?
  • 无论如何你都需要等到某个用户登录。在服务中,在 HandlerEx 例程中你会收到会话通知 - SERVICE_CONTROL_SESSIONCHANGE - 看看WTS_SESSION_LOGON 和@987654334 @你将拥有dwSessionId

标签: windows windows-services c++17


【解决方案1】:

在当前WTSQueryUserToken 中存在不完整的短语:

在其他错误中,GetLastError 可以返回以下之一 错误。

但在旧的 msdn 中是可以返回 api 的列表或错误:

所以ERROR_NO_TOKEN的意思是可以返回如果

令牌查询是针对没有用户登录的会话。这个 发生,例如,当会话处于空闲状态时或 SessionId 为零。

如果我们尝试在系统启动时获取用户令牌,当然还没有任何登录用户。用户只是未知的,因此不存在用户令牌(比如包含用户 sid 的令牌 - 但用户和未知,sid 未知,此时令牌不能存在)。但是,如果需要,服务可以在某些(任何)用户登录到系统时准确启动进程。这需要从 通过RegisterServiceCtrlHandlerEx注册的HandlerEx回调

我们需要寻找SERVICE_CONTROL_SESSIONCHANGE 事件。 用户会话中运行过程的简单代码可以是这样的

DWORD WINAPI HandlerEx(
                       DWORD dwControl,
                       DWORD dwEventType,
                       PVOID lpEventData,
                       PVOID lpContext
                       )
{

    switch (dwControl)
    {
    case SERVICE_CONTROL_SESSIONCHANGE:

        if (dwEventType == WTS_SESSION_LOGON)
        {
            HANDLE hToken;
            if (WTSQueryUserToken(reinterpret_cast<PWTSSESSION_NOTIFICATION>(lpEventData)->dwSessionId, &hToken))
            {
                PVOID lpEnvironment;
                if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
                {
                    STARTUPINFOW si = { sizeof(si) };
                    PROCESS_INFORMATION pi;
                    if (CreateProcessAsUserW(hToken, 
                        L"c:\\windows\\notepad.exe", 0, 0, 0, 0, 
                        CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &si, &pi))
                    {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                    }
                    DestroyEnvironmentBlock(lpEnvironment);
                }
                CloseHandle(hToken);
            }
        }
        break;
    }

    // ...
}

【讨论】:

  • 写得真棒!再次感谢:D
  • 你好,我已经更新了我的代码来处理 SERVICE_CONTROL_SESSIONCHANGE 但似乎代码从未执行过......任何想法为什么?我的代码几乎与 MSDN 上的 The Complete Service Sample 相同,但我已将 ReportSvcStatus() 中的 gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP 更改为 gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE,更新了 SvcCtrlHandler() 以匹配您的代码,并添加了我自己的代码,该代码不应该对 @ 产生任何影响987654337@。什么给了?!
  • @Kenny83 - 此代码为 SvcCtrlHandler 调用 RegisterServiceCtrlHandler 但您需要使用 RegisterServiceCtrlHandlerEx 使用 - 阅读此 This parameter can also be one of the following extended control codes. Note that these control codes are not supported by the Handler function.
  • @Kenny83 only HandlerEx 收到了SERVICE_CONTROL_SESSIONCHANGE 通知。
  • 对不起,我忘了提到我也改变了它(这几乎是我对 MSFT 代码所做的第一次改变)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-09
  • 2018-07-18
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多