Перехват буфера обмена на Ассемблере
Перехват буфера обмена на Ассемблере
Сегодня разберем интересную тему - перехват буфера обмена. Применений этому перехвату можно найти много: менеджеры буфера обмена, хранящие последние несколько скопированных текстов; программы, выполняющие заданные действия, если в буфере обмена появилось кодовое слово; кейлоггеры, перехватывающие пароли и тексты пользователя; одно время были популярны трояны, подменяющие в буфере обмена номера электронных кошельков на свои собственные. Область применения любой технологии, как обычно, ограничивается только вашей фантазией. Но это все лирика, пора переходить к программированию.
Для того, чтобы ваше приложение узнавало об изменении содержимого буфера обмена, оно должно встроиться в цепочку обработчиков буфера обмена ("наблюдателей"). Существует два основных способа это сделать. Первый способ поддерживается операционными системами от Windows 2000 и выше, он основан на использовании функции SetClipboardViewer.
Code (Assembler) : Убрать нумерацию
- wm_init:
- ; Добавить наше окно в список наблюдателей
- invoke SetClipboardViewer, [hwnddlg]
- mov [hNextW], eax
- ...
- wm_close:
- ; Убрать наше окно из списка наблюдателей
- invoke ChangeClipboardChain, [hwnddlg], [hNextW]
- ...
Code (Assembler) : Убрать нумерацию
- ; Отправить сообщение следующему окну
- invoke SendMessage, [hNextW], WM_DRAWCLIPBOARD, 0, 0
Code (Assembler) : Убрать нумерацию
- ; Удаляется известное нам окно?
- mov eax,[wparam]
- cmp eax,[hNextW]
- jne unknown_handle
- ; Запомнить новый хэндл следующего обработчика
- mov eax,[lparam]
- mov [hNextW],eax
Code (Assembler) : Убрать нумерацию
- unknown_handle:
- ; Передать сообщение следующему окну
- invoke SendMessage, [hNextW], WM_CHANGECBCHAIN, [wparam], [lparam]
Второй, более современный способ, доступен в операционных системах, начиная с Windows Vista. Здесь используется функция AddClipboardFormatListener.
Code (Assembler) : Убрать нумерацию
- wm_init:
- ; Добавить наше окно в список наблюдателей
- invoke AddClipboardFormatListener,[hwnddlg]
- ...
- wm_close:
- ; Убрать наше окно из списка наблюдателей
- invoke RemoveClipboardFormatListener,[hwnddlg]
- ...
Третий способ основан на использовании функции GetClipboardSequenceNumber. Она возвращает текущий номер буфера обмена. В документации он почему-то назван "серийным номером", но при чем тут "серийный" я не совсем понял. При любом изменении буфера обмена, а также при его очистке, этот номер увеличивается на единичку. Соответственно, отслеживая изменения этого номера, можно получать информацию, что содержимое буфера обмена изменилось и его можно запросить. Опрос производится по таймеру:
Code (Assembler) : Убрать нумерацию
- cmp [msg],WM_TIMER
- je wm_timer
- ...
- wm_timer:
- ; Получить текущее значение счетчика
- invoke GetClipboardSequenceNumber
- cmp eax,[clip]
- ; Значение не изменилось
- je processed
- ; Сохранить новое значение
- mov [clip],eax
- ...
- wm_init:
- ; Получить текущий номер буфера обмена
- invoke GetClipboardSequenceNumber
- mov [clip],eax
- ; Установить таймер на интервал 1 мс
- invoke SetTimer,[hwnddlg],1,1,NULL
- ...
- wm_close:
- ; Убрать таймер
- invoke KillTimer,[hwnddlg],1
- ...
При написании статьи я попробовал одновременно запустить два приложения, одно из которых использует первый (старый) способ перехвата, а другой второй способ (новый). Как ни странно, в этом случае победил первый способ перехвата. Второму приложению не доставалось ничего до того момента, как было закрыто первое. Дальше я запустил параллельно две копии первого перехватчика, они оба отрабатывали перехват без каких-либо проблем. А вот при запуске двух копии приложения с новым перехватом, данные доставались только тому, которое было запущено позднее. Третий вариант работает всегда, независимо от количества и типа параллельных процессов. Такие дела.
Осталось выяснить еще один вопрос. Как узнать, что именно содержится в буфере обмена? Например, нас интересуют только текстовые строчки, а картинки и всякие эксельные таблицы должны пролетать мимо. Для этого есть функция IsClipboardFormatAvailable.
Code (Assembler) : Убрать нумерацию
- ; В буфере обмена находится текст?
- invoke IsClipboardFormatAvailable,CF_TEXT
- or eax,eax
- jz not_text
Просмотров: 7311 | Комментариев: 5
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(05.03.2021 в 11:53):
Добавил третий способ отслеживания через GetClipboardSequenceNumber. Статью дополнил, архив обновлен.
Марат
(24.08.2013 в 12:52):
...Спасибо Вам...
brute
(23.08.2013 в 20:04):
да стебусь я по случаю пятницы) Давно хотел на любимом PB переводчик в стиле QDictionary запилить(самодельные словари есть), поэтому статья весьма полезна!
ManHunter
(23.08.2013 в 19:46):
А зачем копировать текст из окна самой программы? Можно добавить проверку владельца окна, но это уже выходит за рамки примера.
brute
(23.08.2013 в 19:01):
первый пример не работает, если копировать текст из самого окна примера. Если запустить две копии первой программы и копировать текст в одной из них, то корректно отображает его только одна.. жаль, что второй пример на XP не запускается..:)
Добавить комментарий
Заполните форму для добавления комментария