WTSQueryUserToken 抛出错误 1008,即使在 运行 下的 LocalSystem 下也是如此
WTSQueryUserToken throws error 1008, even when running under LocalSystem
我遇到的问题与 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
权限。另一个问题引用的同一段落:
Obtains the primary access token of the logged-on user specified by the session ID. To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege.
但是通过阅读 https://docs.microsoft.com/en-us/windows/win32/services/localsystem-account,在我看来,任何 进程 运行 在 LocalSystem
帐户下似乎 自动有这个特权:
The LocalSystem account has the following privileges:
- SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
- SE_AUDIT_NAME (enabled)
- SE_BACKUP_NAME (disabled)
- ...many others
- SE_TCB_NAME (enabled)
那么我是否需要明确地将此权限添加到我的进程中?还有什么可能是我的问题的原因? MTIA! :-)
当前WTSQueryUserToken
存在不完整的词组:
Among other errors, GetLastError can return one of the following
errors.
但在旧的 msdn 中是列表或错误可以 return api:
所以 ERROR_NO_TOKEN
意味着可以 returned if
The token query is for a session in which no user is logged-on. This
occurs, for example, when the session is in the idle state or
SessionId is zero.
如果我们当然在系统启动时尝试获取用户令牌,但没有任何登录用户。用户只是未知的,因此不存在和用户令牌(比如包含用户 sid 的令牌 - 但用户和未知,sid 未知,令牌此时不能存在)。但是,如果需要,服务可以在某些(任何)用户登录系统时准确启动进程。这需要从
HandlerEx
通过 RegisterServiceCtrlHandlerEx
注册的回调
我们需要寻找 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;
}
// ...
}
我遇到的问题与 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
权限。另一个问题引用的同一段落:
Obtains the primary access token of the logged-on user specified by the session ID. To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege.
但是通过阅读 https://docs.microsoft.com/en-us/windows/win32/services/localsystem-account,在我看来,任何 进程 运行 在 LocalSystem
帐户下似乎 自动有这个特权:
The LocalSystem account has the following privileges:
- SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
- SE_AUDIT_NAME (enabled)
- SE_BACKUP_NAME (disabled)
- ...many others
- SE_TCB_NAME (enabled)
那么我是否需要明确地将此权限添加到我的进程中?还有什么可能是我的问题的原因? MTIA! :-)
当前WTSQueryUserToken
存在不完整的词组:
Among other errors, GetLastError can return one of the following errors.
但在旧的 msdn 中是列表或错误可以 return api:
所以 ERROR_NO_TOKEN
意味着可以 returned if
The token query is for a session in which no user is logged-on. This occurs, for example, when the session is in the idle state or SessionId is zero.
如果我们当然在系统启动时尝试获取用户令牌,但没有任何登录用户。用户只是未知的,因此不存在和用户令牌(比如包含用户 sid 的令牌 - 但用户和未知,sid 未知,令牌此时不能存在)。但是,如果需要,服务可以在某些(任何)用户登录系统时准确启动进程。这需要从
HandlerEx
通过 RegisterServiceCtrlHandlerEx
我们需要寻找 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;
}
// ...
}