从windows服务中枚举打开的窗口

本文关键字:窗口 枚举 windows 服务 | 更新日期: 2023-09-27 18:14:46

我想枚举给定进程的子窗口来检查对话窗口。由于某些原因,我不会在这里展开讨论,如果它发现了任何问题,我希望随后终止该应用程序。

运行一个独立的应用程序来完成这个工作没有任何问题。应用程序可以访问(通过一些P/Invoke调用)进程的窗口,我可以随后终止该应用程序。

然而,

将相同的代码作为服务运行,并不像预期的那样工作。似乎运行该服务的用户无法与桌面交互(这是一个我只能看到本地系统帐户的设置)。

有人知道这个的变通方法吗?我是否可以从窗口服务中枚举进程的窗口?

仅供参考——我使用的代码(至少是改编的)可以在这里获得:https://stackoverflow.com/a/1405088/2115261

从windows服务中枚举打开的窗口

你可能运行的是Windows 7(或8或Vista),因为Windows服务与桌面交互的能力最后是在Windows XP中支持的。

在MSDN上有一篇白皮书描述了Vista及以上版本的变化。基本上,现在不可能以任何方式与桌面交互。

然而,CodeProject上有一个例子演示了如何与Windows服务中的任务调度程序交互,并且任务调度程序执行的进程可以与桌面交互。

您只能枚举与您的进程相同的终端服务会话(又名远程桌面会话)上的窗口。但是,如果给予适当的权限,您可以在另一个终端服务会话中启动子进程来代表您执行该工作,尽管您需要注意潜在的安全问题,这取决于您执行此操作的方式。

假设您已经获得了目标进程的句柄,最简单的方法是使用OpenProcessToken在目标会话中获取令牌,使用DuplicateTokenEx复制令牌,使用CreateProcessAsUser启动子进程。因为你所需要的只是一个是/否的答案,你可以使用进程退出码,而不需要IPC机制。

安全含义:由于子进程在用户的上下文中运行,有知识的用户可能会阻止它正常运行。此外,如果您确实使用IPC机制,则必须将来自子进程的输入视为不可信(检查缓冲区溢出等)。

另一种方法是在您自己的上下文中启动子流程,但在目标会话中。在IIRC中,您可以复制自己的令牌,并在使用CreateProcessAsUser启动子进程之前在副本上使用SetTokenInformation来更改TokenSessionId

安全含义:子进程以及通过子进程的服务进程和服务帐户可能受到粉碎攻击(恶意窗口消息)和其他风险,尽管完整性级别机制可能在一定程度上减轻这种风险。我的理解是,创建单独的窗口站和桌面(使用适当的acl)可以消除这些风险,但我不确定这会对您想要运行的代码产生什么影响。另一种缓解方法是在启动子进程之前使用CreateRestrictedToken从令牌中删除所有组和权限。

除非绝对必要,否则用户不能破坏您检测对话框窗口存在的能力,否则我强烈建议使用第一种方法。

如果你给服务一个本地系统帐户登录,你将能够勾选"允许服务与桌面交互"复选框在服务的属性(从服务控制管理器)。

请参阅服务属性页的"登录"选项卡。

那可能对你有用。但不幸的是,它可能不会。还是值得一试吗?