2016-07-14 78 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。 –