8

我正在准备一个 Delphi 模块,它在线程中设置一个钩子来记录宏:

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

这在 WinXP 上运行良好,但在 Vista/Windows 7 上以ERROR_ACCESS_DENIED. 我在谷歌(this)中找到了(that)。报价单:

较低权限的进程不能: … 使用日志挂钩来监控较高权限的进程。

试过没有成功:

  1. 以管理员身份运行应用程序。可能线程的启动权限低于主线程(尽管我不是 100% 确定)
  2. 使用管理员安全上下文模拟线程也无济于事。

代码示例:

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);

LogonUserImpersonateLoggedOnUser执行没有错误。

其他尝试的可能性:

  1. 永久关闭 UAC。这有帮助,但我不能强迫模块用户这样做。
  2. 模块客户签署应用程序并将其放置在受信任的位置。没有尝试过,但这从根本上使用户的模块使用复杂化。
  3. 将模块放入一些签名的应用程序并分发 EXE。这将破坏一些核心功能。

您能否显示在 Visa/Windows 7 下设置挂钩的代码或建议可行的解决方案?

4

1 回答 1

9

再次更仔细地阅读该文章的“用户界面特权隔离”部分。它指的是完整性级别,而不是用户权限。这就是为什么冒充另一个用户并不能解决问题的原因。完整性级别是在进程首次启动时建立的,不能在代码中动态更改。

用户界面特权隔离 (UIPI) 是一种机制,可帮助将在同一交互式桌面上以完全管理员身份运行的进程与以低于管理员身份的帐户运行的进程隔离开来。UIPI 特定于窗口和图形子系统,称为 USER,它支持窗口和用户界面控件。UIPI 阻止较低权限的应用程序使用 Windows 消息将输入从一个进程发送到较高权限的进程。将输入从一个进程发送到另一个进程允许进程将输入注入另一个进程,而无需用户提供键盘或鼠标操作。

Windows Vista 通过以分层方式定义一组用户界面特权级别来实现 UIPI。级别的性质是,较高的特权级别可以将窗口消息发送到运行在较低级别的应用程序。但是,较低级别不能将窗口消息发送到运行在较高级别的应用程序窗口。

用户界面特权级别是进程级别。初始化进程时,用户子系统调用安全子系统来确定进程的安全访问令牌中分配的桌面完整性级别。桌面完整性级别由安全子系统在进程创建时设置并且不会更改。因此,用户界面权限级别也是由用户子系统在进程创建时设置的,不会改变。

标准用户运行的所有应用程序都具有相同的用户界面权限级别。UIPI 不会干扰或更改具有相同权限级别的应用程序之间的窗口消息传递行为。 UIPI 对作为管理员组成员的用户生效,并且可能以标准用户身份运行应用程序(有时称为具有过滤访问令牌的进程)以及在同一用户上使用完整管理员访问令牌运行的进程桌面。UIPI 通过阻止下面列出的行为来防止较低权限的进程访问较高权限的进程。

  • 使用日志挂钩来监控更高权限的进程。

根据这篇文章,您的应用需要一个同时指定requestedExecutionLevel=requireAdministrator和的 UAC 清单uiAccess=True。UIAccess 权限很重要:

通过在 requestedPrivileges 属性中指定 UIAccess=”true”,应用程序声明了绕过 UIPI 限制的要求……使用 UIAccess 权限启动的进程:

  • 可以设置日志挂钩。
于 2012-02-07T02:21:40.900 回答