[Win32] 服务程序开发(2)Session 0隔离(上)

来源:互联网 发布:陕师大远程教育网络 编辑:程序博客网 时间:2024/05/14 01:10
本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/47614907

在上一篇博文中,我说了如何编写一个系统服务,SERVICE_STATUS结构中有一个SdwServiceType成员,ERVICE_INTERACTIVE_PROCESS表示服务是一个交互式服务,可以与用户交互,MSDN上虽然是这么说的,其实经过测试,在XP上这一个完全不影响服务显示UI,只要安装服务时允许服务与桌面交互即可(见下图)。而在WinVista和Win7以及更高的平台,天生就有Session 0隔离,这一个加不加就显得更鸡肋了。。

MSDN关于Session 0隔离的兼容性白皮书:(话说MSDN上有篇中文的文档可真不容易,,)https://msdn.microsoft.com/zh-cn/library/ee663077.aspx

简单说,Win32子系统中有会话这一概念,Vista以后,服务被隔离到了Session 0会话,用户会话从1开始,因此他们之间不能直接共享UI。

我们知道,会话之中是窗口站,窗口站里面有桌面,其中用户会话的交互式窗口站是固定的,也就是winsta0,其中的默认桌面也是固定的default,也就是说我们只需要在这个桌面窗口一个进程即可。

当然,直接使用CreateProcess肯定是不行的,因为进程的令牌会继承,进程令牌里有会话ID。那么我们就使用CreateProcessAsUser即可。

如何在编写服务,如何在服务使用下面的代码请参见:[Win32] 服务程序开发(1)基本概念和服务程序的框架

void ShowMessage(LPWSTR lpszMessage, LPWSTR lpszTitle){// 获得当前Session IDDWORD dwSession = WTSGetActiveConsoleSessionId();DWORD dwResponse = 0;// 显示消息对话框WTSSendMessageW(WTS_CURRENT_SERVER_HANDLE, dwSession,lpszTitle,static_cast<DWORD>((wcslen(lpszTitle) + 1) * sizeof(wchar_t)),lpszMessage,static_cast<DWORD>((wcslen(lpszMessage) + 1) * sizeof(wchar_t)),0, 0, &dwResponse, FALSE);}void CreateUserProcess(LPCTSTR Filename){STARTUPINFO si;PROCESS_INFORMATION pi;RtlZeroMemory(&si, sizeof(STARTUPINFO));RtlZeroMemory(&pi, sizeof(PROCESS_INFORMATION));si.cb = sizeof(STARTUPINFO);//si.lpDesktop = TEXT("Winsta0\\default");HANDLE hToken, hDuplicatedToken = NULL;WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hToken);//获取用户令牌DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken);//复制令牌LPVOID lpEnvironment = NULL;CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE);//创建当前用户环境//在当前用户创建进程(CREATE_UNICODE_ENVIRONMENT表示用户环境是Unicode字符串)if (CreateProcessAsUser(hDuplicatedToken, Filename, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si, &pi) == 0){ShowMessage(L"在用户界面创建进程失败", L"Error");}//释放资源CloseHandle(pi.hProcess);CloseHandle(pi.hThread);CloseHandle(hToken);CloseHandle(hDuplicatedToken);DestroyEnvironmentBlock(lpEnvironment);}


CreateUserProcess这个函数就是创建一个当前用户的进程,不过如果开启了UAC这个进程是没有管理员权限的,因为开启UAC时WTSQueryUserToken获取的是低权限令牌。

在Win8.1测试:运行正常。

在Win10测试:新创建的进程窗口不能直接创建在前面,即使新进程调用SetWindowPos

在Win7测试:和win10效果一样,新创建的进程窗口不能直接创建在前面,即使新进程调用SetWindowPos

在XP测试:和win8.1效果一样,运行正常。

进一步测试:运行的程序创建一个有总在最前风格的程序窗口

Win8.1正常、Win7正常、Win10正常、XP正常

下一篇中,将介绍如何在当前用户桌面上创建一个SYSTEM权限的进程



0 0