Попытка подключиться к системному API MessageBeep

Клиент попросил меня решить следующую неприятную проблему. У них есть специальное программное обеспечение, которое имеет тенденцию отображать окна сообщений «влево и вправо» без видимой причины. Например, само программное обеспечение является бухгалтерской программой, и когда они принимают платеж клиента, окно сообщения может отображаться примерно 3 или 4 раза подряд. Каждое окно сообщения воспроизводит звук Windows по умолчанию. К сожалению, то, как это программное обеспечение было запрограммировано, тип звуков, которые оно воспроизводит, совершенно неверно. Например, он может отображать окно с предупреждающим сообщением и воспроизводить звук системы предупреждения, когда само сообщение является просто информацией. Все это довольно раздражает сотрудников, которые используют программное обеспечение.

Я пытался связаться с поставщиком, который распространяет программное обеспечение, но я столкнулся с ними. Поэтому сейчас я ищу способы смягчить эту проблему.

Моим самым простым решением было предложить отключить звук динамиков, но, к сожалению, им требуется наличие звука, чтобы они могли слышать входящие электронные письма и, что самое важное, позже могли воспроизводить голосовые сообщения от них. Таким образом, мое решение заключалось в том, чтобы как-то отключить звук окна сообщения только для одного процесса.

Из своего опыта я знаю, что есть два API, которые могут создавать эти звуки: MessageBeep и старше гудок.

Я также нашел Эта статья это объясняет, как использовать AppInit_DLLs для подключения к системным API. Он прекрасно работает, за исключением того, что оба API, которые мне нужно подключить, приходят из User32.dll, а не из kernel32.dll, как предлагает автор.

Есть также эта почта в разделе вопросов, который как бы дает приблизительные шаги по подключению к API от User32.dll, но когда я пытался их реализовать, мне не хватало информации (насколько мне известно, чтобы это сделать).

Итак, мои вопросы, кто-нибудь знает, как подключить API в модуле User32.dll?

РЕДАКТИРОВАТЬPS Забыл упомянуть. Это программное обеспечение установлено в Windows 7 Professional с отключенным UAC — поскольку оно не совместимо с UAC 🙂

1

Решение

Это сложный способ сделать это: если ваше приложение должно работать от имени администратора в Windows до Windows Vista, вы можете получить адрес 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. Даже предоставьте себе право писать на страницу с этим адресом и переписать начало API с помощью jmp инструкция, попадающая в ваш обход (т. е. в вашу «версию» API для подключения). Обратите внимание, что ваш обход должен иметь одинаковую подпись и соглашение о вызовах (обычно _cdecl) как API, который вы хотите подключить, иначе монстры будут пробуждены.

Как описано здесь, эта техника несколько деструктивна: вы не можете перезвонить в исходный API из объезда, так как исходный API был изменен, чтобы перейти к вашему, и вы получите очень узкий и приятный бесконечный цикл. Существует много различных методов, которые позволят вам сохранить и / или перезвонить в исходный API, одним из которых является перехват ...A() версии API, а затем вызывая в ...W() версии (большинство, если не все ...A() Windows API преобразует строки ASCII в строки UNICODE и в конечном итоге вызывает их ...W() двойники).

1

Другие решения

В качестве альтернативы вы можете исправить ваше приложение. Найти звонки MessageBeep и перезаписать их nop,

2

Не нужно тратить время на пользовательскую программу, чтобы сделать это.

Вы можете отключить звук определенного приложения, когда оно запущено, и этот параметр запомнится при следующем открытии приложения. Увидеть https://superuser.com/questions/37281/how-to-disable-sound-of-certain-applications.

Существует также Windows Sound Sentry, которая отключает большинство системных звуков, хотя я не знаю никаких настроек для каждого приложения для Sound Sentry.

0

Ты можешь использовать Deviare API hook и решить крюк в пару строк C #. Или вы можете использовать EasyHook, который немного сложнее и менее стабилен.

0