USB Keylogger на AVR. Перехват нажатий клавиш USB клавиатуры
У меня возникла необходимость в некотором урезанном варианте KVM, для переключения USB клавиатуры с мышкой между компьютером и SmartTV на Андроиде. Готовые KVM меня не устроили т.к. мне не нужно было переключать видео сигнал, а главное, дешевые модели KVM для работы с USB клавиатурой не позволяли производить переключение по команде с клавиатуры а только кнопкой на самом устройстве. Для реализации такого устройства мне надо было перехватывать и анализировать нажатия клавиш и при появлении необходимой комбинации производить переключение между выходами.
Поиск в интернете дал много вариантов реализации захвата нажатий клавиш для PS/2 клавиатуры в рамках устройств, называемых кейлоггерами. Для USB клавиатуры я ничего подобного на нашел. Если не считать варианта воткнуть клавиатуру в USB-PS/2 переходник, а дальше действовать по налаженной схеме. Основным препятствием, насколько я понял, была сложность протокола USB по с равнению с PS/2. Поэтому пришлось разрабатывать такое устройство самому. Данное устройство не является законченным кейлогером готовым к использованию. Это шаблон, на основе которого можно разрабатывать устройства, которые требуют перехвата данных передаваемых по шине USB от периферийного устройства к компьютеру. Здесь показывается способ перехвата нажатых клавиш и дальнейшая их передача в компьютер по протоколу UART.
Аппаратная часть, использованная, для разработки представлена на фото.
Сверху вниз: приемник от беспроводной клавиатуры в качестве источника сигналов, макетная плата AVR-USB-MEGA16 для дешифровки сигналов, переходник UART-USB для передачи данных на компьютер для последующего анализа.
Схема включения является простейшей схемой включения AVR микроконтроллера с внешним кварцем. Частота кварца обязательно должна быть 12 МГц. Фьюзы указаны для ATMega32. Не знаю подойдут ли они для других контроллеров. LOW FUSE BYTE: 0xCF, HIGH FUSE BYTE: 0x18. Сигнал Dата+ шины USB должен быть подключен к выводу INT0 или INT1 контроллера, Dата- к любому другому выводу порта D. Используемые выводы настраиваются в файле usbconfig.h.
Клавиатура является низкоскоростным устройством работающим по стандарту USB 1.1 на скорости 1,5 Мб/с, т.е. сигнал передается на частоте 1,5 МГц. Описание протокола достаточно понятно описано в документе USB in a NutShell — путеводитель по стандарту USB. Так как сигнал передается на очень высокой скорости, то ля его захвата и анализа надо было писать часть программы на ассемблере. Во первых, я плохо знаком с ассемблером, а, во-вторых, уже существуют библиотеки для программной реализации USB интерфейса, которые в своем составе содержат модуль приема и обработки USB сигнала. Для своих целей я использовал библиотеку V-USB от компании OBJECTIVE DEVELOPMENT.
В результате получился данный проект созданный в Atmel Studio 6.1.
Данные захваченные с USB шины можно посмотреть любой терминальной программой (я использую PuTTY). Скорость подключения к COM порту 19200.
Проанализируем полученные данные. Для начала немного теории. Обмен между USB устройством ведется пакетами данных. Каждый пакет состоит из идентификатора пакета (PID) длиной 1-й байт и некоторых данных, зависящих от типа пакета. Обмен данными всегда инициализируется компьютером, т.е. компьютер сначала делает запрос на получение данных посылая пакет IN c PID = 0х69, а только затем устройство передает данные в пакете DATA0 PID=0xc3 DATA1 PID = 0x4b или не передает, если данных нет.
Соответственно каждая строка в логе представляет из себя пару из запроса на получение данных, и ответа с передаваемыми данными.
Запрос IN состоит из 3-х байт. 1-й это непосредственно идентификатор самого запроса. 2-й и 3-й байт содержат следующие данные: 7 бит – адрес устройства, получаемый им при подключении к шине, 4 бита – номер конечной точки и 5 бит контрольной суммы. Таким образом 2-й и 3-й байт запроса IN идентифицируют устройство, от которого будут получены данные. Так как я использовал составное устройство, то на логе видно, что обмен происходил с двумя устройствами: клавиатурой и мышью (отмечено желтой рамкой).
Запрос типа DATA состоит из 11 байт (фиолетовая рамка), из которых первый содержит идентификатор пакета, а два последних – контрольную сумму. Байты со 2-го по 9-й содержат 8 байт данных (оранжевая рамка). Информация в байтах данных распределяется следующим образом: 1-байт содержит данные о нажатии модификационных клавиш (Alt, Shift, Ctrl, Win), 2-й байт не используется, с 3-го по 8-й содержат скан-коды нажатых клавиш.
Распределение бит байта модификации
Бит 7 |
Бит 6 |
Бит 5 |
Бит 4 |
Бит 3 |
Бит 2 |
Бит 1 |
Бит 0 |
RightGUI |
RightAlt |
RightShift |
RightControl |
LeftGUI |
LeftAlt |
LeftShift |
LeftControl |
Так на обведенном синей рамкой отрезке видно, что первый байт данных равен 0х2 = 0b00000010, т.е. установлен бит 1, что соответствует нажатию клавиши LeftShift.
В простейшем случае (при нажатии и отпускании одной клавиши) обмен данными состоит из передачи трех пар пакетов IN-DATA. Первая передача возникает когда происходит нажатие клавиши и в 4-м байте из 11 байт пакета (или во 3-ем из 8 байт данных) содержится скан код нажатой клавиши. При отпускании генерируются две пары пакетов с нулевыми данными (почему две пары, я так и не понял, наверное документацию надо было лучше читать J).
При нажатии комбинации клавиш – все сложнее, насколько я понял при нажатии каждой последующей клавиши передаются скан-коды всех нажатых в данный момент клавиш в байтах с 4-го по 9-й и в модификационном байте. На логе обведено малиновой рамкой. При отпускании какой либо клавиши, также передаются коды всех оставшихся нажатых клавиш. (Н
Таким образом анализируя принятые пакеты данных можно организовать реакцию устройства на нажатие определенных комбинаций или последовательностей. Если же хочется сделать законченное устройство, то, например, к выходам Rx Tx можно подсоединить BlueTooth модуль типа HC-06, и передавать не коды нажатых клавиш, а их символьное представление в соответствии с таблицей скан-кодов. Результат в таком случае можно просматривать на экране смартфона.
Ограничения.
Данная реализация устройства имеет существенные ограничения. Т.к. это устройство может работать только с протоколом LowSpeed USB 1.1, оно не будет работать, если клавиатура будет подключена к USB хабу, а устройство будет включено между хабом и компьютером. Это происходит из-за того, что обмен с хабом происходит уже по протоколу USB 2.0 или USB 1.1 FullSpeed. Частный случай этого, когда клавиатура содержит встроенный USB hub, тогда модуль клавиатуры подключается к компьютеру не напрямую, а через встроенный USB hub. Также при нажатии таких клавиш, как CapsLock, NumLock, ScrollLock, происходит перехват большего количества данных, т.к. данные передаются как от клавиатуры к компьютеру, так и наоборот. Нажатия мультимедийных клавиш также передаются в соответствии со своим протоколом, отличающимся от передачи обычных клавиш.
P.S. Кстати, само устройство типа KVM, о котором говорилось в начале статьи, будет опубликовано позднее, когда доделаю.
[Ссылки]