Вводная : Необходимо отсылать приложению клавиши. Защита приложения не позволяет этого делать, перехватывая NtUserSendInput - т.е. любые API нам не помогут (если без из?бств) Остаётся работать на уровне ядра и прикинуться железкой. Т.к. на компе была ps/2 клава и у заказчика приложения - аналогично, причём переход на usb не планировался - то решено имитировать PS/2, благо инфы в инете всё же есть (начать стоит с "i8042 controller refence manual" как-то так :-))
Работаем так (алгоритм выявлен с помощью этих документов и реверсинженеринга простого ассемблерного x86-драйвера (собственно, невозможность собрать его под x64 и вынудила меня тут извращаться) : Ждем пока 7-й (младший бит порта 64h) не выставится в 0. Теперь - пока 6-й. Запишем в 64h команду 0x0d2 (она заставит считать посланный байт пришедшим с клавы) Опять ждём установки 6-го байта в 0. Пишем в 60h скан-код имитируемой клавиши
Так проходимся по массиву скан-кодов (ВАЖНО : СКАН-КОДЫ И ВИРТУАЛЬНЫЕ КОДЫ - ДВЕ РАЗНЫЕ ВЕЩИ.) таблицу скан кодов приводить не буду - я за развитие навыков поиска информации, тем более - легкодоступной :-)
Попытки реализовать это из охренной библиотеки inpout32 не привели в лучшем случае ни к чему хорошему - т.к. какая-нибудь скотина в самый ответственный момент брала управление на себя и творила свои грязные делишки.
Т.е. было надо строить драйвер. Сперва я нашёл вот это :
Этот драйвер юзает KmdKit и masm32 - причём пойдёт не всякий masm. Я юзал тот что в Microsoft Visual Studio 2005 (не ржать :-) ).
Но под 64-битными ОС оно не пахало - и пришлось-таки изобретать велосипед, вспоминать университетский курс чистой сишки, и упарываться MSDN-ом.
Начнём с того, что нам нужен Windows DDK. И ещё крайне желательна утилита DebugView. Не бойтесь, всё бесплатно, пиратить не заставлю :-)
Когда всё скачено - пора перейти к кодингу.
Открой Windows DDK в меню пуск - дальше выбери платформу для компиляции (OS и архитектуру).
Если у тебя Windows x64 - сразу обрадую тем, что придётся попотеть чтобы отладить драйвер, ведь без сертификатов система вообще хер чего сделает. Ладно, не ссы, прорвёмся (и не трубы :-) )
Вот код драйвера на C :
Первая строка инклудит заголовки ntddk (да, я Кеп). Далее объявим макрос с именем устройства - для NT и для прочих.
Потом с синтаксим древнего C (не С99 явно) пойдёт сам драйвер. Сначала описываются функции, в том числе - DriverEntry - точка входа (там ОС и получает базовую инфу о файле), CtlCreate (создание коннекта с внешними миром), CtlClose - и так ясно из предыдщего, DriverUnload - тоже понятно и CtlDispatch - вот она-то нам и нужна для обмена
Из pIrpStack->Parameters.DeviceIoControl.IoControlCode мы получим, какой код управления нам кинули (если он равен IOCTL_WRITE, т.е. значению объявленного вверху макроса - обработаем данные).
С помощью Irp->AssociatedIrp.SystemBuffer мы получили указатель на переданные нам данные. А данные такие :
Во первых - каждое значение - 1 байт
Первый байт (у которого нулевой индекс) - число сканкодов для отсылки
Дальше - сами сканкоды
DbgPrint используется чтобы следить за состоянием из отладчика. Синтаксис аналогичен printf
Для чтения/записи в порты в HAL есть 3 группы функций : READ_PORT_UCHAR/WRITE_PORT_UCHAR, READ_PORT_USHORT/WRITE_PORT_USHORT и READ_PORT_ULONG/WRITE_PORT_ULONG. Они работают соответственно с 1,2 и 4 байтами. (КРАЙНЕ ВАЖНО! ПУТАНИЦА МОЖЕТ ПРИВЕСТИ ТЗИНЧ ЗНАЕТ К ЧЕМУ :-) )
Сам драйвер компилируется при помощи команды build из DDK.
Вот с сертификацией и установкой в ОС могут быть проблемы. Разберём по частям :
Если содавать программно с помощью CreateService и прочих - при вылете прога не удалит службу и в дальнейшем не сможет приконнектиться без траблов
В Windows 7 x64 неподписанный драйвер не запустить. Нужен хотя бы самописный сертификат
Так что для первого я приюзал 2 *.bat-файла - driver/install.bat, driver/remove.bat
Вот код установщика. Тут всё ясно, но что за dseo13b.exe? А эта программа впишет самописный сертификат. Гулится вполне легко. Есть и иные способы (гуглите по "подписание драйверов windows 7 x64")
Ну, а деисталлятор - тупо первые строки отсюда, удаляющие службу и файл
Вот пример на дельфи.
Он тупо ждём 2.5 секунды, а потом шлёт клавишу Enter (скан код указан дважды - для нажатой codes[1] и отжатой codes[2]. Второй можно получить, добавив 128 к первому)