阿猫翻译的,用作备忘
深入理解windows——session、window stations、desktops
翻译自:http://www.brianbondy.com/blog/id/100/
本文将回答一些关于windows内部工作的简单问题。本文预期读者为有技术背景的人,同时部分内容对有一定windows编程经验的人来说特别有帮助。
如果你没有完全理解如下问题,你应该阅读本文:
要理解上面提到的全部问题,你需要理解如下概念: Sessions, Window Stations, 和Desktops.
一些解释可能难于理解,但值得学习他来了解windows是如何工作的
Sessions简介:
你机器上的所有程序,当运行时,都被叫做一个进程。进程指的是正在执行的程序副本。每个进程都包括代码页、一堆执行的线程,以及相关资源。
每个进程都唯一的属于他的启动用户,同时也属于一个叫做Session的东西。每个Session包括一堆进程,这些进程开启的窗体,Window Stations, Desktops,以及其他资源。其中Window Stations, Desktops将在本文中被介绍。
你可以在任务管理器中看到机器运行的所有进程。打开任务管理器,切换到进程选项卡,你可以看到进程以及他启动着的对应关系,也能改改看到进程对应的Session。Windows默认不显示session,但你可以在查看菜单中选择列为session id的列
任何进程都有且只有一个session。每个session都有有一个session id对应。启动后不能修改进程的session。Vista(不含)以下版本的win任务管理器中你至少会看到一个session。Vista以上版本的win你至少会看到两个session。
Win不会将你限制在初始数目的session上。你可以创建任意个数的session——有最大上限,但是为了方便起见,我们假设你可以创建无限个session。
Vista以上版本的session0是专用于服务的,0以上的第二个启动的session是第一个登录系统的用户的程序执行的地方。
当有更多用户登录到同一台机器上的时候,将会有更多session创建。包括任何途径——终端服务、远程桌面、快速切换等,任何时候,只要有一个成功登录,一个新的session就创建了。
用API CreateProcessAsUser 来在另一个session中创建进程.调用需要包括关联session的用户标识(token,安全相关)。用Win32 API SetUserToken 和用户标识(TokenSessionId)
来设置session的token
下面简单的说明了目前为止,我们对win里头的理解:
Vista改了session运作方式:
Vista之前,首个登录用户和服务共享第一个session,叫做session 0.session0可以进行交互。
Vista起,将用户和服务session隔离开来,session0 用于运行服务,从而不可与用户交互(session1,上面提到过)
如此更改是由于安全原因。用于保证服务不受应用程序的干扰。为毛服务被特殊保护?主要是由于服务的特权(System权限),这个特权意义重大,能搞一些普通程序不能搞的事情。看下面的内容。"How to circumvent all security in Windows".
Vista之前3用户的session状况:
Vista之后的3用户session状况:
两张图的区别在于第一个登录用户是否与服务共享session 0.
Window Stations:
每个session里头都有一堆的Window Stations, 剪贴板,以及其他的乱七八糟的东西。每个station都有个名字,这个名字在所属的session中唯一。意思是在一个session中,每个window station都是独立的。多个不同session中的window stations可以叫同一个名字,但他们同样的也是相互独立的。
你可以认为一个window station是一个安全边界。同样的,一个window station创建后你也不能修改所属的session。
进程属于window station,但不同于session和进程的关系,进程可以运行时修改所属的window station
可用于搞window station的api: GetProcessWindowStation, SetProcessWindowStation, CreateWindowStation, and OpenWindowStation.
每个session都有个特别的window station叫做Winsta0. WinSta0是唯一的一个可以显示ui和接收输入的。处理键盘鼠标和显示。其他的不能搞定gui和用户输入。
进程用于设置window station的api: SetProcessWindowStation.
但一个进程设置了所属的window station,就可以访问station所属的东西,比如桌面和剪贴板。后头将讨论桌面。.
进程被父进程启动,如果你没有改window station,将继承父进程的window station。如下api用于创建新的window station: CreateWindowStation
目前为止,win里头有如下的东西:
Windows Desktops
每个 Window Station都有一堆桌面(desktops)。 桌面(desktop)是载入内核内存空间中的,逻辑上存在的显示设备。所有GUI对象都在桌面上分配。
每个桌面都属于一个session和(同时也属于)一个 window station
同一时间每个session只有一个桌面能被显示。根据定义,必须属于WinSta0. 该桌面叫做输入桌面。可以用如下api拿一个到当前session的输入桌面的句柄: OpenInputDesktop
WinSta0 有三个桌面:
在vista以上版本的win中有第四个桌面,叫做安全桌面("Secure Desktop"),用于uac提示。
锁定机器的时候从默认桌面转入WinLogon桌面.
NT服务运行的时候,每个有指定权限的服务都将创建自己的station和桌面。(下头会讲相关内容,参考. 允许服务与桌面交互)
如下api用于处理桌面相关:
要指定启动进程的desktop 和window station,可以修改STARTUP结构的lpDesktop成员。通常被CreateProcessAsUser or CreateProcess调用
目前为止,windows桌面内部结构如下:
选读:服务配置页的谜样的多选框
奇怪的多选框:允许服务与桌面交互。
这个多选框决定服务是运行在Window Station Winsta0还是其他的,不允许用户交互的Window Station。不确定这个多选框是不是会在今后的版本被移除,但直到win7还会是被支持的。(8.1也还是支持的)
任何服务都可以从注册表中打开该选项,因此他本身就可能有安全隐患,因此猜测可能会在今后的版本中移除。.
打开选项会创建一个新的session,并创建新的window station叫做winsta0.若服务试图显示gui,会 在用户当前session上激活一个提示框,告诉你其他桌面有消息需要被处理。你可以单击确定来显示gui,或者说等个5min再提示。单击显示,一般会看到一个黑屏,上头放着service的gui,没有别的东西了。
关闭该选项的时候,若服务试图显示gui,没有任何提示,调用不会失败但也不会有任何的效果。服务起的的时候会在session0上启动。
Windows 句柄
Windows系统中的窗口属于desktop对象。
窗口是任何用于显示的gui元素,通常被一个windows句柄(hwnd)所指示。理解windows句柄是非常重要的,这样可以理解在与Desktop交互的时候什么\
Sessions通信
取决于通信类型,跨session通信是可能的。
管道,全局事件,sockets等可以跨session通信。.
但如windows messages和本地事件是不允许跨session通信的。
如前所述,windows vista有巨大的改变,从这个版本开始所有服务在session0中而不与用户共享。意味着大量的以windows services模式运行的程序,不再能直接显示gui。
对服务而言适当的显示gui的方式是做一些跨session通信,如管道等。这时候gui程序会是另一个程序,通过跨进程通信方式与服务交互。
另一个方式是在用户session的winsta0中的默认桌面上启动一个进程。
桌面间的通信
Windows消息不能跨桌面通信,只能在同一桌面上通信。如下文章确认: Inter-Desktop communication via message passing is not possible.
意味着用于监视和得到通知的hook消息只能在同一桌面上完成。
因此键盘记录器不能记录到锁屏的密码,因为在不同桌面上。
枚举桌面后,可以枚举每个桌面的所有窗口.可以用API EnumDesktopWindows 来枚举桌面窗体。这个api拿一个desktop的句柄并且返回在这个desktop里头的窗体的句柄,侧面证明了windows是desktop的一个子对象。
绕过安全机制(未测试)
访问并对其他session、window station、desktop为所欲为实际上是可能的。方法是建立一个以system账户运行的服务。
该服务运行并提权(通过manifest问卷)后,可以拿到token并且将其与任何session中的任何进程的token相联系,然后用token运行一个帮助程序来做任何想做的事。实际上windows任务管理器就是这么干的。
//uac创建两个token,第二个是受限的token,第一个则是logonuser返回的token。
//UAC creates 2 tokens. The second one is the restricted token and the first one is the one returned by LogonUser //Vista and above links the elevated token to the Logonuser token though :)))) TOKEN_LINKED_TOKEN tlt; DWORD len; if(GetTokenInformation(hToken , (TOKEN_INFORMATION_CLASS)TokenLinkedToken , &tlt, sizeof(TOKEN_LINKED_TOKEN) , &len)) { hLinkedToken = tlt.LinkedToken; //From here you can start elevated processes }
捆绑在一起 Tying it all together
回答之前的问题。
当你锁定计算机的时候会发生什么?对于所有正在运行的程序而言?对于任务栏而言?
锁屏将当前桌面转换到winlogon桌面,这两个桌面在同一个window station winsta0中的。当然,两个桌面在同一个session中。
同样也意味着每个session有自己独立的登录屏幕,并且同一时间,在同一个机器上不同的用户有自己的独立的屏幕
UAC有啥特别的?他们如何锁定并且将整个屏幕变暗?他能真正的保护我吗?
Uac默认将你转入一个叫做安全桌面的桌面上。Uac创建截屏并且将变暗效果在图像上处理。然后在上头显示uac。Uac是安全桌面的一部分,用户可以要求在当前桌面上显示uac提示窗口(安全性较低一些)
为毛键盘记录器无法记录一台锁屏计算机的密码
小时候。。这不重要啦I remember as a kid writing a key logger and using it at school. I was able to see everyone's login password, then later I could login as them and see all of their files. Since then multi Session operating systems have been introduced though.
键盘记录软件 依赖于hook监听windows message来接受每个键的事件(按下、弹起、击键——按下短时间弹起)
由于键盘记录器与登录界面不在同一桌面,因此不能记录密码.
跨session的键盘记录器可能是可能的。但没有发现存在的。看上头获得更多信息。
屏保及其工作原理
没有什么特别的,没有隐藏任何gui元素,也没有在上头绘制,只是做了一次桌面切换操作,切换到屏保桌面。记住桌面是一个逻辑的图形设备
多用户同时登陆
非常简单,每个用户有一个自己的session,每个session有其他的东西,每个人看到自己的winsta0 window Station.
.
终端服务
终端服务与远程桌面让你能访问一个已经打开的session或新的session。Session可以在已连接或未连接的状态。
为毛一些远程控制软件很渣
一些原厂控制软件(不是终端服务/远程桌面)没有考虑session,只能运作在第一个session上。包括大多数 VNC servers including FogCreek Copilot.
这种软件有多个session存在时不能控制其他session.
进程跨session通信
可以,但是你需要知道通信指的是什么(管道、socket等)
进程跨桌面接受消息?
做不到
Vista为毛那么渣,而win7就可以接受了
(一种原因是)vista部分的破坏了向后兼容性,许多软件开发公司及他们的产品没来得及处理session0隔离。最大的问题在于没有正确的理解。
Win7推出的时候一段时间已经过去了,因此一些改变已经发生。因此vista看起来很渣,当然,这就是vista的问题,因为他首先破坏了向后兼容性。
我没说vista完美,远远没到完美,但对vista的批评高于它应得的。
进一步阅读