【问题标题】:ChangeWindowMessageFilterEx() Returns Error Code 5ChangeWindowMessageFilterEx() 返回错误代码 5
【发布时间】:2019-09-12 05:24:44
【问题描述】:

我想获取窗口中复选框的状态。

所以我使用了SendMessage(hwnd, BM_GETCHECK, NULL, NULL),但它总是返回 0。为了知道原因,我使用了 GetLastError(),它返回了 5。

Microsoft's documentation 中,它表示“当消息被 UIPI 阻止时,使用 GetLastError 检索的最后一个错误设置为 5(拒绝访问)。”

所以,经过一番研究,我使用ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0) 来绕过特权问题。

ChangeWindowMessageFilterEx() 也给出错误代码 5 并返回 false。

但是,当我使用 ChangeWindowMessageFilter() 时,它返回 true 并给出错误代码 0。但 SendMessage(hwnd, BM_GETCHECK, NULL, NULL) 仍然给出错误代码 5。

方法 1

status = ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0); //returns false
error = ::GetLastError(); // gives error code 5
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);

方法 2

status = ChangeWindowMessageFilter(BM_GETCHECK, MSGFLT_ADD); //returns true
error = ::GetLastError() // gives error code 0
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);
error = ::GetLastError(); // gives error code 5   

我在这里做错了什么?

【问题讨论】:

  • ChangeWindowMessageFiltertarget 进程调用,以允许低权限应用向其发送消息。如果任何进程都可以更改另一个应用程序的过滤器,这将不是一个很好的安全机制吗?
  • 尝试以管理员权限运行您的代码。
  • 另外,子窗口控件的HWND id如何能够首先向它发送消息? EnumChildWindows?
  • @JonathanPotter 我是新手。所以如果我错了请原谅我。如果我不能调用 ChangeWindowMessageFilter,那么就没有办法从我的程序中更改权限,是吗?当我检查我的进程时,它以中等完整性运行。但是我找不到我的程序试图向其发送消息的窗口的完整性。另外,我很困惑如何从该窗口的进程中调用 ChangeWindowMessageFilter。我是不是迷路了?
  • 如果您的低权限进程可以通过调用函数简单地从高权限进程中禁用 UIPI,那么 UIPI 将毫无意义。您需要要求目标进程的作者更改他们的代码以让您进入。他们不太可能会这样做。因此,请以管理员权限运行您的进程。

标签: c++ windows winapi


【解决方案1】:

终于找到了另一种获取复选框状态的方法。 inspect.exe 是救星。感谢@Rita Han - MSFT 建议 inspect.exe。由于更改权限/访问权限或绕过 UIPI 限制并不复杂,我们决定使用 UIAutomation。我们使用 UIAutomation 检索了设置窗口中的所有数据!

【讨论】:

    【解决方案2】:

    有两种方法可以获取此场景中复选框的状态。

    1. 以与目标程序相同或更高的完整性级别运行您的程序,例如在提升模式下运行程序可能会有所帮助,因为大多数程序都在高完整性下运行。您还可以在清单中指定级别,如下所示(参考/MANIFESTUAC

      /MANIFESTUAC:level=_level

    2. 使用程序应用程序清单中的特殊安全属性(称为 UIAccess)的 UI 自动化程序可以跨权限级别绕过 UIPI 对 SendMessage 的限制。以下是 UIAccess 程序的应用程序清单条目示例。

      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" UIAccess="true" /> </requestedPrivileges> </security> </trustInfo>

    通过在 requestedPrivileges 属性中指定 UIAccess=”true”,应用程序要求绕过 UIPI 对跨权限级别发送窗口消息的限制。在启动具有 UIAccess 权限的应用程序之前,Windows Vista 会实施以下策略检查。

    • 应用程序必须具有可验证的数字签名 使用链接到受信任根的数字证书 本地机器受信任的根证书颁发机构证书 商店。

    • 应用程序必须安装在本地文件夹应用程序中 只能由管理员写入的目录,例如 程序文件目录。 UI 自动化允许的目录 应用程序是:

      • %ProgramFiles% 及其子目录。
      • %WinDir% 及其子目录,但由于标准用户具有写入权限而被排除的少数子目录除外。

    详情请参考文档:

    Mandatory Integrity Control

    但现在唯一的问题是只有在鼠标悬停在该元素上后才能检索复选框状态。我正在尝试为此找到解决方案。无论如何,如果您能对此有所了解,那就太好了。

    我们可以通过windows handler获取元素,而不是鼠标悬停后获取元素。以下是获取复选框状态的代码供您参考:

    CoInitialize(NULL);
    
    IUIAutomation * UIAutomation;
    InitializeUIAutomation(&UIAutomation);
    
    IUIAutomationElement *targetIUIAutomationElement;
    
    UIAutomation->ElementFromHandle((UIA_HWND)0x513F8,&targetIUIAutomationElement);
    
    VARIANT checkboxState;
    targetIUIAutomationElement->GetCurrentPropertyValue(UIA_ToggleToggleStatePropertyId,&checkboxState);
    if(checkboxState.lVal== ToggleState_Off)
        std::cout << "The check box is not checked...\n";
    else if(checkboxState.lVal == ToggleState_On)
        std::cout << "The check box is checked...\n";
    else
        std::cout << "The checkbox is in indeterminate...\n";
    

    【讨论】:

    • 客户端不希望我们更改访问/特权。所以我们找到了另一种获取复选框状态的方法。无论如何,非常感谢您的努力!非常感谢。
    • @GowthamM 您可以在此处分享解决方案/解决方法,以便有相同问题的其他社区也可以从这篇文章中受益。顺便说一句,如果客户不想更改访问/特权,您也可以选择选项 2 绕过 UIPI 限制。
    【解决方案3】:

    如果您只想询问复选框的状态,而不是使用 SendMessage,您可以只检查可访问性树。也就是说,使用与屏幕阅读器相同的 API。

    AccessibleObjectFromWindow and friends开头。

    【讨论】:

    • 这肯定也会受到 UIPI 的约束
    • 虽然技术上是正确的,但这个答案并不能解决实际提出的问题
    猜你喜欢
    • 2017-06-03
    • 2017-06-30
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 2014-07-03
    • 1970-01-01
    相关资源
    最近更新 更多