Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Как получить список устройств ввода

26.06.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter

Как получить список устройств ввода

Как узнать, подключена ли к компьютеру клавиатура и/или мышь? Ответить на этот вопрос можно путем перечисления всех подключенных системных устройств ввода при помощи функции GetRawInputDeviceList. Она позволяет получить список идентификаторов и типов устройств ввода, а на основании идентификатора при помощи функции GetRawInputDeviceInfo можно узнать об этом устройстве более детальную информацию.

Читать статью целиком »
Просмотров: 853 | Комментариев: 8

Эмуляция нажатия мультимедийных клавиш на клавиатуре

18.06.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
В статье про обработку мультимедийных кнопок я немного коснулся эмуляции их нажатий. Там эмуляция была направлена напрямую в оболочку, сейчас же я расскажу, как выполнять такое действие полноценно, с учетом интересов всех запущенных приложений. Начнем с эмуляции пользовательского ввода с помощью функции SendInput.

При всей моей любви к FASM, просто убивает скудность его инклудов. Похоже, что наполнение их данными остановилось на Win2000, а если захочется что-нибудь чуть новее, то все, добро пожаловать в MSDN. И хорошо, если структура окажется на пять-десять записей. Вот и сейчас нам придется самостоятельно описать структуру INPUT и обозначить коды мультимедийных клавиш.
  1. struct MOUSEINPUT
  2.         dx          dd ?
  3.         dy          dd ?
  4.         mouseData   dd ?
  5.         dwFlags     dd ?
  6.         time        dd ?
  7.         dwExtraInfo dd ?
  8. ends
  9.  
  10. struct KEYBDINPUT
  11.         wVk         dw ?
  12.         wScan       dw ?
  13.         dwFlags     dd ?
  14.         time        dd ?
  15.         dwExtraInfo dd ?
  16. ends
  17.  
  18. struct HARDWAREINPUT
  19.         uMsg        dd ?
  20.         wParamL     dw ?
  21.         wParamH     dw ?
  22. ends
  23.  
  24. struct INPUT
  25.         type        dd ?
  26.         union
  27.             mi      MOUSEINPUT
  28.             ki      KEYBDINPUT
  29.             hi      HARDWAREINPUT
  30.         ends
  31. ends
  32.  
  33. INPUT_KEYBOARD = 1
  34.  
  35. VK_VOLUME_UP   = 0xAF
  36. VK_VOLUME_DOWN = 0xAE
  37. VK_LAUNCH_APP2 = 0xB7
Структура INPUT задана через union, так как в зависимости от типа использования, внутри нее будет структура с разным количеством и разрядностью полей. В нашем случае будет эмуляция только клавиатурного ввода, но на будущее могут пригодиться и другие структуры.

Читать статью целиком »
Просмотров: 615 | Комментариев: 2

Получение информации о заголовке окна

12.06.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Манипулировать кнопками в заголовке окна мы уже научились. А как узнать, какие кнопки отображаются в заголовке окна и в каком они состоянии? Конечно, можно пройтись по стилям, по меню, но правильнее будет воспользоваться следующей информацией. Мне кажется, она станет хорошим дополнением к статье об управлении кнопками в заголовке окна.

Для получения подробной информации о заголовке окна ему отправляется сообщение WM_GETTITLEBARINFOEX. Если все прошло успешно, на выходе получается заполненная структура TITLEBARINFOEX, в которой содержится информация о позициях и состоянии кнопок в заголовке окна, а также о размере самого заголовка.

Сперва надо описать структуру TITLEBARINFOEX и несколько констант, так как FASM в базовой комплектации о них не знает. Скорее всего это потому, что сообщение WM_GETTITLEBARINFOEX поддерживается только в Windows Vista и выше.
  1. struct TITLEBARINFOEX
  2.         cbSize        dd ?
  3.         rcTitleBar    RECT
  4.         stateTitleBar dd ?
  5.         sReserved1    dd ?
  6.         stateMinimize dd ?
  7.         stateMaximize dd ?
  8.         stateHelp     dd ?
  9.         stateClose    dd ?
  10.         rReserved0    RECT
  11.         rReserved1    RECT
  12.         rectMinimize  RECT
  13.         rectMaximize  RECT
  14.         rectHelp      RECT
  15.         rectClose     RECT
  16. ends
  17.  
  18. WM_GETTITLEBARINFOEX     = 0x033F
  19.  
  20. STATE_SYSTEM_FOCUSABLE   = 0x00100000
  21. STATE_SYSTEM_INVISIBLE   = 0x00008000
  22. STATE_SYSTEM_OFFSCREEN   = 0x00010000
  23. STATE_SYSTEM_UNAVAILABLE = 0x00000001
  24. STATE_SYSTEM_PRESSED     = 0x00000008
При описании TITLEBARINFOEX я немного отошел от MSDN'овского описания, там состояния и координаты описаны шестиэлементными массивами, а я для удобства работы дал им осмысленные имена вместо числовых индексов. Сути это не меняет, размера структуры тоже.

Читать статью целиком »
Просмотров: 515 | Комментариев: 0

Как программно создать ярлык

08.06.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Ярлыки - одна из ключевых сущностей Windows. Это специальные файлы, служащие указателями на папки, программы или команды. Для управления ярлыками в Windows используется COM-объект ShellLink, точнее одна версия для ANSI и вторая для юникода. Они отличаются своими GUID. В любом из этих объектов реализовано по два интерфейса. Интерфейс IShellLink, с помощью которого можно получать и изменять свойства ярлыка, и интерфейс IPersistFile для работы непосредственно с самим файлом ярлыка.

Для доступа к COM-объектам первым делом надо обозначить их GUID:
  1. ; GUID {00021401-0000-0000-C000-000000000046}
  2. CLSID_ShellLink    dd 00021401h
  3.                    dw 0000h
  4.                    dw 0000h
  5.                    db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  6.  
  7. ; GUID {000214F9-0000-0000-C000-000000000046}
  8. IID_IShellLinkW    dd 000214F9h
  9.                    dw 0000h
  10.                    dw 0000h
  11.                    db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  12.  
  13. ; GUID {0000010B-0000-0000-C000-000000000046}
  14. IID_IPersistFile   dd 0000010Bh
  15.                    dw 0000h
  16.                    dw 0000h
  17.                    db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
Теперь надо описать интерфейсы, я сделаю это в виде структур, чтобы не путаться с индексами вызываемых методов. В одной из статей я уже отмечал, что на сайте MSDN названия методов идут не в том порядке, как они фактически представлены в интерфейсе. Не обошла проблема нестыковки и эти интерфейсы.
  1. ; IID_IShellLinkW Interface
  2. struct IShellLinkWDispatch
  3.     QueryInterface      dd ?
  4.     AddRef              dd ?
  5.     Release             dd ?
  6.  
  7.     GetPath             dd ?
  8.     GetIDList           dd ?
  9.     SetIDList           dd ?
  10.     GetDescription      dd ?
  11.     SetDescription      dd ?
  12.     GetWorkingDirectory dd ?
  13.     SetWorkingDirectory dd ?
  14.     GetArguments        dd ?
  15.     SetArguments        dd ?
  16.     GetHotkey           dd ?
  17.     SetHotkey           dd ?
  18.     GetShowCmd          dd ?
  19.     SetShowCmd          dd ?
  20.     GetIconLocation     dd ?
  21.     SetIconLocation     dd ?
  22.     SetRelativePath     dd ?
  23.     Resolve             dd ?
  24.     SetPath             dd ?
  25. ends
  26.  
  27. ; IID_IPersistFile Interface
  28. struct IPersistFileDispatch
  29.     QueryInterface      dd ?
  30.     AddRef              dd ?
  31.     Release             dd ?
  32.  
  33.     GetClassID          dd ?
  34.     IsDirty             dd ?
  35.     Load                dd ?
  36.     Save                dd ?
  37.     SaveCompleted       dd ?
  38.     GetCurFile          dd ?
  39. ends
Работа с ярлыком состоит из двух этапов. При создании ярлыка сперва надо назначить все его свойства, затем получить доступ к интерфейсу для работы с файлом ярлыка, а потом сохранить созданный ярлык в файл. Для обратной операции надо получить интерфейс для работы с файлами, прочитать файл ярлыка, а затем узнать его свойства.

Читать статью целиком »
Просмотров: 569 | Комментариев: 0

Управление редактором реестра из своего приложения

27.05.2020 | Категория: Образ мышления: Assembler | Автор: ManHunter
Наверняка вы слышали о программе RegJump от SysInternals, ныне принадлежащая Microsoft. При помощи этой программы вы можете открыть regedit сразу же на нужной ветке реестра. Мне стало очень интересно, как она это делает. Дизассемблер в руки, отладчик в боевую готовность и вперед!

Вот что мне удалось накопать. Я оставил только самый важный код, попутно упростив и оптимизировав его. Оригинальный RegJump сперва пытается найти запущенный regedit по наименованию класса окна, если такого нет, то пытается запустить regedit из системной папки. Так или иначе, вся работа выполняется с найденным окном. У меня подразумевается, что редактор реестра уже запущен.
  1. section '.data' data readable writeable
  2.  
  3. ; Классы окон для поиска
  4. szClass db 'RegEdit_RegEdit',0
  5. szList  db 'SysTreeView32',0
  6. ; Название ветки реестра
  7. szReg   db '\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\',0
Наименование ветки реестра, куда надо перейти, переводится в верхний регистр, а в начало и конец строки прицепляется символ "\". Традиционные сокращения типа "HKLM" разворачиваются в полноценные наименования веток реестра "HKEY_LOCAL_MACHINE" и т.п. Я надеюсь, с подобным преобразованием строки у вас проблем возникнуть не должно. У меня строка сразу приведена в должный вид.

Хэндл процесса необходим для синхронизации пользовательского ввода с окном приложения, поскольку все управление regedit выполняется через эмуляцию нажатий клавиш в списке. Для "своей" копии regedit, которая запущена RegJump, используется результат выполнения функции CreateProcess, для запущенного ранее экземпляра хэндл получается через пару функций GetWindowThreadProcessId и OpenProcess. Особых привилегий для этого не надо.
  1.         ; Найти окно редактора реестра
  2.         invoke  FindWindow,szClass,NULL
  3.         or      eax,eax
  4.         jz      loc_exit
  5.         mov     [hRWnd],eax
  6.  
  7.         ; Найти список в окне редактора реестра
  8.         invoke  FindWindowEx,[hRWnd],NULL,szList,NULL
  9.         or      eax,eax
  10.         jz      loc_exit
  11.         mov     [hWnd],eax
  12.  
  13.         ; Получить хэндл процесса-владельца
  14.         invoke  GetWindowThreadProcessId,[hRWnd],ProcessId
  15.         invoke  OpenProcess,PROCESS_QUERY_INFORMATION,0,[ProcessId]
  16.         or      eax,eax
  17.         jz      loc_exit
  18.         mov     [hProcess],eax
  19.  
  20.         ; Активировать окно редактора реестра
  21.         invoke  ShowWindow,[hRWnd],SW_RESTORE
  22.         invoke  SetForegroundWindow,[hRWnd]
  23.         ; Установить фокус на список
  24.         invoke  SetFocus,[hWnd]
  25.         invoke  WaitForInputIdle,[hProcess],-1
  26.  
  27.         ; Вот тут непонятно :(
  28.         invoke  SendMessage,[hRWnd],WM_COMMAND,10288h,0
  29.         invoke  WaitForInputIdle,[hProcess],-1
  30.  
  31.         ; Перейти на верхний уровень списка
  32.         mov     ebx,30
  33. @@:
  34.         invoke  SendMessage,[hWnd],WM_KEYDOWN,VK_LEFT,0
  35.         invoke  WaitForInputIdle,[hProcess],-1
  36.         sub     ebx,1
  37.         jnz     @b
  38.  
  39.         ; Указатель на строку в названием ветки реестра
  40.         mov     esi,szReg
  41. loc_loop:
  42.         lodsb
  43.         or      al,al
  44.         jz      loc_exit_clean
  45.  
  46.         cmp     al,'\'
  47.         jne     @f
  48.         ; Открыть ветку списка
  49.         invoke  SendMessage,[hWnd],WM_KEYDOWN,VK_RIGHT,0
  50.         invoke  WaitForInputIdle,[hProcess],-1
  51.         jmp     loc_loop
  52. @@:
  53.         movzx   eax,al
  54.         ; Поиск строки в списке
  55.         invoke  SendMessage,[hWnd],WM_CHAR,eax,0
  56.         invoke  WaitForInputIdle,[hProcess],-1
  57.         jmp     loc_loop
  58. loc_exit_clean:
  59.         invoke  CloseHandle,[hProcess]
  60.  
  61. loc_exit:
Когда все нужные окна найдены и хэндл процесса получен, начинается эмуляция нажатий клавиш. Сперва выполняется переход на самый верхний уровень списка. Судя по коду, Марк Руссинович предположил, что глубже 30-го уровня списка зайти невозможно, что ж, ему виднее. Затем начинается обработка строки с нужным названием ветки реестра. Строка обрабатывается посимвольно, когда встретится символ "\", то эмулируется нажатие стрелки вправо для открытия нужного уровня списка и перехода на него. Именно для этого исходная строка дополняется в начале и в конце этим символом. Строковые символы из строки передаются в поиск, тем самым определяя следующий уровень списка. Как видите, никаких ракетных технологий, но лично мне было очень интересно посмотреть на решение этой задачи от одного из признанных знатоков внутренностей Windows.

Читать статью целиком »
Просмотров: 681 | Комментариев: 6

01 ... 08 09 10 11 12 13 14 ... 51
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2021
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.18 сек. / MySQL: 3 (0.0595 сек.) / Память: 4.75 Mb
Наверх