WindowsStations窗口站

来源:互联网 发布:西安交通大学网络导航 编辑:程序博客网 时间:2024/05/22 10:38

以下文章不知道转载自哪里:找不到原网站了。

Window stations 和桌面可能是Windows NT服务中最与众不同的了绝大多数编程者都不会直接接触这两种对象尽管用户每时每刻都要碰到它们window station 和桌面对象就象其它Windows NT对象如事件互斥量和信号量一样是安全(securable)的一个window station 对象包括一个剪贴板一个全局原子集和更多的桌面对象一个window station或者是可见的或者是不可见的一个可见的window station接收用户来自于鼠标或键盘的输入一个显示设备也与之相连这样信息可以显示给交互式用户
在 Windows NT 中只有一个window station 能被看得到就是WinSta可见的window station也被定义成交互式的一个不可见的window station是不可交互的而且也不能接收任何用户的输入也没有显示设备与之相连
如前所述桌面包含在window station对象中一个桌面对象包含一个逻辑的显示表面和窗口菜单等只有属于可见window station的桌面才能被看见并接收用户的输入这个桌面叫做活动桌面
作为交互式用户你在不同的时候碰到三种不同的桌面缺省(Default) Winlogon和ScreensaverWinlogon 桌面是当你按下Ctrl+Alt+Delete组合键时显示在你面前的对话框缺省(Default)桌面是浏览器(Explorer)或者是由交互式用户启动的所有进程它更应当被理解成交互式的应用程序桌面最终的桌面是Screensaver它显示你的屏幕saver你可能已经注意到可以在不同的桌面之间切换当一个用户按下Ctrl+Alt+Delete组合键时操作系统可以从缺省状态切换到Winlogon桌面当你在登录对话框中选择取消系统将再切换回缺省桌面有人问我当切换进行的时候是否其它桌面上的东西都被破坏掉了答案是 不虽然你看不到其它桌面但它们仍然在那里
系统中所有的进程都与window station 和桌面相联系当一个用户第一次登录时交互式window station WinSta和缺省桌面都与这个用户的Shell进程相关联这样用户就能看到shell了如果不是这样用户是什么也看不到的而且在这之后由shell启动的所有进程也会和WinSta 及缺省桌面相关联
你还可以通过STARTUPINFO 数据结构的lpDesktop 成员指定你的进程同哪个window station 和桌面相关联这个数据结构传递给CreateProcess 和 CreateProcessAsUser两个函数你可以将lpDesktop 初始化为NULL意思是让CreateProcess函数使用和调用进程相同的window station 和桌面你可以将你自己的window station 和桌面组合定义成WinSta\Default 或者就定义成空字符串这个参数会让操作系统为启动进程创建一个新的不可见的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 cbReserved;
LPBYTE lpReserved;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO *LPSTARTUPINFO;
Window stations和桌面是具有安全性的对象与window station 和桌面将关联的进程必须由对这些对象的合适的访问权限如果进程没有访问权你会看到这两个消息之一Userdll initialization failure(Userdll初始化失败) 或 Kerneldll initialization failure(Kerneldll初始化失败)由进程返回的退出码为 或 ERROR_NO_WAIT_CHILDREN那么我所指的合适的访问权是什么意思呢?假如你有一个文件这样的对象你可以为这个文件创建一个DACL以使用户具有对这个文件的读访问权Window station 和 桌面是以相同的方式工作的
对于一个桌面对象的一个访问权限叫做DESKTOP_CREATEWINDOW如果用户没有被授予这个访问权限任何由这个用户启动的进程都不能创建窗口不幸的是 象CreateWindow 这样的USER APIs 在发生同CreateFile 或 CreateMutex API类似的安全问题时不会返回 Access Denied(访问被拒绝) 消息Userdll 中的Windows 应用程序将会被终止导致DLL初始化错误的消息Kerneldll 初始化过程是在创建一个控制板窗口时发生的一个例程在没有对window station和桌面的合适的访问权限的时候启动cmdexe然而不幸的是 CreateProcess 没有任何机制来检查这个错误当用户不具有对window station和桌面的合适访问权限时它并不返回一个错误信息CreateProcess将会启动这个应用程序然后这个应用程序本身在DLL失败后终止
编程人员还可以有一种方法越过Userdll initialization failure(Userdll初始化失败消息系统有一个堆用来为window station分配内存内存是有限的缺省设置允许创建七个或八个window station对象如果你用光了所有的内存你就会看到这个消息不过值得庆幸的是有一个注册表关键字可以用来增加这个设置 (参见Knowledge Base article Q)
如果你没在开发服务而只是普通的应用程序Window stations 和桌面就不是真正的问题你的应用程序只同交互式桌面WinSta\Default 相关联如果你是在开发一个服务那么它可能就会同下面的window station 及桌面组合关联
WinSta\Default
Servicexe$\Default
Service Accounts Logon SID\Default
WinSta\Default 同运行在LocalSystem帐户的并且与桌面交互的服务关联 (在ServiceType必须指明SERVICE_INTERACTIVE_PROCESS标志)如果服务不同桌面交互那么它是与Servicexe$\Default相关联的这是个不可见的window station你一定很疑惑这乱七八糟的xe$ 是什么它是服务的登录SID 登录SID是独一无二的它指的是用户所属的组系统中的所有用户都会有一个登录SID
有一个有趣的现象是尽管你为同一个服务帐户配置了两个服务但由于它们的登录SID是不同的所以每个都将有一个独一无二的window station 及桌面用户的SID是相同的但是由于它们运行在不同的服务帐户登录段中所以它们每一个都有独一无二的登录段对于交互式服务和非交互式的LocalSystem 服务情况就不同了因为它们既同WinSta关联又同Servicexe$关联
为什么知道哪个window station和桌面与服务相关联是如此的重要呢?第一交互性如果你的服务没有和WinSta\Default相关联它就不能以缺省状态把任何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 桌面现在是活动桌面当第二个用户登录系统时系统将会切换回缺省桌面用户显示的任何事物都可以被交互式用户看到
交互式服务和由交互式用户启动的进程之间的区别是当没有用户登录时服务仍然可以运行这就导致了一些有趣的问题例如基于安全的原因当交互式用户退出系统后操作系统竟全局原子表清为如果一个交互式服务依赖于存储在全局原子表中的信息那么当这个交互式用户退出后信息全部消失另一个例子是自启动交互式服务第一个用户登录之前缺省桌面还没有创建这意味着在用户登录之前试图显示信息的交互式服务一定会出问题
我想讨论的最后一件事是交互式服务是暴露给交互式用户的这个交互式用户可以通过任务管理器杀死服务如果你有一个运行在LocalSystem 帐户上的服务则交互式用户将不具备必须的安全性来杀死你的进程假设你进入任务管理器列出所有的进程如果你点击了End Process(终止进程)按纽来终止运行在LocalSystem帐户上的进程时你将会得到意料之中的 Access is denied(访问被拒绝) 消息框但是如果这个服务有一个显示在外层的窗口你可以在任务管理器中列出所有应用程序当你点击End Task(终止任务)按纽你就可以通过这个暴露的窗口杀死这个服务避免这种情况发生的一种方法就是让你的窗口不要显示在应用程序标签中创建一个隐藏的窗口然后将可见的窗口作为这个隐藏窗口的儿子窗口
记住最后的手段才是将你的服务交互化最好的选择是创建一个交互式的客户应用程序
注册表蜂箱
蜂箱是操作系统用来存储用户注册信息的在注册表中存储的注册信息包括桌面应用程序打印和网络设置系统将用户的注册信息备份在一个象蜂箱一样的文件中Windows NT的每个用户都分配一个蜂箱这个蜂箱能放在本地的或远程的服务器上当一个用户登录到Windows NT机器上时系统把用户的蜂箱装载到注册表中在HKEY_USERS 关键字下 注册表关键字名称代表蜂箱时基于用户的SID的如果你通过regedtexe 或regeditexe检测到HKEY_USERS下的注册表关键字你将看到至少两个子关键字 DEFAULT 和以S开头的长字符串这是用户的SID如果你还不清楚HKEY_CURRENT_USER代表的是什么意思那么我告诉你基本上说它是一个HKEY_USERS\users SID的映射通过regedtexe 或regeditexe可以得到验证
HKEY_USER\users SID和HKEY_CURRENT_USER的子关键字实际上是一模一样的当一个应用程序是关于HKEY_CURRENT_USER的系统将会基于用户的安全上下文把用户映射到合适的蜂箱中包括用户的SID它用来在HKEY_USERS下查找正确的蜂箱如果由于某种原因用户的蜂箱没有被装载系统将会把用户的蜂箱映射到DEFAULT
现在看起来一切都好了但是还有很多问题首先服务要依赖用户的注册信息绝大多数应用程序在HKEY_CURRENT_USER中存储用户的注册信息例如用户的打印信息存储在用户的蜂箱中如果服务配置配置给不同的帐户那这个服务将没有任何打印信息不是所有的服务都使用DEFAULT 蜂箱如果一个服务配置给一个具有蜂箱的服务帐户那么 Service Control Manager将会装载哟功能户的蜂箱Windows NT 中已经增添了这一功能
Service Control Manager不能做的一件事是为服务正确地准备用户的环境环境变量存储早用户的蜂箱中服务继承的唯一一个环境变量来自于Service Control Manager它的环境基于系统环境变量如果你改变系统环境变量那么只有在重新启动机器后所做的改变才能反映到服务中当系统环境变量改变时Service Control Manager不象其它系统进程一样处理WM_SETTINGCHANGE 消息
让我们返回到LocalSystem 帐户的情况中怎样得到一个已合理配置的蜂箱呢?有这样几种选择如果你有创建注册关键字的应用程序的控制权就可以创建两次关键字一次是为HKEY_CURRENT_USER另一次是为HKEY_USERS\Default另一种方法是判断应用程序创建了那些关键字进行复制这种方法可以通过手工或编程实现
如果你不想和注册表搅在一起你可以用编程的方式装载你自己的蜂箱如果你知道一个已经正确初始化的蜂箱的用户名服务将基于用户名决定蜂箱的位置通过RegLoadKey API装载蜂箱然后扮演这个用户
问题是你需要一个进程标志来扮演这个用户一个进程标志可以通过LogonUser API调用生成当然你需要一个用户口令如果由于某种原因你所感兴趣的用户有一些进程运行在系统中服务将会列举这些进程知道运行在目标用户的安全上下文中的进程一旦一个进程被定位这个服务将通过调用OpenProcessToken获得用户标志在这时服务将用获得标志扮演这个用户
结尾
讨论了在Windows NT服务和由交互式用户启动的应用程序之间的区别也讨论了服务开发人员最关心的三个领域 Windows NT 安全 window stations 和桌面以及注册表蜂箱这些信息将使Windows NT服务的开发变得容易一些并能应用于服务中使用的其它技术中




0 0
原创粉丝点击