SetWindowsHookEx for WH_JOURNALRECORD fails under Vista/Windows 7
Asked Answered
R

1

8

I am preparing a Delphi module, which sets a hook in a thread to record a macro:

FHandleRec  := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);
FHandlePlay := SetWindowsHookEx(WH_JOURNALPLAYBACK, FPlayProc, HInstance, 0);

That works fine on WinXP, but on Vista/Windows 7 fails with ERROR_ACCESS_DENIED. I have found in Google (this) referring (that). The quote:

A lower privilege process cannot: … Use Journal hooks to monitor a higher privilege process.

Tried without success:

  1. Run application as administrator. Probably the thread is started with lower privileges than the main thread (though I am not 100% sure)
  2. Impersonating the thread with administrator security context doesn’t help either.

The code sample:

if LogonUser(PWideChar(sAdminUser), PWideChar(sDomain), PWideChar(sPwd),
             LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) then 
begin  
  if not ImpersonateLoggedOnUser(hToken) then
    raise Exception.Create('Error impersonating the user');
end;
FHandleRec := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);

LogonUser and ImpersonateLoggedOnUser execute without errors.

Other possibilities to try:

  1. Turn UAC OFF permanently. This helps, but I cannot force the module users to do that.
  2. A module customer signs an application and put it in a trusted location. Not tried that, but that radically complicates the module usage for the users.
  3. Put the module into some signed application and distribute EXE. That will break some core functionality.

Could you please show the code that is setting the hook under Visa / Windows 7 or suggest the working solution ?

Rare answered 6/2, 2012 at 19:2 Comment(1)
You'll need to embed a manifest to ask the user for elevation permission. I suspect that falls in the "radically complicates" category.Jihad
M
9

Read the "User Interface Privilege Isolation" section of that article again more carefully. It is referring to integrity levels, not user permissions. That is why impersonating another user does not solve the problem. The integrity level is established when the process first starts and cannot be changed dynamically in code.

User Interface Privilege Isolation (UIPI) is one of the mechanisms that helps isolate processes running as a full administrator from processes running as an account lower than an administrator on the same interactive desktop. UIPI is specific to the windowing and graphics subsystem, known as USER, that supports windows and user interface controls. UIPI prevents a lower privilege application from using Windows messages to send input from one process to a higher privilege process. Sending input from one process to another allows a process to inject input into another process without the user providing keyboard or mouse actions.

Windows Vista implements UIPI by defining a set of user interface privilege levels in a hierarchical fashion. The nature of the levels is such that higher privilege levels can send window messages to applications running at lower levels. However, lower levels cannot send window messages to application windows running at higher levels.

The user interface privilege level is at the process level. When a process is initialized, the User subsystem calls into the security subsystem to determine the desktop integrity level assigned in the process’s security access token. The desktop integrity level is set by the security subsystem when the process is created and does not change. Therefore, the user interface privilege level is also set by the User subsystem when the process is created and does not change.

All applications run by a standard user have the same user interface privilege level. UIPI does not interfere or change the behavior of window messaging between applications at the same privilege level. UIPI comes into effect for a user who is a member of the administrators group and may be running applications as a standard user (sometimes referred to as a process with a filtered access token) and also processes running with a full administrator access token on the same desktop. UIPI prevents lower privilege processes from accessing higher privilege processes by blocking the behavior listed below.

  • Use Journal hooks to monitor a higher privilege process.

According to this article, your app needs a UAC manifest that specifies both requestedExecutionLevel=requireAdministrator and uiAccess=True. The UIAccess right is important:

By specifying UIAccess=”true” in the requestedPrivileges attribute, the application is stating a requirement to bypass UIPI restrictions ... A process that is launched with UIAccess rights:

  • Can set journal hooks.
Meredithmeredithe answered 7/2, 2012 at 2:21 Comment(3)
Remy, thanks much for the answer. Suppose I have the out-of-process COM server - signed and manifested exe with uiAccess=True. The server sets the hook procedures and exchanges the data with the user application through the COM callbacks. So, all processing is still performed by the user application. Question: when a standard UI application (not signed and running without rights elevation) uses such a COM server, will the server still be able to set the journal hooks?Rare
@AlexeyDaryin: as its name implies, an out-of-process COM server runs in its own process. The rights of the standard app's process will not have an effect on the rights of the COM server's process. You might need to use CoInitializeSecurity() to allow lower-rights processes to connect and use your COM server, though.Meredithmeredithe
@AlexeyDaryin, if you don't want to elevate the main app with UAC/UIAccess rights, then you have to elevate another process, whether that is a COM server or a Service or whatever is up to you, whatever suits your needs.Meredithmeredithe

© 2022 - 2024 — McMap. All rights reserved.