将 SessionId 转换为用户帐户 SID _without_ WTSQuerySessionInformation?

Posted

技术标签:

【中文标题】将 SessionId 转换为用户帐户 SID _without_ WTSQuerySessionInformation?【英文标题】:Convert SessionId to User Account SID _without_ WTSQuerySessionInformation? 【发布时间】:2020-12-02 19:47:30 【问题描述】:

我正在开发一个接收会话更改通知(特别是 SessionLogon)的服务 (C#)。我通过该通知获得的唯一信息是SessionId

我的最终目标是检查登录用户的配置文件(本地/漫游 AppData/MyCorp/MyApp 文件夹)是否有特定设置,如果存在则执行任务。

我需要从 SessionId 转到我可以映射到本地用户配置文件的东西,或者直接映射到 用户帐户 SID 或映射到可以映射到SID,(例如 "\" 等)。

我在 SO 上找到的解决方案依赖于 Windows 终端服务 (WTS) API(例如 WTSQuerySessionInformation),但远程桌面服务在 Windows 10 家庭版中不可用,所以这是一个非首发。

有谁知道如何从 SessionId 映射到不涉及 WTS API 的本地用户帐户?

(编辑#1)澄清:

在 .NET 中,ServiceBase 类有一个 OnSessionChange 覆盖,用于登录/注销/解锁/锁定事件。我最初认为这是针对所有此类事件(来自物理机或终端服务器)。

看起来这个适用于终端服务器会话(?)所以,显然,我得到的sessionId 是终端服务器特定的东西。正如@RbMm 在下面指出的那样,这个覆盖可能不会在 Windows Home 版上被首先调用。不过,这是一个有争议的问题,因为我感兴趣的是本地(物理)登录事件,这与终端服务会话完全不同。

在我看来,服务基类会有这样一个有用的事件,但它与 Terminal Services 相关联,而不是适用于所有情况,这对我来说似乎很奇怪。也许有人对此有所了解?

(编辑#2)实现:

@RbMm 的 cmets 消除了我一开始的一些误解。这是更新:

OnSessionChange 事件用于终端服务,与本地(物理)登录会话无关(我将两者混为一谈)。 我对本地登录会话感兴趣,因此我将寻找一种方法来在我的服务中获得有关它们的通知。如果没有此类通知,我将不得不设置一个计时器并进行投票。 我需要从收到的任何信息以及此类通知(或定期致电 LsaGetLogonSessionData)中获取用户帐户 SID

【问题讨论】:

如果远程桌面服务不可用或未运行 - 根本不会更改会话。结果没有通知,在这种情况下你永远不会打电话给WTSQuerySessionInformationW。从另一边这个 api 总是被导出,所以你总是可以导入它 我也认为文档非常糟糕且不正确。 如果远程桌面服务未运行,则对 WTSQuerySessionInformation 的调用失败 - 不清楚这仅用于检索会话 ID 或任何情况。但在我的系统上,远程桌面服务 (TermService) 没有运行,但 WTSQuerySessionInformation 不会失败 并返回实际信息 OnSessionChange - 我如何理解您准确注册终端会话通知。不是登录会话。这里你得到WM_WTSSESSION_CHANGE消息的wParam参数和指向WTSSESSION_NOTIFICATION的指针。所以你需要准确地打电话给WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSSessionInfo, (PWSTR*)&pp, &dwSessionId),我确定这个电话不会失败。 我认为您不了解终端和登录会话之间的区别。在单个终端会话中可以有几个不同的登录会话。例如运行this 看看输出 注册SERVICE_ACCEPT_SESSIONCHANGE 时无论如何服务都会收到SERVICE_CONTROL_SESSIONCHANGE 通知。它在用户登录,注销,锁定,解锁......等本地用户时调用,不仅适用于远程用户。如果本地用户 WinStationName 将是 Console 【参考方案1】:

我认为您可以通过 WMI 检索此信息

Win32_LogonSession

class Win32_LogonSession : Win32_Session

  string   Caption;
  string   Description;
  datetime InstallDate;
  string   Name;
  string   Status;
  datetime StartTime;
  string   AuthenticationPackage;
  string   LogonId;
  uint32   LogonType;
;

此外:

LogonId

数据类型:字符串

访问类型:只读

限定符:关键

分配给登录会话的 ID。

示例

var scope = new ManagementScope(ManagementPath.DefaultPath);
var query = new SelectQuery($"Select * from Win32_LogonSession where LogonId = SessionId");
var searcher = new ManagementObjectSearcher(scope, query);
var results = searcher.Get();
foreach (ManagementObject mo in results)

 

请注意,这是完全未经测试的

【讨论】:

关于登录会话(LUID)或终端会话(ULONG)的问题?这是绝对不同的事情。您查询有关登录会话的信息。为此存在LsaGetLogonSessionData。使用 wmi 总是不好的解决方案。这只是对 wmi 服务进程的远程调用。但是这个过程需要什么 api 来获取信息?为什么不直接调用这个api呢? @RbMm 如果 LsaGetLogonSessionData 符合 OP 的要求。也许你可以回答这个问题:)我的回答只是一个猜测,如果它错了,我很高兴删除 我不明白原来的问题 - 关于他问的是哪个会话。但我只是注意——如果信息可以通过 wmi 获得——这意味着我们可以在没有 wmi 的情况下获得相同的信息(这只是非常慢的远程调用)。从某种意义上说,最好使用LsaGetLogonSessionData,它返回SECURITY_LOGON_SESSION_DATA,然后是wmi,它内部无论如何调用LsaGetLogonSessionData LogonId 和SessionId 绝对不同。在同一个 SessionId 中可以是多个不同的 LogonId 会话。我认为 OP 询问他在 HandlerEx - SERVICE_CONTROL_SESSIONCHANGEWTSSESSION_NOTIFICATION 中收到的终端会话 ID。他在哪里得到DWORD dwSessionId。你,我想,这与登录会话混淆 抱歉耽搁了,但我想this comment解释情况

以上是关于将 SessionId 转换为用户帐户 SID _without_ WTSQuerySessionInformation?的主要内容,如果未能解决你的问题,请参考以下文章

安全标识符

如何将两个不同的ListAPIView转换为单个ModelViewSet

ghost系统sid重复无法加入域?

子账户 SID 和令牌检索

小白学习windows第四篇

尝试创建 iTunes 应用商店测试用户时出错;无法将 Apple ID 帐户转换为 iTunes 商店帐户