1

客户要求我解决以下讨厌的问题。他们有一个自定义软件,该软件倾向于在没有任何明显原因的情况下“左右”显示消息框。比如软件本身就是一个记账程序,当他们取客户的钱时,消息框可能会连续显示3到4次左右。每个消息框都会播放 Windows 默认声音。不幸的是,这个软件的编程方式,它播放的声音类型是完全错误的。例如,当消息本身只是一个信息时,它可能会显示一个警告消息框并播放警告系统声音。这一切对于使用该软件的员工来说是相当烦人的。

我试图联系分发软件的供应商,但我遇到了死胡同。所以现在我正在寻找缓解这个问题的方法。

我最简单的解决方案是建议将扬声器静音,但不幸的是,它们需要有声音才能听到传入的电子邮件,最重要的是,以后能够播放来自它们的语音邮件。所以我的解决方案是以某种方式静音消息框的声音,只为一个进程。

根据我的经验,我知道有两个 API 可能会产生这些声音:MessageBeep和一个较旧的Beep

我还发现这篇文章解释了如何使用 AppInit_DLLs 来挂钩到系统 API。它工作得很好,除了我需要挂钩的两个 API 来自 User32.dll 而不是作者建议的 kernel32.dll 。

问题部分中还有这篇文章,它提供了从 User32.dll 连接到 API 的大致步骤,但是当我尝试实现它们时,没有足够的信息(据我所知)。

所以我的问题是,有谁知道如何挂钩 User32.dll 模块中的 API?

编辑:附言。忘了提。该软件安装在 Windows 7 Professional 上,禁用了 UAC——因为它与 UAC 不兼容 :)

4

4 回答 4

2

作为替代方案,您可以修补您的应用程序。查找调用MessageBeep并用 覆盖它们nop

于 2013-06-12T09:43:12.000 回答
1

这是很难做到的:如果您的应用程序应该在 Vista 之前的 Windows 上以管理员身份运行,您可以通过 获取 API 的地址::GetProcAddress(),授予自己写入其内存页面的权限,并覆盖开头API 代码的“ jmp”汇编指令跳转到覆盖函数的地址。确保您的覆盖函数采用相同的参数并声明为__cdecl.

扩展答案如下。

API 挂钩的“标准”技术包括以下步骤:

1:将你的DLL注入目标进程

这通常通过首先在目标进程中为包含 DLL 的名称/路径的字符串分配内存(例如“MyHook.dll”),然后在目标进程中创建一个远程线程,其入口点kernel32::LoadLibraryA()传递您的 DLL 作为参数。此页面具有此技术的实现。您将不得不与特权作斗争,但它可以保证在 Windows XP 和更早的操作系统上 100% 工作。我不确定 Vista 和后 Vista,地址空间布局随机化可能会使这变得棘手。

2. 挂钩API

一旦你的 DLL 被加载到目标进程中,它DllMain()就会自动执行,让你有机会在目标进程中运行任何你想要的东西。从您的内部DllMain,使用::LoadLibraryA()获取HMODULE包含您要挂钩的 API 的库(例如“user32.dll”)并将其::GetProcAddress()与您要挂钩的 API 的名称(例如“MessageBeep”)一起传递给以获取API 本身的地址。Eventaully 给自己写入该地址页面的权限,并用jmp跳转到您的绕行的指令覆盖 API 的开头(即进入您要挂接的 API 的“版本”)。请注意,您的 detour 需要与_cdecl您要挂钩的 API 具有相同的签名和调用约定(通常),否则将唤醒怪物。

正如这里所描述的,这种技术具有一定的破坏性:您不能从绕道中回调原始 API,因为原始 API 已被修改为跳入您的 API,您最终会得到一个非常紧凑且漂亮的无限循环。有许多不同的技术可以让您保留和/或回调原始 API,其中之一是挂钩...A()API 的版本,然后调用...W()版本(如果不是全部的话,大多数...A()Windows API 将 ASCII 字符串转换为UNICODE 字符串并最终调用它们的...W()对应项)。

于 2013-06-11T20:35:42.793 回答
0

无需花时间在自定义程序上即可做到这一点。

您可以在特定应用程序运行时将其静音,并且该设置将在您下次打开该应用程序时被记住。请参阅https://superuser.com/questions/37281/how-to-disable-sound-of-certain-applications

还有 Windows Sound Sentry 可以关闭大多数系统声音,尽管我不知道 Sound Sentry 的任何应用程序设置。

于 2013-06-11T20:53:40.377 回答
0

您可以使用Deviare API 挂钩并在几行 C# 中解决该挂钩。或者您可以使用更难且不太稳定的 EasyHook。

于 2013-06-13T18:15:05.543 回答