Данный опус является переводом статьи из
летнего, 59-ого выпуска журнала Phrack. Я вполне
допускаю, что в нее могли закрасться некие
неточности, поэтому в случае возникновения
вопросов обращайтесь к оригиналу: http://www.phrack.org/show.php?p=59&a=14.
Ну, понеслась.

Как работает драйвер клавиатуры

Согласись, для того что бы написать
грамотный keylogger нужно знать, каким образом
нажатие клавиши на клавиатуре
регистрируется в системе. Смотри схему:

handle_scancode -> put_queue -> tty_queue -> receive_buf ->
буфер tty_ldisc -> tty_read -> /dev/ttyX -> sys_read ->
процесс пользователя

Сначала, когда вы нажимаете клавишу на
клавиатуре, устройство посылает
соответствующий скан код клавиши
клавиатурному драйверу. Единичное нажатие
может произвести последовательность до
шести кодов. Функция handle_scancode() в
клавиатурном драйвере обрабатывает поток
кодов и конвертирует их (при помощи функции
перевода kbd_translate()) в серию событий типа "клавиша
нажата", "клавиша отпущена". 
Каждый баттон имеет свой уникальный код от 1
до 127. Нажатие клавиши генерирует этот код, а
отпускание — этот код + 128 (например когда вы
нажимаете ‘a’ то на гора выдается код 30, а
когда отпускаете — 158).

Дальше код клавиши в соответствии с
картой клавиш конвертится обратно в сам
символ (вообще говоря при этом учитываются
нажатые функциональные клавиши — Shift , AltGr,
Control, Alt, ShiftL, ShiftR, CtrlL и CtrlR, комбинации
активных "модификаторов" — CapsLock
например) и передается по цепочке буферов и
очередей к терминалу.

Драйвер клавиатуры может работать в
четырех режимах:

  • scancode (RAW MODE): приложенице получает
    сканкод из потока и дальше обрабатывает
    его собственным драйвером (пример тому — Х11).

  • keycode (MEDIUMRAW MODE): программа получает код
    клавиши, переведенный из скан кода
    драйвером в соответствии с собственной
    таблицей.

  • ASCII (XLATE MODE): код клавиши преобразуется в
    ASCII-код символа или некоторую
    последовательность ASCII-кодов символов в
    соответствии с таблицей раскладки
    клавиатуры, которая хранится в памяти/диске
    виде отдельного файла (можно поменять
    раскладку клавиатуры командой kbdconfig, она
    прописывает новое значение в файл /etc/sysconfig/keyboard
    и загружает указанную таблицу в
    оперативную память).

  • Unicode (UNICODE MODE): этот режим отличается от
    предыдущего другим форматом вывода
    символов — UTF8, а не ASCII.

Эти режимы в конце концов и определяют,
что приложение получит в результате
нажатия клавиши. (Кстати говоря: режим
работы драйвера клавиатуры можно узнать
или изменить с помощью kbd_mode(). Но
помни! Смена режима может вообще оставить
тебя без клавиатуры!)

Kernel based keylogger

В общем говоря, мы можем перехватить поток
кодов двумя способами: написать обработчик
прерывания клавиатуры или вмешаться в
передачу на одном из описанных выше этапов.

Обработчик прерывания

Гляди как реализуется первый вариант. В
архитектуре Intel для контроллера клавиатуры
выделено первое прерывание. Когда оно
возникает наш обработчик должен прочитать
сканкод и статус клавиатуры. События
клавиатуры можно получить на 0х60 порту (Keyboard
data register), а ее состояние — на 0х64 (Keyboard status
register).

/* below code is intel specific */
#define KEYBOARD_IRQ 1
#define KBD_STATUS_REG 0x64
#define KBD_CNTL_REG 0x64
#define KBD_DATA_REG 0x60
#define kbd_read_input() inb(KBD_DATA_REG)
#define kbd_read_status() inb(KBD_STATUS_REG)
#define kbd_write_output(val) outb(val, KBD_DATA_REG)
#define kbd_write_command(val) outb(val, KBD_CNTL_REG)
/* register our own IRQ handler */
request_irq(KEYBOARD_IRQ, my_keyboard_irq_handler, 0, "my keyboard",
NULL);

В my_keyboard_irq_handler():

scancode = kbd_read_input();
key_status = kbd_read_status();
log_scancode(scancode);

Этот обработчик канает только для
архитектуры Intel, так что в случае переноса
на другую платформу он работать
естественно не будет. Хотя, честно говоря,
где ты у нас видел другие платформы…

Замена функций

Это начальная функция драйвера
клавиатуры (keyboard.c), она обрабатывает скан
коды, получаемые от клавиатуры:

# /usr/src/linux/drives/char/keyboard.c
void handle_scancode(unsigned char scancode, int down);

Мы можем заменить настоящий handle_scancode()
собственной процедурой, которая помимо
всего прочего будет записывать коды клавиш.

(Продолжение следует)

Оставить мнение

Check Also

Атака NFCdrip использует NFC для передачи данных на сравнительно дальние дистанции

Исследователь продемонстрировал, что NFC можно использовать в преступных целях и на сравни…