Windows 7系统服务的Session 0隔离
在Windows XP,Windows Server 2003以及其他更早期的Windows操作系统中,所有操作系统服务和应用程序都在相同的session中运行,这个session由第一个登陆系统的用户所启动。这个session被称为Session 0。在Session 0中同时运行系统服务和应用程序会给操作系统带来一些安全风险,因为服务运行在一个更高的用户权限下,这就使得系统服务成为那些想要提升自己权限的病毒或者恶意软件的攻击目标。
从Windows Vista开始,系统服务开始运行在一个被称为Session 0的特殊session中。而应用程序则被跟系统服务隔离开来,这是因为应用程序运行在由用户登录系统后创建的一系列session中。比如,Session 1对应于第一个登陆的用户,Session 2对应于第二个登录系统的用户,以此类推。
图3 Windows操作系统的Session
各个Session之间是相互独立的。在不同Session中运行的实体,相互之间不能发送Windows消息、共享UI元素或者是在没有指定他们有权限访问全局名字空间(并且提供正确的访问控制设置)的情况下,共享核心对象。
图4 Session之间是相互独立的
跨越鸿沟,如何突破Session 0隔离
虽然Session 0隔离可以使得操作系统更加安全,但是,有时候运行于Session 0的系统服务和运行于其他Session的进程之间进行交互和通信时必须的。就像大禹治水,我们不能仅仅把Session 0隔离起来就万事大吉了,我们还需要采用疏导的方式,用更加安全的方式完成Session 0和其他Session之间的交互和通信。针对Session 0隔离所带来的两类问题,我们提供相应的解决方案。
从系统服务显示消息对话框
如果一个系统服务想要发送消息对话框给用户,我们可以使用WTSSendMessage函数。这个函数提供了跟MessageBox大致相同的功能。这将为那些无需复杂UI的服务提供了一个简单的,易于实现的,但是功能足够的解决方案。并且,这也是安全的,因为被显示的消息框不能被用来控制底层服务。还是上文的MessageBox的例子,我们用ShowMessage函数封装WTSSendMessage函数,从系统服务显示一个消息对话框到用户桌面:
void ShowMessage(LPWSTR lpszMessage, LPWSTR lpszTitle)
{
// 获得当前Session ID
DWORD dwSession = WTSGetActiveConsoleSessionId();
DWORD dwResponse = 0;
// 显示消息对话框
WTSSendMessage(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);
}
DWORD WINAPI TimeServiceThread(LPVOID)
{
// 进入服务循环
while (!g_Stop)
{
DWORD dwResponse = 0;
Sleep(5000);
// 显示对话框
ShowMessage(L"这是一个从Session 0显示的对话框",
L"Session 0隔离");
if (dwResponse == IDNO)
continue; //
//
}
return 0;
}
这样,我们就可以直接看到来自服务的消息对话框而不会被“Interactive Service Detection”所打断工作流。