Win32之Session

现在做的项目有一个用服务起的后台常驻程序,服务是一个守护进程,然后拉起一后台常驻进程。这个时候守护进程用户是system,会话ID是0,后台常驻的进程的会话ID是1。第一次接触到了会话的概念,借此了解一番。

Win7开发文档里边写到:

服务是整合在Microsoft Windows操作系统中的结构。服务与用户的应用程序不同,因为你可以对他们进行配置,不需要一个激活的用户登录,就可以使这些服务在系统启动的时候运行,直到系统关闭。Windows中的服务,负责所有种类的后台活动,但不包括从远程过程调用(RPC)服务到网络位置服务的用户。

一些服务可能会试图显示一些用户界面对话框,或者与用户的应用程序进行通信。这些服务都将面临与Windows 7 的兼容性问题。这个就是Windows 7的服务的Session 0隔离机制。

在Windows XP, Windows Server 2003或者更早期的Windows操作系统中,所有的服务和应用程序都是运行在与第一个登录到控制台的用户得Session中。这个Session叫做Session 0。在Session 0 中一起运行服务和用户应用程序,由于服务是以高权限运行的,所以会造成一些安全风险。这些因素使得一些恶意代理利用这点,来寻找提升他们自身权限的结构。

在Windows Vista中,服务在一个叫做Session 0 的特殊Session中承载。由于应用程序运行在用户登录到系统后所创建的Session 0 之后的Session中,所以应用程序和服务也就隔离开来:第一个登录的用户在Session 1中,第二个在Session 2中,以此类推。事实上运行在不同的Session中,如果没有特别将其放入全局命名空间(并且设置了相应的访问控制配置),是不能互相传递窗体消息,共享UI元素或者共享kernel对象。

IC351751

上面这张图片看起来就比较清楚了。

所以,在Vista之前,服务和应用程序在同一Session中,没有太多问题,服务进程创建一个新的用户进程只需要调用CreateProcess即可。在Vista之后,由于Session 0隔离机制的存在,服务进程创建新的用户进程需要调用CreateProcessAsUser,在这之前还要进行一下权限的操作

获取当前活动会话ID
DWORD dwSessionID = WTSGetActiveConsoleSessionId();

获取当前活动会话的令牌
HANDLE hToken = NULL;
WTSQueryUserToken(dwSessionID, &hToken);

创建一个当前用户进程
CreateProcessAsUser(hDuplicatedToken, lpszClientPath, NULL, NULL, NULL, FALSE,
 NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE |CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si, &pi);

但是这样创建的只是普通用户进程,有些时候我们需要更高的权限,比如现在的项目,后台进程是system用户。

参见MSDN中SetTokenInformation 和 TOKEN_INFORMATION_CLASS的说明,进程所属的Session由进程令牌中的TokenSessionId来决定,我们就可以复制服务进程的Token令牌,修改其中的TokenSessionId,从而在用户桌面创建一个system进程。

HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
获得服务进程句柄
HANDLE hProcess = GetCurrentProcess();
获取进程令牌
OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken);

复制进程令牌
HANDLE hDuplicatedToken = NULL;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken);

创建环境快
LPVOID lpEnvironment = NULL;
CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE);

然后调用CreateProcessAsUser,就使用服务进程创建了一个system进程。

还有跨Session的内核对象要以“Global\”进行命名,这样内核对象属于全局Session空间中。例如在之前创建的system进程和服务进程使用事件进行通信时,事件命名为“Global\EventName”。

猜你喜欢

转载自www.cnblogs.com/w1ng/p/10182525.html