从UWP应用程序窗口的Windows.UI.Core.CoreWindow获取win32消息

3

我正在尝试通过在WH_CALLWNDPROC, WH_CALLWNDPROCRETWH_GETMESSAGE上钩取来获取特定窗口的Win32指针消息。

我使用dll中的SetWindowsHookEx来钩取并接收消息。

unsigned long processID = 0;
unsigned long threadID = GetWindowThreadProcessId(hWnd, &processID);

g_hhkGetMsg = SetWindowsHookEx(WH_GETMESSAGE,
    GetMsgProc,
    g_hinstDLL,
    threadID);

这适用于许多窗口,但不适用于UWP窗口的CoreWindow。

每个UWP应用程序窗口都有如下结构:UWP window structure

钩取ApplicationFrameWindow可以正常工作,但是钩取Windows.UI.Core.CoreWindow却不能正常工作(SetWindowsHookEx显示成功,但在回调中没有收到任何消息)

然而,Spy++能够捕获来自CoreWindow的消息。(CoreWindow接收WM_POINTER消息,因此我需要订阅该窗口)

考虑问题可能出在我的代码上,我还尝试了开源工具MyLiteSpy,看看它是否能够从CoreWindow捕获消息。它无法捕获任何东西,就像我的示例代码一样。(但是MyLiteSpy能够从同一UWP应用程序的ApplicationFrameWindow中获取消息,我的代码和Spy++也能做到)

enter image description here

有趣的是,关于Spy++的这篇(旧的)博客文章说他们使用与我和MyLiteSpy相同的三个钩子,但它正在接收到我的代码无法接收的消息。

这里有什么区别?为什么会发生这种情况?

(Spy++是否使用了除了三个提到的钩子之外的其他钩子?该博客文章是在2007年编写的,因此情况可能已经改变了)


@IInspectable 不,我的程序没有数字签名(实际上我是在 Visual Studio 中运行它的),我认为 MyLiteSpy 也没有。但是为什么数字签名或清单中的某些内容会影响 win32 钩子呢?这种依赖关系有文档记录吗?如果是真的,你有什么想法可以测试这个假设吗? - Mahdi Ghiasi
1
在清单中需要添加 disableWindowFiltering 属性,参考链接:https://learn.microsoft.com/en-us/windows/desktop/sbscs/application-manifests。 - RbMm
@rbm:所以不需要数字签名,只需要包含“disableWindowFiltering”元素的应用程序清单吗? - IInspectable
@IInspectable - 如果要将dll注入到受保护的进程中,则可能需要数字签名。我没有测试过这一点。但是,如果没有<disableWindowFiltering>true</disableWindowFiltering>,则进程根本无法查看uwp窗口(例如EnumWindows跳过此窗口),因此我猜想,在钩子测试时,disableWindowFiltering在这里扮演关键角色。 - RbMm
@RbMm 哦,所以如果不禁用窗口过滤,应用程序可以看到ApplicationFrameWindow但无法看到CoreWindow?有趣。我还查看了Spy++清单,它确实将disableWindowFiltering设置为true。我会尝试将其添加到我的清单中并查看发生了什么。只是为了确保,我需要将其添加到dll文件的清单中,对吗? - Mahdi Ghiasi
显示剩余18条评论
1个回答

5
类为Windows.UI.Core.CoreWindow的窗口通常是沉浸式窗口。要枚举这样的顶级窗口,我们需要在清单中添加disableWindowFiltering。它禁用了窗口过滤,因此您可以通过EnumWindows从桌面上枚举沉浸式窗口。但是,即使在清单中没有添加disableWindowFiltering,直接调用FindWindowW(L"Windows.UI.Core.CoreWindow", L"Start");也不会失败。但是,这部分仅与可见性沉浸式窗口有关,对于您的应用程序,可以通过EnumWindows进行枚举。
另一个任务是为这些窗口设置WH_GETMESSAGE钩子。问题在于,这些窗口通常属于Windows Store应用(AppContainer)进程。

Windows Store应用开发:如果dwThreadId为零,则窗口钩子DLL不会在Windows Store应用程序进程和Windows Runtime代理进程中加载,除非它们被UIAccess进程(辅助工具)安装。

因此,我们需要在清单中设置uiAccess为true(例如<requestedExecutionLevel level="requireAdministrator" uiAccess="true" />),或者在调用SetWindowsHookEx时将dwThreadId设为非0。我们可以通过GetWindowThreadProcessId获取dwThreadIdWH_GETMESSAGE钩子始终是进程钩子。因此,如果我们为另一个进程调用它,钩子过程必须位于dll中,并将其加载到目标进程中。这里的主要问题是如何将dll加载到Windows Store应用(AppContainer)进程中。
我用简单的dll检查了一下——尝试为Windows.UI.Core.CoreWindow::Calculator窗口设置钩子。调用SetWindowsHookEx(WH_GETMESSAGE, ...)是可以的,在Calculator.exe中调用了LoadLibraryExW来加载我的dll,但是在NtQueryAttributesFile中以STATUS_ACCESS_DENIED的错误失败。好的,Appcontainer是非常受限制的进程,所以我尝试更改我的dll的安全描述符。将其设置为"D:P(A;;FA;;;BA)(A;;FXFR;;;WD)(A;;FXFR;;;AC)S:P(ML;;NW;;;LW)"(向Builtin(local)管理员提供完全访问权限,并为在应用程序包上下文中运行的所有应用程序(SDDL_ALL_APP_PACKAGES-"AC")和“Everyone”("WD")提供读取-执行访问权限)。使用这个,LoadLibraryExW可以继续进行,但仍然无法在ZwCreateSection的调用中为我的DLL分配代码STATUS_SYSTEM_NEEDS_REMEDIATIONC000047EL——检测到系统二进制文件中的错误),之后调用了LdrAppxHandleIntegrityFailure(从ntdll.dll导出的函数)。

enter image description here enter image description here

因此,要将DLL加载到Windows Store应用程序(Appcontainer)中,必须进行签名。从内核方面来看,调用栈如下:

CI!KappxpNotifyNonPackagedFile
CI!KappxNotifyIntegrityFailureInPackagedProcess
CI!CipReportAndReprieveUMCIFailure
CI!CiValidateImageHeader
nt!SeValidateImageHeader
nt!MiValidateSectionCreate
nt!MiCreateNewSection
nt!MiCreateImageOrDataSection
nt!MiCreateSection

有趣的是,如果检查失败,则在KappxpNotifyNonPackagedFile中的CI.DLL会将文件名和哈希写入注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModel\StateChange- BinaryNameREG_SZ)和BinaryHashREG_BINARY)。

enter image description here

对于Spyxx,它使用签名的dll-spyxxhk[_amd64].dll,如果允许所有应用程序包访问它,则该dll将被加载到进程中。因此,Spy++也可以从Appcontainer应用中收集消息。但是在我的研究中,Spy++会以0为dwThreadId开始调用SetWindowsHookExW。因此,spyxxhk[_amd64].dll不会注入到Windows商店应用程序中。需要每次使用非0的dwThreadId并在dll上具有特殊的安全描述符。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接