Windows 提供了以下三种主要类别的对象:图形用户界面(GUI)、图形设备接口 (GDI) 和内核(Kernel)。 内核对象 是安全的,但 GUI对象 和 GDI 对象 并不安全。 因此,为了提供额外的安全性,将使用窗口工作站和桌面管理用户界面对象,这些对象本身就是安全对象。
窗口站(Window Station,停放窗口的站) 是与进程关联的安全对象,包含剪贴板、ATOM 表(原子表)以及一个或多个桌面对象。
桌面 是包含在窗口站内的安全对象。 桌面具有逻辑显示界面,并包含用户界面对象(如窗口、菜单和挂钩)。
窗口站窗口站 包含剪贴板、ATOM表以及一个或多个 桌面对象。 每个窗口站对象都是一个安全对象。 创建窗口站时,它与调用进程相关联,并分配给当前会话。
交互式窗口工作站 是可以显示用户界面或接收用户输入的唯一窗口站。 它被分配给交互式用户的登录会话,包含键盘、鼠标和显示设备。 它始终命名为 "WinSta0"。 所有其他窗口工作站都是非交互式的,这意味着它们不能显示用户界面或接收用户输入。
当用户使用远程桌面服务登录到计算机时,将为该用户启动一个会话。 每个会话都与其自己的交互式窗口工作站(名为 "WinSta0")相关联。
桌面桌面 具有逻辑显示界面,并包含用户界面对象(如窗口、菜单和挂钩);它可用于创建和管理窗体。 每个桌面对象都是一个安全对象。 创建桌面时,它与调用进程的当前窗口站相关联,并分配给调用线程。
只能在同一桌面上的进程之间发送窗口消息。 此外,在特定桌面上运行的进程的挂钩过程只能接收用于在同一桌面中创建的 windows 的消息。
与交互式窗口工作站(Winsta0)关联的桌面可用于显示用户界面和接收用户输入,但一次只能激活其中的一个桌面。 此活动桌面(也称为输入桌面)是当前对用户可见并且接收用户输入的一种。 应用程序可以使用 OpenInputDesktop 函数获取输入桌面的句柄。 具有所需访问权限的应用程序可以使用 SwitchDesktop 函数来指定其他输入桌面。
默认情况下,交互窗口工作站有三个桌面:默认、屏幕保护程序和 Winlogon。
当 Winlogon 启动初始进程作为已登录用户时,将创建默认桌面。 此时,默认桌面将变为活动状态,并用于与用户交互。
每当激活安全屏幕保护程序时,系统会自动切换到屏幕保护程序桌面,这将保护默认桌面上未经授权的用户的进程。 默认情况下,不安全的屏幕保护程序在 Winsta0\Default 上运行 。
当用户登录时,Winlogon 桌面处于活动状态。 当 shell 指示它已准备好显示某些内容或30秒后(以先达到的条件为准)时,系统会切换到默认桌面。 用户会话期间,当用户按下 CTRL + ALT + DEL 键序列时,或者当 "用户帐户控制 (UAC) " 对话框处于打开状态时,系统将切换到 Winlogon 桌面。
Windows Server 2003 和 WINDOWS XP/2000: 不支持 UAC 对话框。
Winlogon 桌面的安全描述符允许访问一组非常有限的帐户,包括 LocalSystem 帐户。 应用程序通常不会在其令牌中携带这些帐户的任何 Sid,因此在 Winlogon 桌面处于活动状态时无法访问 Winlogon 桌面或切换到其他桌面。
桌面工作站和桌面创建系统会自动创建交互窗口站。 当交互式用户登录时,系统会将交互式窗口工作站与用户登录会话相关联。 系统还会为交互式窗口工作站创建默认的输入桌面 (Winsta0\default) 。 已登录用户启动的进程与 Winsta0\default桌面关联。
进程可以使用 CreateWindowStation 函数来创建新的窗口站,并使用 CreateDesktop 或 CreateDesktopEx 函数创建新桌面。 可创建的桌面数受系统桌面堆的大小限制。 有关详细信息,请参阅 CreateDesktop。
当非交互式进程(如服务应用程序)尝试连接到窗口站并且进程登录会话不存在窗口站时,系统将尝试为会话创建窗口站和桌面。 创建的窗口站的名称基于登录会话标识符,桌面命名为默认值,如下所述:
- 如果服务在 LocalSystem 帐户的安全上下文中运行,但不包含SERVICE_INTERACTIVE_PROCESS属性,则使用以下窗口和桌面: Service-0x0-3e7$\default。 此窗口不是交互式的,因此服务不能显示用户界面。 此外,由服务创建的进程无法显示用户界面。
- 如果服务在用户帐户的安全上下文中运行,则窗口工作站的名称基于用户 SID Service-0xZ1-Z2$,其中 Z1 是登录 sid 的高部分, Z2 是登录 sid 的低部分。 由于 SID 对登录会话是唯一的,因此在同一安全上下文中运行的两个服务会接收到唯一的窗口站。 这些窗口工作站不是交互式的。
Windows 工作站和桌面的 "自由访问控制列表 (" DACL) 包含服务的用户帐户的以下访问权限:
窗口工作站:
WINSTA_ACCESSCLIPBOARD WINSTA_ACCESSGLOBALATOMS WINSTA_CREATEDESKTOP WINSTA_EXITWINDOWS WINSTA_READATTRIBUTES STANDARD_RIGHTS_REQUIRED
桌面设备:
DESKTOP_CREATEMENU DESKTOP_CREATEWINDOW DESKTOP_ENUMERATE DESKTOP_HOOKCONTROL DESKTOP_READOBJECTS DESKTOP_WRITEOBJECTS STANDARD_RIGHTS_REQUIRED
到窗口站的进程连接当进程第一次调用 USER32 或 GDI32 函数(窗口站和桌面函数除外)时,它会自动建立到窗口站和桌面的连接。系统根据以下规则确定进程连接的窗口站:
- 如果进程调用了SetProcessWindowStation函数,它将连接到该调用中指定的窗口站。
- 如果进程没有调用SetProcessWindowStation,它将连接到从父进程继承的窗口站。
- 如果进程没有调用SetProcessWindowStation并且没有继承窗口站,系统将尝试打开 MAXIMUM_ALLOWED 访问并连接到窗口站,如下所示:
- 如果在创建进程时使用的STARTUPINFO结构的lpDesktop成员中指定了窗口站名称,则该进程将连接到指定的窗口站。
- 否则,如果进程在交互式用户的登录会话中运行,则该进程连接到交互式窗口站。
- 如果进程在非交互式登录会话中运行,则窗口站名称将根据登录会话标识符形成,并尝试打开该窗口站。如果由于该窗口站不存在而导致打开操作失败,系统会尝试创建该窗口站和默认桌面。
在此连接过程中分配的窗口站不能通过调用CloseWindowStation函数来关闭。
当进程连接到窗口站时,系统会在进程的句柄表中搜索继承的句柄。系统使用它找到的第一个窗口站句柄。如果您希望子进程连接到特定的继承窗口站,您必须确保只有所需的句柄被标记为可继承。如果子进程继承了多个窗口站句柄,则窗口站连接的结果是未定义的。
系统在将进程连接到窗口站时打开的窗口站的句柄是不可继承的。
到桌面的线程连接进程连接到窗口站后,系统会为进行连接的线程分配一个桌面。系统根据以下规则确定要分配给线程的桌面:
- 如果线程调用了SetThreadDesktop函数,它会连接到指定的桌面。
- 如果线程没有调用SetThreadDesktop,它将连接到从父进程继承的桌面。
- 如果线程没有调用SetThreadDesktop并且没有继承桌面,系统会尝试打开 MAXIMUM_ALLOWED 访问并连接到桌面,如下所示:
- 如果在创建进程时使用的STARTUPINFO结构的lpDesktop成员中指定了桌面名称,则线程连接到指定的桌面。
- 否则,线程连接到进程连接到的窗口站的默认桌面。
在此连接过程中分配的桌面无法通过调用CloseDesktop函数关闭。
当进程连接到桌面时,系统会在进程的句柄表中搜索继承的句柄。系统使用它找到的第一个桌面句柄。如果您希望子进程连接到特定的继承桌面,您必须确保只有所需的句柄被标记为可继承。如果子进程继承了多个桌面句柄,则桌面连接的结果是不确定的。
系统在将进程连接到桌面时打开的桌面句柄是不可继承的。
窗口站安全与访问权限安全性使您能够控制对窗口站对象的访问。有关安全性的更多信息,请参阅访问控制模型。
您可以在调用CreateWindowStation函数时为窗口站对象指定安全描述符。如果您指定 NULL,则窗口站将获得一个默认的安全描述符。窗口站的默认安全描述符中的 ACL 来自创建者的主要令牌或模拟令牌。
要获取或设置窗口站对象的安全描述符,请调用GetSecurityInfo和SetSecurityInfo函数。
当您调用OpenWindowStation函数时,系统会根据对象的安全描述符检查请求的访问权限。
窗口站对象的有效访问权限包括标准访问权限和一些特定于对象的访问权限。
下表列出了所有对象使用的标准访问权限。
下表列出了特定于对象的访问权限。
以下是交互式窗口站对象的通用访问权限,该对象是分配给交互式用户登录会话的窗口站。
STANDARD_RIGHTS_READ WINSTA_ENUMDESKTOPS WINSTA_ENUMERATE WINSTA_READATTRIBUTES WINSTA_READSCREEN
GENERIC_WRITESTANDARD_RIGHTS_WRITE WINSTA_ACCESSCLIPBOARD WINSTA_CREATEDESKTOP WINSTA_WRITEATTRIBUTES
GENERIC_EXECUTESTANDARD_RIGHTS_EXECUTE WINSTA_ACCESSGLOBALATOMS WINSTA_EXITWINDOWS
GENERIC_ALLSTANDARD_RIGHTS_REQUIRED WINSTA_ACCESSCLIPBOARD WINSTA_ACCESSGLOBALATOMS WINSTA_CREATEDESKTOP WINSTA_ENUMDESKTOPS WINSTA_ENUMERATE WINSTA_EXITWINDOWS WINSTA_READATTRIBUTES WINSTA_READSCREEN WINSTA_WRITEATTRIBUTES
以下是非交互式窗口站对象的通用访问权限。系统将非交互式窗口站分配给交互式用户以外的所有登录会话。
STANDARD_RIGHTS_READ WINSTA_ENUMDESKTOPS WINSTA_ENUMERATE WINSTA_READATTRIBUTES
GENERIC_WRITESTANDARD_RIGHTS_WRITE WINSTA_ACCESSCLIPBOARD WINSTA_CREATEDESKTOP
GENERIC_EXECUTESTANDARD_RIGHTS_EXECUTE WINSTA_ACCESSGLOBALATOMS WINSTA_EXITWINDOWS
GENERIC_ALLSTANDARD_RIGHTS_REQUIRED WINSTA_ACCESSCLIPBOARD WINSTA_ACCESSGLOBALATOMS WINSTA_CREATEDESKTOP WINSTA_ENUMDESKTOPS WINSTA_ENUMERATE WINSTA_EXITWINDOWS WINSTA_READATTRIBUTES
如果要读取或写入对象的 SACL,可以请求对窗口站对象的 ACCESS_SYSTEM_SECURITY 访问权限。有关详细信息,请参阅访问控制列表 (ACL)和SACL 访问权限。
桌面安全和访问权限安全性使您能够控制对桌面对象的访问。有关安全性的更多信息,请参阅访问控制模型。
您可以在调用CreateDesktop或CreateDesktopEx函数时为桌面对象指定安全描述符。如果指定 NULL,桌面将获得默认安全描述符。桌面的默认安全描述符中的 ACL 来自其父窗口站。
要获取或设置窗口站对象的安全描述符,请调用GetSecurityInfo和SetSecurityInfo函数。
当您调用OpenDesktop或OpenInputDesktop函数时,系统会根据对象的安全描述符检查请求的访问权限。
桌面对象的有效访问权限包括标准访问权限和一些特定于对象的访问权限。
下表列出了所有对象使用的标准访问权限。
下表列出了特定于对象的访问权限。
以下是包含在用户登录会话的交互式窗口站中的桌面对象的通用访问权限。
DESKTOP_ENUMERATE DESKTOP_READOBJECTS STANDARD_RIGHTS_READ
GENERIC_WRITEDESKTOP_CREATEMENU DESKTOP_CREATEWINDOW DESKTOP_HOOKCONTROL DESKTOP_JOURNALPLAYBACK DESKTOP_JOURNALRECORD DESKTOP_WRITEOBJECTS STANDARD_RIGHTS_WRITE
GENERIC_EXECUTEDESKTOP_SWITCHDESKTOP STANDARD_RIGHTS_EXECUTE
GENERIC_ALLDESKTOP_CREATEMENU DESKTOP_CREATEWINDOW DESKTOP_ENUMERATE DESKTOP_HOOKCONTROL DESKTOP_JOURNALPLAYBACK DESKTOP_JOURNALRECORD DESKTOP_READOBJECTS DESKTOP_SWITCHDESKTOP DESKTOP_WRITEOBJECTS STANDARD_RIGHTS_REQUIRED
如果您想读取或写入对象的 SACL,您可以请求桌面对象的 ACCESS_SYSTEM_SECURITY 访问权限。有关详细信息,请参阅访问控制列表 (ACL)和SACL 访问权限。