过期罐头电脑论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 5202|回复: 0
收起左侧

Window Stations 窗口站

[复制链接]
Window stations 和桌面可能是Windows NT服务中最与众不同的了。绝大多数编程者都不会直接接触这两种对象,虽然 用户每时每刻都要碰到它们。window station 和桌面对象就象其它Windows NT对象,如事情 、互斥量和信号量一样,是安全(securable)的。一个window station 对象包括一个剪贴板、一个全局原子集和更多的桌面对象。一个window station或者是可见的或者是不可见的。一个可见的window station接纳 用户来自于鼠标或键盘的输入。一个显示设备也与之相连这样信息可以显示给交互式用户。
在 Windows NT 4.0中,只有一个window station 能被看得到,就是WinSta0。可见的window station也被定义成交互式的。一个不可见的window station是不可交互的,而且也不能接纳 任何用户的输入也没有显示设备与之相连。
如前所述,桌面包含在window station对象中。一个桌面对象包含一个逻辑的显示外表 ,和窗口、菜单等。只有属于可见window station的桌面才能被看见并接纳 用户的输入。这个桌面叫做活动桌面。
作为交互式用户你在不同的时候碰到三种不同的桌面:缺省(Default)、 Winlogon和Screen-saver。Winlogon 桌面是当你按下Ctrl+Alt+Delete组合键时显示在你面前的对话框。缺省(Default)桌面是浏览器(Explorer)或者是由交互式用户启动的一切 进程。它更应当被了解 成交互式的应用程序桌面。最终的桌面是Screen-saver,它显示你的屏幕saver。你可能已经注意到可以在不同的桌面之间切换。当一个用户按下Ctrl+Alt+Delete组合键时,操作系统可以从缺省状态切换到Winlogon桌面。当你在登录对话框当选 择取消,系统将再切换回缺省桌面。有人问我当切换进行的时候,是否其它桌面上的东西都被毁坏 掉了,答案是 "不"。虽然你看不到其它桌面,但它们依然 在那里。
系统中一切 的进程都与window station 和桌面相联络 。当一个用户第一次登录时,交互式window station, WinSta0,和缺省桌面都与这个用户的Shell进程相关联。这样用户就能看到shell了,假如 不是这样,用户是什么也看不到的。而且在这之后,由shell启动的一切 进程也会和WinSta0 及缺省桌面相关联。
你还可以通过STARTUPINFO 数据构造 的lpDesktop 成员指定你的进程同哪个window station 和桌面相关联。这个数据构造 传送 给CreateProcess 和 CreateProcessAsUser两个函数。你可以将lpDesktop 初始化为NULL,意义 是让CreateProcess函数使用和调用进程相同的window station 和桌面。你可以将你自己. 的window station 和桌面组合定义成"WinSta0Default" 或者就定义成空字符串。这个参数会让操作系统为启动进程创建一个新的不可见的window station 及桌面。与这两个新对象关联的安全性授予每个组对它们的完全访问权限。
typedef struct _STARTUPINFO { // si
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
Window stations和桌面是具有安全性的对象。与window station 和桌面将关联的进程必须由对这些对象的合适的访问权限。假如 进程没有访问权,你会看到这两个音讯 之一"User32.dll initialization failure(User32.dll初始化失败)" 或 "Kernel32.dll initialization failure.(Kernel32.dll初始化失败)"。由进程返回的退出码为128 或 ERROR_NO_WAIT_CHILDREN。那么我所指的合适的访问权是什么意义 呢?假设 你有一个文件这样的对象。你可以为这个文件创建一个DACL以使用户具有对这个文件的读访问权。Window station 和 桌面是以相同的方式工作的。
对于一个桌面对象的一个访问权限叫做DESKTOP_CREATEWINDOW。假如 用户没有被授予这个访问权限,任何由这个用户启动的进程都不能创建窗口。不幸的是, 象CreateWindow 这样的USER APIs 在发作 同CreateFile 或 CreateMutex API类似的安全问题时,不会返回 "Access Denied(访问被回绝 )" 音讯 。User32.dll 中的Windows 应用程序将会被终止,导致DLL初始化错误的音讯 。Kernel32.dll 初始化过程是在创建一个控制板窗口时发作 的。一个例程在没有对window station和桌面的合适的访问权限的时候启动cmd.exe。但是 不幸的是, CreateProcess 没有任何机制来检查这个错误。当用户不具有对window station和桌面的合适访问权限时,它并不返回一个错误信息。CreateProcess将会启动这个应用程序,然后这个应用程序自身 在DLL失败后终止。
编程人员还可以有一种方法越过"User32.dll initialization failure(User32.dll初始化失败"音讯 。系统有一个堆用来为window station分配内存。内存是有限的。缺省设置允许创建七个或八个window station对象。假如 你用光了一切 的内存,你就会看到这个音讯 。不过,值得庆幸的是,有一个注册表关键字可以用来增加这个设置。 (参见Knowledge Base article Q142676)
假如 你没在开发服务而只是普通的应用程序,Window stations 和桌面就不是真正的问题。你的应用程序只同交互式桌面WinSta0Default 相关联。假如 你是在开发一个服务,那么它可能就会同下面的window station 及桌面组合关联:
WinSta0Default
Service-0x0-3e7$Default
Service Account's Logon SIDDefault
WinSta0Default 同运行在LocalSystem帐户的,并且与桌面交互的服务关联 。 (在ServiceType必须指明SERVICE_INTERACTIVE_PROCESS标志)。假如 服务不同桌面交互,那么它是与Service-0x0-3e7$Default相关联的。这是个不可见的window station。你一定很疑惑这乌七八糟 的0x0-3e7$ 是什么,它是服务的登录SID 。登录SID是无独有偶 的。它指的是用户所属的组。系统中的一切 用户都会有一个登录SID。

有一个有趣的现象是虽然 你为同一个服务帐户配置了两个服务,但由于它们的登录SID是不同的,所以每个都将有一个无独有偶 的window station 及桌面。用户的SID是相同的但是由于它们运行在不同的服务帐户登录段中所以它们每一个都有无独有偶 的登录段。对于交互式服务和非交互式的LocalSystem 服务,状况 就不同了,由于 它们既同WinSta0关联又同Service-0x0-3e7$关联。
为什么知道哪个window station和桌面与服务相关联是如此的重要呢?第一,交互性。假如 你的服务没有和WinSta0Default相关联,它就不能以缺省状态把任何USER对象展现 给用户。这意味着你不能显示一个窗口或者是取得 用户的输入。你可以为一个非交互式的服务显示一个MessageBox 。关键字标志的类型是MB_SERVICE_NOTIFICATION 和 MB_DEFAULT_DESKTOP。你不能用它来发送音讯 。这个动作与你的进程相关联的桌面有关系。假如 你不为进程重新分配正确的window station 及桌面,你就一直 不能做这件事。
另外两种基于服务帐号的登录SID的window station 和桌面组合是不可见的。正如我刚刚提到的,与一个不可见window station相关联的桌面永远不能显示或接纳 来自交互式用户的输入信息(除非MessageBox使用两个特殊的标志)。你依然 可以创建USER对象-但是用户永远不会看到它们。很多服务的开发者们经常要犯的一个错误是显示一个对话框提示用户输入信息。当服务被测试时,开发者会注意到服务被挂起了。这就是由于 服务同一个不可见的window station相关联。操作系统是成功地创建了对话框。问题是用户看不到它。
所以你应当怎么 才能使你的服务能显示并取得 从用户那来的信息呢?首先为用户写一个启动的客户应用程序。客户应用程序将实现显示及从用户处取得 信息的功能,然后使用进程间通讯 机制把信息发回给服务。这样做的最大益处 是你不用 再为window stations及桌面操心。一个缺陷 就是需要. 用户做一些事情来启动你的客户应用程序。
另外一个方法要求你为LocalSystem帐户配置你的服务,要将服务类型说明为SERVICE_INTERACTIVE_PROCESS。这将把你的服务与正确的window station及桌面相关联。独一 的问题就是服务将不能通过NTLM进行任何的网络访问。有两种方法 可以解决。第一种方法 是,NULL 段访问可以在服务器端通过注册表调整。假如 服务开发者有对服务器的合适的安全访问权限,注册表的关键字将会改动 ,允许对LocalSystem 进程的访问。
另一个解决的方法 是扮演一个已经访问过NTLM 安全网络资源的用户。一个问题是服务必须知道用户的口令以通过LogonUser API生成用户的标志。为什么用户不能为服务帐户配置一个服务,那样就只须重新为服务分配交互式的window station 及桌面就可以了?答案只有一个,就是安全。对交互式window station 及桌面具有完全访问权限的独一 用户是LocalSystem帐户和交互式用户(假如 有的话)。我特别指出完全访问权限的原因是属于本地管理员组的用户对交互式window station 及桌面具有 部分访问权限。有一部分USER API 调用可能会由于安全的原因无法运行。
最好的赌注是冒点风险使用本地管理员帐户。交互式用户的访问权限是基于组的登录SID 而不是单个用户的SID。这意味着你可能有一个与交互式用户相同帐户的服务但是组的登录SID是不同的。允许一个为服务帐户配置的服务具有对交互式window station及桌面访问的独一 条件是为交互式用户更改安全性以允许服务访问。
现在你有了一个为交互式window station 及桌面配置的服务,你还会碰上什么样的问题呢?第一个要考虑的问题就是当用户退出时将会发作 什么。假如 服务是交互式的,那么是否缺省桌面被毁坏 了呢?不,缺省桌面依然 存在。独一 的区别是Winlogon 桌面现在是活动桌面。当第二个用户登录系统时,系统将会切换回缺省桌面。用户显示的任何事物都可以被交互式用户看到。
交互式服务和由交互式用户启动的进程之间的区别是,当没有用户登录时,服务依然 可以运行。这就导致了一些有趣的问题。例如,基于安全的原因,当交互式用户退出系统后,操作系统竟全局原子表清为0。假如 一个交互式服务依赖于存储在全局原子表中的信息,那么当这个交互式用户退出后,信息全部消失。另一个例子是自启动交互式服务。第一个用户登录之前缺省桌面还没有创建。这意味着在用户登录之前试图显示信息的交互式服务一定会出问题。
我想讨论的最后一件事是交互式服务是暴露给交互式用户的,这个交互式用户可以通过任务管理器杀死服务。假如 你有一个运行在LocalSystem 帐户上的服务,则交互式用户将不具备必须的安全性来杀死你的进程。假定 你进入任务管理器列出一切 的进程,假如 你点击了End Process(终止进程)按纽来终止运行在LocalSystem帐户上的进程时,你将会得到预料 之中的 "Access is denied(访问被回绝 )" 音讯 框。但是假如 这个服务有一个显示在外层的窗口,你可以在任务管理器中列出一切 应用程序。当你点击End Task(终止任务)按纽,你就可以通过这个暴露的窗口杀死这个服务。避免这种状况 发作 的一种方法就是让你的窗口不要显示在应用程序标签中。创建一个隐藏的窗口,然后将可见的窗口作为这个隐藏窗口的儿子窗口。
记住,最后的手段才是将你的服务交互化。最好的选择是创建一个交互式的客户应用程序。
注册表"蜂箱"
"蜂箱"是操作系统用来存储用户注册信息的。在注册表中存储的注册信息包括桌面、应用程序、打印和网络设置。系统将用户的注册信息备份在一个象蜂箱一样的文件中。Windows NT的每个用户都分配一个蜂箱。这个蜂箱能放在本地的或远程的服务器上。当一个用户登录到Windows NT机器上时,系统把用户的蜂箱装载到注册表中,在HKEY_USERS 关键字下。 注册表关键字称号 代表蜂箱时基于用户的SID的。假如 你通过regedt32.exe 或regedit.exe检测到HKEY_USERS下的注册表关键字,你将看到至少两个子关键字, .DEFAULT 和以S-1开头的长字符串。这是用户的SID。假如 你还不清楚HKEY_CURRENT_USER代表的是什么意义 ,那么我告诉你,基本上说,它是一个HKEY_USERSuser's SID的映射。通过regedt32.exe 或regedit.exe可以得到验证。
HKEY_USERuser's SID和HKEY_CURRENT_USER的子关键字实际上是一模一样的。当一个应用程序是关于HKEY_CURRENT_USER的,系统将会基于用户的安全上下文把用户映射到合适的蜂箱中,包括用户的SID,它用来在HKEY_USERS下查找正确的蜂箱。假如 由于某种原因用户的蜂箱没有被装载,系统将会把用户的蜂箱映射到。DEFAULT。
现在,看起来一切都好了,但是还有很多问题。首先,服务要依赖用户的注册信息。绝大多数应用程序在HKEY_CURRENT_USER中存储用户的注册信息。例如,用户的打印信息存储在用户的蜂箱中。假如 服务配置配置给不同的帐户,那这个服务将没有任何打印信息。不是一切 的服务都使用。DEFAULT 蜂箱。假如 一个服务配置给一个具有蜂箱的服务帐户,那么 Service Control Manager将会装载哟功能户的蜂箱。Windows NT 4.0中已经添加 了这一功能 。
Service Control Manager不能做的一件事是为服务正确地准备用户的环境。环境变量存储早用户的蜂箱中。服务继承的独一 一个环境变量来自于Service Control Manager。它的环境基于系统环境变量。假如 你改动 系统环境变量,那么只有在重新启动机器后,所做的改动 才能反映到服务中。当系统环境变量改动 时,Service Control Manager不象其它系统进程一样处理WM_SETTINGCHANGE 音讯 。
让我们返回到LocalSystem 帐户的状况 中。怎么 得到一个已合理配置的"蜂箱"呢?有这样几种选择。假如 你有创建注册关键字的应用程序的控制权,就可以创建两次关键字。一次是为HKEY_CURRENT_USER,另一次是为HKEY_USERSDefault。另一种方法是判别 应用程序创建了那些关键字,进行复制,这种方法可以通过手工或编程实现。
假如 你不想和注册表搅在一同 ,你可以用编程的方式装载你自己. 的"蜂箱"。假如 你知道一个已经正确初始化的"蜂箱"的用户名,服务将基于用户名决定蜂箱的位置。通过RegLoadKey API装载"蜂箱",然后扮演这个用户。
问题是你需要. 一个进程标志来扮演这个用户。一个进程标志可以通过LogonUser API调用生成。当然,你需要. 一个用户口令。假如 由于某种原因你所感兴趣的用户有一些进程运行在系统中,服务将会罗列 这些进程知道运行在目的 用户的安全上下文中的进程。一旦一个进程被定位,这个服务将通过调用OpenProcessToken取得 用户标志。在这时,服务将用取得 标志扮演这个用户。
结尾
讨论了在Windows NT服务和由交互式用户启动的应用程序之间的区别,也讨论了服务开发人员最关怀 的三个范畴 : Windows NT 安全、 window stations 和桌面以及注册表"蜂箱"。这些信息将使Windows NT服务的开发变得容易一些并能应用于服务中使用的其它技术中。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

一键重装系统|雨人系统下载|联系我们|网站地图|过期罐头电脑论坛

GMT+8, 2024-11-13 04:28 , Processed in 0.039219 second(s), 26 queries .

官方免责声明:本站内容来自网友和互联网.若侵犯到您的版权.请致信联系,我们将第一时间删除相关内容!

Powered by Discuz!

专注于win7_win10_win11系统下载装机

© 2010-2023 GQGTPC.Com

快速回复 返回顶部 返回列表