For security reasons the UI module for my application runs with a high
mandatory integrity level. Everything in it works great, except one thing. For compatibility with older versions I need to be able to let users issue command line calls to the UI module.
At the moment this mechanism works as such:
The shortcut from Windows Explorer calls my module, say as such:
path-to-module\module.exe -op="a, s, r"
When module.exe
process parses this command line it then locates the running copy of UI module (or another copy of self) using FindWindow by its unique class name. It then sends it a registered message using PostMessage API.
Then the running UI module (with high
integrity level), when it receives the message, processes it accordingly.
The problem is that because the running copy of UI module has high
integrity level, it cannot receive messages from a lower integrity level, or the copy of the module when it's run by the Windows Explorer to parse a shortcut command, which makes it run with medium
integrity level.
To address this I found this UIAccess
flag (see here, and scroll down to where it says "UIAccess for UI automation applications".)
So my assumptions were that if I set this flag and code-sign my UI module:
it will be able to bypass the UIPI restriction I described above.
It runs just fine:
But what I see is that PostMessage
API in the algorithm I described above still fails with ERROR_ACCESS_DENIED when I call it from the module running with medium
integrity level.
What have I missed there?
What you describe is covered in the Win32 API documentation:
PostMessage function
If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError returns ERROR_NOT_ENOUGH_QUOTA
when the limit is hit.
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Where UIPI is User Interface Privilege Isolation:
What is User Interface Privilege Isolation (UIPI)
This is also known as UI Privilege Level Isolation (UIPI).
As part of the secure initiatuve in Vista, applications with UI will run in three different levels of privilege. Application windows can interact with others windows of the same or lower levels, but cannot interact with applications at higher level/permission.
Lower privilege modes can send messages to higher privileged applications only if explicitly allowed by the higher privilege application with a message calling ChangeWindowMessageFilter()
. Also lower privileged applications can only read a HWND
owned by a higher privileged application.
Internet Explorer is an example process that runs at the lowest privilege level.
Reference Links:
http://msdn2.microsoft.com/en-us/library/ms632675.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/AccProtVista.asp
UIPI prevents lower privilege processes from accessing higher privilege processes by blocking the following behavior.
A lower privilege process cannot:
– Perform a window handle validation of higher process privilege.
– SendMessage
or PostMessage
to higher privilege application windows. These application programming interfaces (APIs) return success but silently drop the window message.
– Use thread hooks to attach to a higher privilege process.
– Use Journal hooks to monitor a higher privilege process.
– Perform dynamic link library (DLL)–injection to a higher privilege process.
With UIPI enabled, the following shared USER resources are still shared between processes at different privilege levels.
– Desktop window, which actually owns the screen surface
– Desktop heap read-only shared memory
– Global atom table
– Clipboard
As the documentation says, the higher privilege application needs to use ChangeWindowMessageFilter()
to allow specific window messages from lower privilege applications:
Adds or removes a message from the User Interface Privilege Isolation (UIPI)message filter.
On Windows 7 and later, use ChangeWindowMessageFilterEx()
instead:
Modifies the User Interface Privilege Isolation (UIPI) message filter for a specified window.
So, in your case, after your higher privileged process calls RegisterWindowMessage()
to get a registered message ID, it needs to pass that ID to ChangeWindowMessageFilter/Ex()
in order to receive that message from lower privileged processes.