2016-07-14 75 views
4

使用德尔福2007 ... 我有一个应用程序,它只使用一个互斥体来强制执行一个运行实例。在dpr单元中,如果互斥锁已经存在,我可以使用FindWindow获得正在运行的实例的句柄,至今没有问题。第二个实例通常由虚拟打印机驱动程序参考命令行上的文件名启动。如果有一个命令行文件引用,那么我只想将消息发布到正在运行的实例并暂停新实例。调用postmessage返回“访问被拒绝”

我使用这个......

PostMessage(hwnd,WM_STARTUP_MESSAGE,0,0); //hwnd as returned by FindWindow 

WM_STARTUP_MESSAGE被定义为WM_APP + 6057

我与该WM_STARTUP_MESSAGE没有在主线程中处理问题的一个用户。从DPR单元记录的启动信息,它表明了PostMessage返回false和SysErrorMessage(GetLastError)是:

Zugriff verweigert (his windows german translation is Access Denied). 

我有这个应用程序的许多,许多用户和我只有这个问题的2份报告,在这里无法重现。在Windows 10这里,至少有一个问题用户,另一个我不确定。

我在主窗体的OnCreate中使用ChangeWindowMessageFilterEx以允许WM_COPYDATA。我的想法是简单地包含WM_STARTUP_MESSAGE,但这会导致崩溃,因为该函数不喜欢该消息索引值,所以我认为它是为特定范围的消息值保留的。

有没有人看过这个之前,可以提供一些指导?

回答

10

PostMessage()文档:

当通过UIPI最后一个错误,与GetLastError函数检索,被设定为5阻塞的消息(拒绝访问)。

What is User Interface Privilege Isolation (UIPI) on Vista

这也被称为UI权限级别隔离(UIPI)。

作为Vista中安全启动工具的一部分,具有UI的应用程序将在三个不同级别的特权中运行。应用程序窗口可以与相同或较低级别的其他窗口进行交互,但无法与更高级别的应用程序/权限进行交互。

只有在高级特权应用程序明确允许使用调用ChangeWindowMessageFilter()的消息的情况下,较低特权模式才能将消息发送到较高特权应用程序。另外,特权较低的应用程序只能读取拥有较高特权应用程序的HWND。

Internet Explorer是一个以最低特权级别运行的示例进程。

Windows Integrity Mechanism Design

用户界面特权隔离(UIPI)实现在防止低特权应用程序从在较高特权发送窗口消息或安装钩处理窗口子系统限制。允许更高权限的应用程序将窗口消息发送到权限较低的进程。这些限制在SendMessage和相关的窗口消息函数中实现。并非所有从低权限进程发送到高权限进程的窗口消息都被阻止。一般来说,“read”类型的消息,例如WM_GETTEXT,可以从较低权限发送到较高权限窗口。但是,写入类型消息(如WM_SETTEXT)被阻止。

...

UIPI不会干扰或相同特权(或完整性)级别更改窗口消息的应用程序之间的行为。通过阻止以下行为,UIPI可防止较低特权进程访问较高特权进程。权限更低的过程不能:

  • 执行具有较高的权运行的进程的窗口句柄验证。
  • 使用的SendMessage或PostMessage的应用程序窗口具有更高的权运行。这些API返回成功,但无声地丢弃窗口消息。
  • 使用线程挂钩附加到以更高权限运行的进程。
  • 使用日志挂钩来监视以更高权限运行的进程。
  • 对以更高权限运行的进程执行动态链接库(DLL)注入。

所以很明显,当错误发生时,HWND您要发布帖子属于被以更高的完整性/特权级别的发布消息的过程中运行的进程。您可以使用SysInternals' Process Explorer来检查。

你说你的应用程序的第二个实例是由虚拟打印机驱动程序运行,使驾驶员在比由用户启动应用程序的一个实例较低完整性级别可能运行。

ChangeWidowMessageFilter/Ex()不会对非系统消息ID的任何限制(某些系统消息无法被过滤)。它肯定不会在用户定义的消息ID上崩溃。如果您没有权限更改邮件过滤器对于给定HWND /的MsgID,该功能将简单地返回FALSE,而是和GetLastError()会告诉你为什么。

如果遇到碰撞时,它与其他代码中的东西。

此外,窗体的OnCreate事件不是调用ChangeWindowMessageFilterEx()的最佳场所。在程序生命周期中,表单可能需要动态重新创建其HWND,甚至可能不止一次。每次创建新的HWND时,都必须再次拨打ChangeWindowMessageFilterEx()。考虑到,最好的办法是重写窗体的虚拟CreateWnd()方法,如:

type 
    TMyForm = class(TForm) 
    protected 
    procedure CreateWnd; override; 
    end; 

procedure TMyForm.CreateWnd; 
begin 
    inherited; 
    ChangeWindowMessageFilterEx(Handle, WM_STARTUP_MESSAGE, MSGFLT_ALLOW, nil); 
end; 
+0

如果在Windows启动时(通过注册表RUN)项中的应用程序运行时,它在更高的完整性级别运行? –

+0

它以用户的正常(中等)完整性级别运行,除非可执行文件已用'icacls'标记了不同的完整性级别,或者具有UAC提升清单。此外,如果恶意应用程序可以简单地将自己放入Run键并在未经用户许可的情况下自动获得高完整性访问权,那么您不认为这会是安全漏洞吗? –

+1

@John - 如果您的应用程序的第一个实例没有以更高的权限运行,那么您根本不需要调用ChangeWindowMessageFilterEx。 –