桌面环境
https://msdn.microsoft.com/en-us/library/windows/desktop/ee663298(v=vs.85).aspx
Windows Shell
https://msdn.microsoft.com/en-us/library/windows/desktop/bb773177(v=vs.85).aspx
Windows 桌面UI 为用户提供访问运行应用程序和管理操作系统所需要的各种对象。其中我们最最熟悉的对象是驻留在计算机磁盘驱动器上的文件夹和文件。另外,有许多虚拟对象以允许用户执行特定的任务,比如发送文件到远程打印机或者访问回收站。Shell 将这些对象组织成一个分层的命名空间,并给用户和应用程序提供了一种有效的方式来访问和管理对象。
Shell 开发方案
与应用程序开发有关的开发方案。
1. 扩展Shell,包括创建一个数据源(相比于使用Shell 数据模型相比)
2. 实现Shell 数据源任务的一个子集
3. 在Windows 资源管理器中支持库和项目视图
4. 使用公共的文件对话框
5. 实施控制面板项目
6. 管理通知
与文件格式拥有权有关的开发方案
1. 实现Shell 数据源任务的一个子集
2. 实现任意的处理程序
3. 支持桌面搜索
与数据存储拥有者有关的开发方案。
- 支持桌面搜索和开放搜索
- 实现Shell 数据源任务的一个子集(虚拟文件夹)
- 在Windows 资源管理利器中支持库
下面是一些与设备支持有关的开发方案。
1. 自动执行和自动播放
Windows Shell SDK 文档
文档分为三大部分。
1. Shell 开发者指南,提供有关Shell 的工作原理以及如何在应用程序中使用Shell 的API 的概念资料
2. Shell 接口,
3. Shell SDK 示例代码
Windows 属性系统
https://msdn.microsoft.com/en-us/library/windows/desktop/ff728898(v=vs.85).aspx
Windows Shell 系统是一个扩展的读/写数据定义的系统,系统提供了一个唯一的方式来表达Shell 项目的元数据。Windows 属性系统使得用户可以存储和检索Shell 项目的元数据。一个Shell 项目是任何单独的内容,比如一个文件,目录,邮件或者联系人。属性是与Shell 项目关联的单个元数据。
Windows 搜索
https://msdn.microsoft.com/en-us/library/windows/desktop/ff628790(v=vs.85).aspx
Windows Search 是一种桌面搜索平台,可以为大多数常见的文件和数据类型(电子邮件,联系人, 日历约会,文档,照片,多媒体以及可由第三方开发人员扩展的其他格式)提供即时搜索功能。这些功能使用用户能够在家庭和企业环境中查找,管理和组织越来越多的数据。
窗口站和桌面
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687098(v=vs.85).aspx
Windows 创建了三种主要类型的对象:用户接口,图形设备接口,还有内核。内核对象是可保安全的,但是用户对象和GDI 对象是不可以的。为了提供额外的安全性,使用窗口站和桌面来管理用户接口对象,这两个对象本身是可保安全的。
Windows 帮助
描述Windows 中可用的帮助技术。
控制台
控制台管理字符模式应用程序(不提供它们自己的图形用户接口的应用程序)的输入和输出。
上面简单介绍了桌面环境的组成。下面我们着重介绍窗口站和桌面的信息。
窗口站
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687096(v=vs.85).aspx
一个窗口站包含剪贴板,原子表和一个或者多个桌面对象。窗口站对象是可保安全的,当一个窗口站被创建了,它被绑定到调用者进程和当前的会话。
交互式窗口站是唯一可以显示用户界面或者接收用户输入的窗口站。它被绑定到交互式用户的登陆会话上,其包含了键盘,鼠标,和一个显示设备。它有一个固定的名称“WinSta0”,其它所有的窗口站是不可交互的,因此不可以显示用户桌面或者接收用户输入。
当一个用户使用远程桌面服务登陆了一个计算机,系统将为用户创建一个登陆会话。每一个会话将有一个和它绑定了的交互式窗口站“WinSta0”。
*远程桌面会话
当一个用户登陆到一个远程登陆服务开启的计算机上的时候,系统为该用户创建一个会话。每一个会话用一个唯一的会话SID 标志。因为每一次登陆到远程桌面连接(RDC– Remote Desktop Connection )客户端时都接收到一个单独的会话ID,因此每个用户体验类似于同时登陆到多台计算机上,例如,办公室计算机和家庭计算机。
每一个远程桌面会话绑定一个交互式窗口站。交互式窗口站的名字是唯一的—“WinSta0”,因此每个会话有其自己的“WinSta0”窗口站。每一个窗口站有三个标准的桌面:WinLogon 桌面,桌面保护程序桌面和交互式桌面。
一个会话的交互式窗口站所绑定的用户就是我们通常所说的交互用户。在一个RDC 客户端上,除了当前远程桌面服务控制台上的交互式用户外,还可能有很多个交互式用户。调用WTSGetActiveConsoleSessionId 函数可以得到当前控制台上的会话的SID。
当一个用户从RDC 客户端退出的时候,该远程会话主机服务上与该用户绑定的会话被删除,与该会话绑定的窗口栈和桌面也被清除。因为远程桌面服务控制台会话是永远不会被删除的,该控制台会话绑定的窗口站也不被删除。当应用程序配置为在交互式用户的安全环境中运行的时候(我们所知道的“Run As 交互式用户”对象激活模型),这将影响应用程序在远程桌面服务环境中的行为。
窗口站安全和访问权限
桌面安全和访问权限
- 深入理解Windows 操作系统中关于中断服务和多会话的描述
终端服务指的是在单个系统中,Windows 对于多个可交互用户会话的支持。利用Windows 的终端服务,一个远程用户可以在另一台机器上建立一个会话,并登录进去,在该服务器上运行应用程序。服务器把图形用户界面(以及其他可配置的资源,比如音频和剪贴板)传送到客户机,客户机把用户的输入传回服务器。(与X 窗口系统类似,Windows 允许在一个服务器系统上运行单独的应用程序,其显示部分远程传送到客户机,而非将整个桌面远程到客户机)。
第一个会话被认为是服务会话,或者零号会话,它包含了宿纳系统服务的进程。在机器的物理控制台上的第一个登录会话为一号会话,而其他的会话可以通过远程桌面连接程序(Mstsc.exe)来建立,或者通过使用快速用户切换来建立。
一个可以使用本地方式或者远程方式使用Windows 客户机系统,但不能同时以这两种方式来使用该系统)。- 会话管理器(Smss.exe)
会话管理器是系统中创建的第一个用户模式进程。这一个进程由服务完成执行体和内核初始化工作最后阶段的内核模式系统线程创建。
Smss 启动的时候,检查自己是第一个实例,还是主Smss 为了创建会话而启动起来的一个实例(如果存在命令行参数)。通过在引导过程中以及在终端服务会话的创建过程中创建多个多个Smss 实例,Smss 可以同时创建多个会话。一旦一个会话完成了初始化,该会话的Smss 副本便会终止。只有初始的Smss.exe 进程仍然是活动的。
注册表中需要用来驱动Smss 初始化的配置信息都在HKLM\SYSTEM\CurrentControlSet\Control\Session Manager 下。- 主Smss 执行下面的一次性初始化步骤。
- 将该进程和初始线程标记为“关键的”,关键线程或进程退出将导致系统崩溃。
- 进程优先级提升为11
- 如果系统支持动态增加热处理器,则允许自动更新处理器亲和性,这样,如果新的处理器被加入,新的会话将可以利用这些新加入的处理器。
- 创建相应的命名管道和邮件槽,用于Smss,Csrss,Lsm 之间的通信。
- 创建ALPC 端口接收命令。
- 根据注册表..\Environment设置系统范围的环境变量。
- 根据注册表中..\DOS Devices的定义,在对象管理器名字空间的\Global?? 目录下为该注册表键中定义的设备创建符号链接。
- 在对象管理器名字空间中创建\Sessions 根目录。
- 运行注册表..\BootExecute 中的进程,默认是Autochk.exe ,执行磁盘检查。
- 根据..\PendingFileRenameOperations 中指定的信息,处理尚未完成的文件改名操作。
- 初始化页面文件(paging file)
- 初始化注册表的其它部分(HKLM Software、SAM和Security 储巢(hive)。
- 运行..\SetupExecute 中的程序
- 打开已知DLL (..\Known DLLs),将它们映射为永久内存区(映射文件)。
- 创建一个线程来响应会话创建请求。
- 创建Smss 来初始化会话0(非交互会话)
- 创建Smss 来初始化会话1(交互会话)
这些操作完成后,Smss 将在会话0的Csrss.exe 实例的句柄上等待。会话启动的Smss 实例完成以下事项:
- 调用NtSetSystemInformation 请求建立起内核模式的会话数据结构—>调用内部的内存管理器函数MmSessionCreate,它建立起会话虚拟地址空间,其中包含该会话的换页内存池,以及由Win32k.sys 和其它的会话空间设备驱动程序所分配的属于每个会话的数据结构。
- 为该会话创建子系统进程(默认Csrss.exe)
- 创建Winlogon 实例(对于交互会话)或者Wininit实例(对于会话0)
然后这一中间Smss 进程退出(留下子系统进程和Winlogon 或 Wininit 成为无父进程)。Windows 初始化进程(Wininit.exe)
- 将自己标记为“关键的”
- 初始化用户模式调度设施
- 创建$windir%\temp 文件夹
- 创建一个窗口站(Winsta0)和两个桌面(Winlogon 和 Default),以便会话0 中的进程可以在其中运行。
- 创建Services.exe(服务控制管理器,SCM)
- 启动Lsass.exe(本地安全认证子系统服务器)
- 启动Lsm.exe (本地会话管理器)
- 一直等待,直到系统停机
- 本地会话管理器(Lsm.exe)
Lsm.exe 管理本地机器上的终端服务器会话的状态。它通过ALPC 断奶口SmSsWinStationApiPort 向Smss 发送请求启动新的会话,比如当用户在资源管理器中选择“切换用户”时,Lsm 也跟Winlogon 和 Csrss 进行通信(通过一个本地系统RPC)。它通知Csrss 诸如建立连接、断开连接、终止等时间,也广播系统消息。对于以下的事件,它接收Winlogon 的通知:
- 登录和注销
- Shell 启动和终止
- 连接到一个会话。
- 与一个会话断开连接
- 锁住或解锁桌面。
- Winlogon 、LogonUI 和 Userinit
Windows 登录进程(Winlogon.exe)处理交互式用户的登陆和注销。当SAS 组合键(Ctrl+Alt+Delete)被按下,Winlogon 接收到一个用户登录请求。登录过程的身份识别和认证是通过一种称为凭证提供者的DLL来实现的。标准的Windows 凭证提供者实现了默认的Windows 认证接口:口令和智能卡,但是开发人员可以开发自己的凭证提供者来实现其它的身份识别和认证机制(如声波,指纹等)。凭证提供者和显示登录对话框的UI 都运行在Winlogon 的一个子进程中,称为LogonUI,当Winlogon 检测到SAS 时,启动这个进程,该进程会初始化凭证提供者。一旦用户输入了凭证,或者取消了登录界面,LogonUI 进程就终止。
获得用户名和口令后,送到本地安全认证服务器进程(Lsass.exe)进行认证,认证成功后,LSASS 调用安全引用监视器中的一个函数,生成一个访问令牌对象。然后Winlogon 利用此令牌创建该用户会话中的初始进程(默认Userinit.exe)。Userinit 执行用户环境的一些初始化工作(比如运行登录脚本、应用组策略),然后在注册表中查找Shell 值,并创建一个进程来运行系统定义的shell(默认Explorer.exe)。然后,Userinit 退出(explorer 进程无父进程)。
Winlogon 不仅在用户登录和注销的时候是活动的,截取到键盘的SAS 就是活动的。如果你在登录之后按下了SAS ,Windows 安全屏幕会出现,提示注销、启动任务管理器、锁定工作站、关闭系统等选线。Winlogon 和 LogonUI 是负责处理这一交互过程的进程。
除了两个地方Smss 进程和其它的任何用户进程都一样。首先,Windows 认为Smss 是一个可信任的操作系统进程。第二,Smss 是一个native 应用程序。因为它是一个受信任的进程,它可以执行绝大多数其它进程不能执行的操作,比如创建安全令牌。因为它是一个native 应用程序,Smss 不调用Windows API(在Smss 启动时候Csrss 尚未启动,而且是Smss 创建的Csrss进程),它仅仅调用大家已经知道的称为windows native API 的核心执行体API。
窗口站和桌面创建
系统自动创建交互式窗口站。当一个交互式用户登陆,系统将用户登陆会话和交互式窗口站绑定起来。系统为交互式窗口站创建默认的输入桌面(WinSta0\default)。登录用户启动的进程被绑定到Winsta0\default 桌面。
一个进程可以调用CreateWindowStation 函数来创建一个新的窗口站,调用CreateDesktop 或者 CreateDesktopEx 函数来创建一个新的桌面。系统桌面堆的数量限制了我们所能创建的桌面的数量。更多信息请参见CreateDesktop 函数。
当一个非交互进程比如服务应用程序尝试连接到一个窗口站,而进程登录会话没有窗口站,系统将尝试为会话创建一个窗口站和桌面。被创建的窗口站的名字是基于登录会话SID 的,而桌面的名字是默认的,正如下面两点描述的一样:
1. 如果一个服务运行在本地系统账户的安全上下文但是没有包含SERVICE_INTERACTIVE_PROCESS 属性,它使用下面的窗口站和桌面:Service-0x0-3e7$\default。这个窗口是不可交互的,因此服务不能显示用户交互信息。另外,服务创建的进程不能显示用户交互信息。
2. 如果一个服务运行在一个用户账户的安全上下文中,窗口站的名称是基于用户SID Service-0xZ1-Z2$,Z1 是登录SID 的高部分,Z2 是登录SID 的低部分。因为一个SID 对于登录会话来说是唯一的,两个运行在同样的安全环境中的服务接收独一无二的窗口站。这些窗口站不可交互。
对于服务的用户账户来说,窗口站和桌面的DACL 包含以下的访问权限:
Window Station
WINSTA_ACCESSCLIPBOARD
WINSTA_ACCESSGLOBALATOMS
WINSTA_CREATEDESKTOP
WINSTA_EXITWINDOWS
WINSTA_READATTRIBUTES
STANDARD_RIGHTS_REQUIRED
Desktop
DESKTOP_CREATEMENU
DESKTOP_CREATEWINDOW
DESKTOP_ENUMERATE
DESKTOP_HOOKCONTROL
DESKTOP_READOBJECTS
DESKTOP_WRITEOBJECTS
STANDARD_RIGHTS_REQUIRED
进程连接到一个窗口站
当一个进程第一次调用USER32 或者 GDI32 函数函数(除了窗口站和桌面函数)的时候,它将与一个窗口站建立连接关系。系统根据下面的规则决定将与进程建立连接的窗口站。
1.如果进程调用SetProcessWindowStation 函数,它将连接该函数指定的窗口站。
2.如果进程没有调用SetProcessWindowStation 函数,继承其父进程所连接的窗口站。
3.如果上述两个方法没有得到其窗口站,系统尝试以MAXIMUM_ALLOWED 访问权限来访问并连接下面列举的窗口站中中的每一个,直到连接上:
1. 如果创建进程的时候STARTINFO 结构中的lpDesktop 成员指定了一个窗口站名称,进程将尝试连接指定的窗口站。
2. 否则, 如果进程运行在交互用户的登录会话中的话,进程连接到这个交互式窗口站。
3. 如果进程运行在一个非交互式登录会话中,将基于登录会话ID 来构建窗口站名字,并尝试以这个名字来打开窗口站。如果因为窗口站不存在而打不开窗口站的话,系统尝试创建该窗口站和一个默认的桌面。
在这个连接过程中,进程不能通过调用CloseWindowStation 函数来关闭这个被绑定的窗口站。
当一个进程正在连接到一个窗口站的时候,系统在进程的句柄表中搜索可继承的句柄表。系统使用它所找到的第一个窗口站句柄。如果你想让子进程继承特定的窗口站句柄,必须确保该句柄是唯一一个可继承的句柄。如果一个子进程继承了多个窗口站句柄,被连接的窗口站是不确定的。
将进程连接到窗口站时系统打开的窗口的句柄是不可继承的。
连接线程到桌面
在一个进程连接到一个窗口站的时候,系统绑定一个桌面到这个建立连接的线程。系统按照下面的规则来决定线程将要绑定的桌面。
1.如果线程调用SetThreadDesktop函数,线程将连接到函数指定的桌面。
2.如果线程没有调用SetThreadDesktop 函数,它连接到从其父进程继承的桌面。
3.如果上面的两个都没有绑定桌面,系统尝试按照下面的顺序以MAXIMUM_ALLOWED 访问权限来打开桌面。
1. 如果在创建进程的时候在STARTUPINFO 的lpDesktop 成员指定了一个特定的桌面名称, 线程将连接这个特定的桌面。
2. 否则,线程连接进程连接的窗口站中的默认桌面。
在这个连接期间,进程不能通过CloseDesktop 函数来关闭被绑定的desktop。
当一个进程在连接一个桌面,系统搜索进程的句柄表中的可继承句柄。系统使用它所找到的第一个桌面句柄。如果你想一个子进程来连接一个特定的可进程的桌面,必须确保该句柄是唯一可继承的桌面句柄。如果一个子进程继承了多个可进程的桌面句柄,桌面连接的结果是不确定的。
系统在连接一个进程到一个桌面的时候打开的句柄是不可继承的。
桌面
一个桌面有一个逻辑显示器并包含诸如窗口,菜单和hook 等用户接口对象。他可以用来创建和管理窗口。每一个桌面对象都是可保安全的。当创建一个桌面对象的时候,它被绑定到调用进程的当前窗口站上,并被绑定到当前线程上。
窗口消息只能在同一个桌面的不同进程之间进行传递。另外,一个进程的hook 函数只能接收来自同一个桌面内创建的窗口的特定消息。
一个交互式窗口站(WinSta0)可以有多个桌面,以用来显示用户接口并接收用户输入,但是同一时间只能有一个桌面是活动的,这个活动的桌面就是我们通常所说的“输入桌面”。应用程序可以调用OpenInputDesktop 函数来得到“输入桌面”的句柄。如果拥有相应的权限,应用程序
可以调用SwitchDesktop 函数来切换“输入桌面”为其它的桌面。
默认情况下,一个交互式窗口站中有三个桌面:默认,屏幕保护,Winlogon。
默认桌面是Winlogon 以一个已经登录的用户的身份启动初始进程的时候创建的,这时候,默认桌面开始活动,并用来与用户进行交互。
每当一个安全的屏幕保护程序活动的时候,系统自动转换到屏幕保护桌面,该桌面禁止没有认证的用户访问默认桌面的进程。不安全的桌面保护桌面运行在Winsta0\Default。