如何使用 C++ 从 Windows 服务中获取登录用户的令牌?

如何使用 C++ 从 Windows 服务中获取登录用户的令牌?

问题描述:

在 windows vista 上 &以上,

on windows vista & above,

目前,我正在枚举所有 Windows 会话,然后一旦找到活动会话,就会调用 WTSQueryUserToken(),它为我提供当前用户的令牌.

currently, I am enumerating all windows sessions, then once I find an active session, WTSQueryUserToken() is called which gives me the token of current user.

此令牌用于以他的权限/在他的桌面内启动一个进程.

This token is used to launch a process with his privileges / inside his desktop.

我面临的问题是没有可靠的方法来获取活动会话/交互式会话.我必须等待(每隔几毫秒检查一次它是否存在),直到生成 explorer.exe.

Problem I am facing is that there is not reliable way to get the active session / interactive session. I have to wait (check its presence every few millsecs) until explorer.exe is spawned.

我不喜欢来自用户已登录的 SENS(系统通知服务)的通知.

I am not preferring notifications like those from SENS (system notification service) that user has logged on.

在收到 SERVICE_CONTROL_SESSIONCHANGE/登录事件时,我调用 WTSGetActiveConsoleSessionId() 来获取当前会话,然后我使用此会话 ID 和 WTSQueryUserToken() 来获取令牌.

On receiving SERVICE_CONTROL_SESSIONCHANGE / logon event I call WTSGetActiveConsoleSessionId() to get the current session then I use this session ID with WTSQueryUserToken() to get token.

WTSGetActiveConsoleSessionId() 有时会返回会话 0.因此,当我想要来自当前登录用户会话的令牌时,我最终会得到会话 0 的令牌.

WTSGetActiveConsoleSessionId() sometimes returns me session 0. Thus I end up with token of session 0 when I want token from session of currently logged-in user.

这取决于 WTSGetActiveConsoleSessionId() 调用的时间.

It depends on timing of WTSGetActiveConsoleSessionId() call.

通过试验,我想出了等待 explorer.exe 的想法,只有在它出现后才调用 WTSGetActiveConsoleSessionId(),这似乎可以保证我总是获得会话 1 或更高版本以及相应的令牌.

By experimenting I came up with idea to wait for explorer.exe and only after it comes up call WTSGetActiveConsoleSessionId(), this seems to guarantee that I always get session 1 or above and thus corresponding token.

寻求更清洁的方法.

在收到 SERVICE_CONTROL_SESSIONCHANGE/登录事件时,我调用 WTSGetActiveConsoleSessionId() 来获取当前会话,然后我使用此会话 ID 和 WTSQueryUserToken() 来获取令牌.

On receiving SERVICE_CONTROL_SESSIONCHANGE / logon event I call WTSGetActiveConsoleSessionId() to get the current session then I use this session ID with WTSQueryUserToken() to get token.

您应该使用由 SERVICE_CONTROL_SESSIONCHANGE 本身报告的会话 ID.lpEventData 参数将是一个指向 WTSSESSION_NOTIFICATION 结构,其中包含一个 dwSessionId 字段.

You should be using the session ID that is reported by SERVICE_CONTROL_SESSIONCHANGE itself. The lpEventData parameter will be a pointer to a WTSSESSION_NOTIFICATION structure, which contains a dwSessionId field.

WTSGetActiveConsoleSessionId() 有时会返回会话 0.

WTSGetActiveConsoleSessionId() sometimes returns me session 0.

WTSGetActiveConsoleSessionId() 返回附加到本地机器的物理控制台(鼠标/键盘/显示器)的会话.它永远不会在 Vista 及更高版本中报告会话 0(由于会话 0 隔离),但在 XP 中可以(其中第一个登录的交互式用户使用会话 0).但是,即使它可以报告会话 0,也不能保证它是与登录用户关联的正确会话.除了通过物理控制台之外,还有其他方法可以登录到计算机.例如远程桌面.

WTSGetActiveConsoleSessionId() returns the session that is attached to the physical console (mouse/keyboard/monitor) of the local machine. It can NEVER report session 0 in Vista and later (due to session 0 isolation), but it can in XP (where the first interactive user to login uses session 0). However, even if it could report session 0, that is not guaranteed to be the correct session that is associated with the user who logged in. There are other ways to log in to a computer than through its physical console. Remote Desktop, for example.

因此,当我想要来自当前登录用户的会话的令牌时,我最终得到了会话 0 的令牌.

Thus I end up with token of session 0 when I want token from session of currently logged-in user.

您需要查询用户实际登录的会话.SERVICE_CONTROL_SESSIONCHANGE 告诉您实际的会话 ID,它在 Vista 及更高版本上永远不会为 0(由于会话 0 隔离).

You need to query the session that the user actually logged into. SERVICE_CONTROL_SESSIONCHANGE tells you the actual session ID, which will never be 0 on Vista and later (due to Session 0 isolation).

通过试验,我想出了等待 explorer.exe 的想法,只有在它出现后才调用 WTSGetActiveConsoleSessionId(),这似乎可以保证我总是获得会话 1 或更高版本以及相应的令牌.

By experimenting I came up with idea to wait for explorer.exe and only after it comes up call WTSGetActiveConsoleSessionId(), this seems to guarantee that I always get session 1 or above and thus corresponding token.

但这并不能保证活动控制台会话是要查询的正确会话.

But that is not a guarantee that that active console session is the correct session to query.

寻求更清洁的方法.

使用通知明确告诉您的会话 ID.不要去寻找它.

Use the session ID that the notification explicitly tells you. Don't hunt for it.