尝试挂接到 MessageBeep 系统 API
Trying to hook to MessageBeep system API
被客户要求解决以下讨厌的问题。他们有一个自定义软件,该软件倾向于在没有任何明显原因的情况下"左右"显示消息框。例如,软件本身是一个会计程序,当他们接受客户的付款时,消息框可能会连续显示大约 3 或 4 次。每个消息框都播放 Windows 默认声音。不幸的是,该软件的编程方式,它播放的声音类型是完全错误的。例如,当消息本身只是一个信息时,它可能会显示一个警告消息框并播放警告系统声音。对于使用该软件的工作人员来说,所有这些都很烦人。
我试图联系分发软件的供应商,但我与他们陷入了死胡同。所以现在我正在寻找缓解这个问题的方法。
我最简单的解决方案是建议将扬声器静音,但不幸的是,它们需要声音才能听到传入的电子邮件,最重要的是,以后能够播放来自扬声器的语音邮件。所以我的解决方案是以某种方式将消息框声音静音,仅用于单个进程。
根据我的经验,我知道有两个API可能会产生这些声音:MessageBeep和较旧的哔哔声。
我还发现了这篇文章,它解释了如何使用AppInit_DLLs挂接到系统 API。它工作得很好,除了我需要钩接的两个 API 都来自 User32.dll而不是像作者建议的那样来自 kernel32.dll。
问题部分还有这篇文章,它给出了从 User32.dll 挂钩到 API 的大致步骤,但是当我尝试实现它们时,没有足够的信息(据我所知(。
所以我的问题是,有谁知道如何挂接到 User32.dll 模块中的 API?
编辑:PS.忘了提。此软件安装在 Windows 7 专业版上,禁用了 UAC - 因为它与 UAC :)<</p>
作为替代方案,您可以修补您的应用程序。查找要MessageBeep
的调用,并用 nop
覆盖它们。
这是很难做到的:如果你的应用程序应该在Vista之前的Windows上以管理员身份运行,你可以通过::GetProcAddress()
获取API的地址,给自己写入其内存页面的权限,并用"jmp
"汇编指令覆盖API代码的开头跳入覆盖函数的地址。确保您的覆盖函数采用相同的参数并声明为 __cdecl
。
扩展答案如下。
API 挂钩的"标准"技术涉及以下步骤:
1:将 DLL 注入目标进程
这通常是通过首先在目标进程中为包含 DLL 名称/路径的字符串分配内存(例如"MyHook.dll"(来实现的,然后在目标进程中创建一个远程线程,其入口点kernel32::LoadLibraryA()
传递 DLL 的名称作为参数。此页面包含此技术的实现。你将不得不与特权搏斗,但它保证在Windows XP和更早的操作系统上100%工作。我不确定 Vista 和后 Vista,地址空间布局随机化可能会使这变得棘手。
2. 挂钩 API
将 DLL 加载到目标进程后,其DllMain()
将自动执行,让您有机会在目标进程中运行所需的任何内容。在DllMain
中,使用 ::LoadLibraryA()
获取包含要挂钩的 API 的库的HMODULE
(例如"user32.dll"(,并将其与要挂钩的 API 的名称(例如"MessageBeep"(一起传递给::GetProcAddress()
以获取 API 本身的地址。最终,赋予自己写入该地址页面的权限,并用跳入绕道的jmp
指令覆盖API的开头(即进入要挂钩的API的"版本"(。请注意,您的绕道需要与您要挂钩的 API 具有相同的签名和调用约定(通常为 _cdecl
(,否则怪物将被唤醒。
如此处所述,这种技术在某种程度上具有破坏性:你不能绕道回调原始 API,因为原始 API 已被修改为跳转到你的 API,你最终会得到一个非常紧凑和漂亮的无限循环。有许多不同的技术可以让你保留和/或回调到原始API,其中之一是挂接API的...A()
版本,然后调用...W()
版本(大多数(如果不是全部(...A()
Windows API将ASCII字符串转换为UNICODE字符串,并最终调用它们的...W()
对应项(。
无需花时间在自定义程序上来执行此操作。
您可以在特定应用程序运行时将其静音,下次打开该应用程序时将记住该设置。请参阅 https://superuser.com/questions/37281/how-to-disable-sound-of-certain-applications。
还有Windows Sound Sentry可以关闭大多数系统声音,尽管我不知道Sound Sentry的任何每个应用程序的设置。
您可以使用 Deviare API 钩子并在几个 C# 行中求解钩子。或者你可以使用更困难和不太稳定的EasyHook。
- C++,系统无法执行指定的程序
- 在UNIX系统中使用DIR查找文件的字节大小
- 错误处理.将系统错误代码映射到泛型
- 当系统的卷被修改时,如何修改WASAPI环回捕获卷
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 在C++游戏中与库存系统作斗争
- 文件系统:复制功能的速度秘诀是什么
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 在gtest.中使用fff.h模拟系统API
- 如何制作无限制照明系统
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 如何传递多个 std::文件系统选项?
- 遍历顺序由 std::文件系统directory_iterator给出
- C++系统找不到指定的文件错误
- 系统参数信息A 与 SPI_GETMOUSE 返回 0
- libstdc++ 文件系统中未初始化的用法?
- 如何在ECS框架中更新组件数据和通知系统
- boost::文件系统::recursive_directory_iterator多线程安全
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- 尝试挂接到 MessageBeep 系统 API