Клиент попросил меня решить следующую неприятную проблему. У них есть специальное программное обеспечение, которое имеет тенденцию отображать окна сообщений «влево и вправо» без видимой причины. Например, само программное обеспечение является бухгалтерской программой, и когда они принимают платеж клиента, окно сообщения может отображаться примерно 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 🙂
Это сложный способ сделать это: если ваше приложение должно работать от имени администратора в Windows до Windows Vista, вы можете получить адрес API через ::GetProcAddress()
, дайте себе привилегии писать на его страницу памяти и переписать начало кода API с помощью «jmp
«Инструкция по сборке, переходящая в адрес вашей функции переопределения. Убедитесь, что ваша функция перезаписи принимает те же аргументы и объявлена как __cdecl
,
Расширенный ответ следует.
«Стандартный» метод для перехвата API включает следующие шаги:
Обычно это достигается путем выделения памяти в целевом процессе для строки, содержащей имя / путь к вашей DLL (например, «MyHook.dll»), а затем создания удаленного потока в целевом процессе с точкой входа kernel32::LoadLibraryA()
передавая имя вашей DLL в качестве аргумента. Эта страница имеет реализацию этой методики. Вам придется немного побороться с привилегиями, но на Windows XP и более ранних версиях он гарантированно будет работать на 100%. Я не уверен насчет Vista и пост-Vista, Рандомизация размещения адресного пространства может сделать это сложно.
Как только ваша 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()
двойники).
В качестве альтернативы вы можете исправить ваше приложение. Найти звонки MessageBeep
и перезаписать их nop
,
Не нужно тратить время на пользовательскую программу, чтобы сделать это.
Вы можете отключить звук определенного приложения, когда оно запущено, и этот параметр запомнится при следующем открытии приложения. Увидеть https://superuser.com/questions/37281/how-to-disable-sound-of-certain-applications.
Существует также Windows Sound Sentry, которая отключает большинство системных звуков, хотя я не знаю никаких настроек для каждого приложения для Sound Sentry.
Ты можешь использовать Deviare API hook и решить крюк в пару строк C #. Или вы можете использовать EasyHook, который немного сложнее и менее стабилен.