Kernelmode драйвер имитации дёргания мышкой и клавиатурой

Тема в разделе "WASM.NT.KERNEL", создана пользователем mcbain, 26 июн 2011.

  1. mcbain

    mcbain New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2008
    Сообщения:
    18
    Нужна помощь написания драйвера виртуальной клавиатуры и мышки (xp/vista/7), котороый мог бы имитировать движения мышкой, нажатия кнопок и клавиш клавиатуры, и который управлялся бы из userland. Фактически kernelmode драйвер я хочу сделать потому что как я понимаю это самый лучший способ чтобы добиться высокой сложности детекции что нажатия имитированы а не вызваны оборудованием?

    Собственно вопрос, может кто знает какой-нибудь подобный открытый проект, или хотя бы подобный, в котором можно было бы посмотреть код, скажем какой-нибудь открытый драйвер настоящей мышки который можно было бы модифицировать. С чего начать короче? Может какие-нибудь статьи именно про как драйвер мышки говорит системе что произошли события?

    FAQ здесь на сайте и Four-F статьи проштудировал, нужна инфа именно насчёт IO мышки и клавы.
     
  2. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Сам не пробовал, но думаю можно просто написать фильтр, который заполняет выходные структуры нужной информацией и завершает IRP.
     
  3. assorted

    assorted New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2006
    Сообщения:
    227
    Только что тему создал с подробным описанием проблем. WDM виден в устройствах, а перехват - не дает завершить IRP что уже обрабатывается. После неуспешных эксперементов в этом направлении пошел иным путем.
     
  4. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    В RIT сообщения доставлять - проще и лучше ничего нет. IRP фильтруется всем, чем тока можно.
     
  5. mcbain

    mcbain New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2008
    Сообщения:
    18
    Хотя бы примерно как?

    Вот тут http://www.securelist.com/en/analysis/204792178/Keyloggers_Implementing_keyloggers_in_Windows_Part_Two написано что драйвера мышки общаются с драйвером класса мышки посредстов callback функций (хотя может так было только в 9x). Нельзя просто вызвать эту функцию из моего драйвера?

    Если я правильно понимаю, IRP используются чуть выше уровнем, между RIT и class driver, так если бы найти эту функцию из class driver которую должен вызывать драйвер конкретной мыши, то можно было бы обойти все эти проблемы над которыми assorted бьётся?

    Этот факт помогает мне или наоборот?



    UPDATE:
    Похоже это вот эта функция
    http://msdn.microsoft.com/en-us/library/ff542324(v=vs.85).aspx
    пока не разобрался совсем, но вопрос в том нельзя ли прямо её вызывать и через неё инъецировать все события? Сработает?
    assorted, ты это уже пробовал? По идее эта функция приводит как раз к завершению висяшего IRP запроса?
     
  6. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Интереса ради сделал нечто подобное. Результат -- 50/50. С одной стороны работает -- текущее окно получает букву "a", с другой, почему-то виснет все. Почему виснет клавиатура я понимаю, но почему весь остальной интерфейс, например, нажатие мышкой на кнопку просто не работает, пока не ясно. Если кто знает ответ -- скажите, будет интересно. Ну и код не ругайте, написано на коленке:

    Код (Text):
    1. #include <ntddk.h>
    2. #include <ntddkbd.h>
    3.  
    4. typedef struct _DEVICE_EXTENSION
    5. {
    6.     PDEVICE_OBJECT NextLowerDevice;
    7. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
    8.  
    9. PDEVICE_OBJECT FltDeviceObject;
    10.  
    11. USHORT MakeBreak = KEY_MAKE;
    12.  
    13. NTSTATUS IrpMjPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
    14. {
    15.     PDEVICE_EXTENSION DeviceExtension;
    16.  
    17.     PoStartNextPowerIrp(Irp);
    18.  
    19.     IoSkipCurrentIrpStackLocation(Irp);
    20.  
    21.     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject ->DeviceExtension;
    22.  
    23.     return PoCallDriver(DeviceExtension ->NextLowerDevice, Irp);
    24. }
    25.  
    26. NTSTATUS IrpMjRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
    27. {
    28.     LARGE_INTEGER        Delay;
    29.     PKEYBOARD_INPUT_DATA Key;
    30.  
    31.     Delay.QuadPart = -(10 * 1000 * 1000);
    32.  
    33.     KeDelayExecutionThread(UserMode, TRUE, &Delay);
    34.  
    35.  
    36.     Key = (PKEYBOARD_INPUT_DATA)Irp ->AssociatedIrp.SystemBuffer;
    37.  
    38.     RtlZeroMemory(Key, sizeof(KEYBOARD_INPUT_DATA));
    39.  
    40.     Key ->UnitId = 0x0;
    41.  
    42.     Key ->MakeCode = 0x1E;
    43.  
    44.     Key ->Flags = MakeBreak;
    45.  
    46.     if (MakeBreak == KEY_MAKE)
    47.     {
    48.         MakeBreak = KEY_BREAK;
    49.     }
    50.     else
    51.     {
    52.         MakeBreak = KEY_MAKE;
    53.     }
    54.    
    55.  
    56.     Irp ->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
    57.  
    58.     Irp ->IoStatus.Status = STATUS_SUCCESS;
    59.  
    60.     IoCompleteRequest(Irp, IO_NO_INCREMENT);
    61.  
    62.     return STATUS_SUCCESS;
    63. }
    64.  
    65. NTSTATUS IrpMjDefault(PDEVICE_OBJECT DeviceObject, PIRP Irp)
    66. {
    67.     PDEVICE_EXTENSION DeviceExtension;
    68.  
    69.     IoSkipCurrentIrpStackLocation(Irp);
    70.  
    71.     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject ->DeviceExtension;
    72.  
    73.     return IoCallDriver(DeviceExtension ->NextLowerDevice, Irp);
    74. }
    75.  
    76. NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath)
    77. {
    78.     SIZE_T            i;
    79.     NTSTATUS          status;
    80.     UNICODE_STRING    NextLowerDeviceName;
    81.     PDEVICE_OBJECT    NextLowerDeviceObject;
    82.     PFILE_OBJECT      NextLowerDeviceFileObject;
    83.     PDEVICE_EXTENSION DeviceExtension;
    84.  
    85.     for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
    86.     {
    87.         DriverObject ->MajorFunction[i] = IrpMjDefault;
    88.     }
    89.     DriverObject ->MajorFunction[IRP_MJ_READ] = IrpMjRead;
    90.     DriverObject ->MajorFunction[IRP_MJ_POWER] = IrpMjPower;
    91.  
    92.     status = IoCreateDevice(DriverObject,
    93.                             sizeof(DEVICE_EXTENSION),
    94.                             NULL,
    95.                             FILE_DEVICE_KEYBOARD,
    96.                             0,
    97.                             TRUE,
    98.                             &FltDeviceObject);
    99.  
    100.     if (!NT_SUCCESS(status))
    101.     {
    102.         goto LocRetNoDev;
    103.     }
    104.  
    105.     FltDeviceObject ->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
    106.     FltDeviceObject ->Flags &= ~DO_DEVICE_INITIALIZING;
    107.  
    108.  
    109.     RtlInitUnicodeString(&NextLowerDeviceName, L"\\Device\\KeyboardClass0");
    110.  
    111.     status = IoGetDeviceObjectPointer(&NextLowerDeviceName,
    112.                                       GENERIC_READ,
    113.                                       &NextLowerDeviceFileObject,
    114.                                       &NextLowerDeviceObject);
    115.     if (NT_SUCCESS(status))
    116.     {
    117.         DeviceExtension = FltDeviceObject ->DeviceExtension;
    118.  
    119.         DeviceExtension ->NextLowerDevice =
    120.             IoAttachDeviceToDeviceStack(FltDeviceObject,
    121.                                         NextLowerDeviceObject);
    122.  
    123.         if (DeviceExtension ->NextLowerDevice == NULL)
    124.         {
    125.             status = STATUS_UNSUCCESSFUL;
    126.         }
    127.         else
    128.         {
    129.             ObDereferenceObject(NextLowerDeviceObject);
    130.         }
    131.     }
    132.  
    133. LocRetNoDev:
    134.     return status;
    135. }
     
  7. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Думаю, здесь есть всё, что тебе нужно. Терминология такая: функциональный драйвер (function driver) - драйвер непосредственно железки, обрабатывает прерывания и всё такое (именно этот драйвер вызывает колбек-функцию с данными из своей ISR), драйвер класса (class driver) - соответственно, драйвер целого класса устройств (клавиатура/мышь в данном случае), отвечает за передачу данных в CSR (там вечный IRP_MJ_READ висит, схема передачи данных наверх называется inverted calls), фильтрующий драйвер (filter driver) - драйвер, расположенный между первыми двумя драйверами. Вкратце, схема такая: классовый драйвер отсылает connect-запрос функциональному драйверу, в котором передаёт адрес своей колбек-функции (поле CONNECT_DATA.ClassService), тот сохраняет её у себя и впоследствии вызывает в своей ISR для передачи данных дальше. Перехватив этот колбек, ты сможешь менять данные как угодно. Основная сложность здесь это подключиться (attach device) в стек к функциональному драйверу, особенно следует учесть, что он может быть не один. Исходники конкретных примеров ищи в гугле, например, по имени connect I/O запроса.

    Это первый вариант. Второй вариант несколько проще: подключиться к девайсам классового драйвера (ну это которые \Device\KeyboardClass0, \Device\PointerClass0 и т.д.), там уже будешь ловить Read-запросы от CSR непосредственно. Подменять данные можно в своей функции завершения (completion routine), которую необходимо вешать на каждый приходящий Read-запрос. Но тут следует помнить, что если ты подключаешься в стек к классу уже после загрузки системы, то как минимум один отложенный IRP ты рискуешь пропустить. Хотя, в общем-то, я не вижу в этом большой проблемы, откровенно говоря. Я так понимаю, это именно та проблема, над которой бился assorted. Мне было бы интересно услышать, почему он считает это проблемой? Кстати, в WDK есть исходники нескольких драйверов по теме, в частности, \src\input\kbdclass, это поможет тебе лучше узнать, как это всё работает изнутри.
     
  8. mcbain

    mcbain New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2008
    Сообщения:
    18
    Ого, прикольно. А виснет насовсем или пока оно не отпустит клавишу?
    Я как нуб не стану комментировать код, профи лучше будет видно но может попробовать вместо IRP функций просто вызвать

    KeyboardClassServiceCallback

    Единственное что нужно это PDEVICE_OBJECT, а он у тебя уже есть (хотя не знаю тот ли это который нужен):

    Код (Text):
    1.     RtlInitUnicodeString(&NextLowerDeviceName, L"\\Device\\KeyboardClass0");
    2.  
    3.     status = IoGetDeviceObjectPointer(&NextLowerDeviceName,
    4.                                       GENERIC_READ,
    5.                                       &NextLowerDeviceFileObject,
    6.                                       &NextLowerDeviceObject);
    К примеру вот здесь у чувака вроде получилось: http://www.osronline.com/showThread.CFM?link=113470


    (Я конечно и сам попробую, пока сначала изучаю, даже среда ещё не настроена)
     
  9. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Частая ошибка у новичков.
     
  10. mcbain

    mcbain New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2008
    Сообщения:
    18
    x64, раз уж ты тут, спасибо за инфу, что думаешь о моём посте #8?
    Единственная разница с тем что ты написал это что мне нужно подключиться в стек к драйверу. Зачем это нужно делать? Он иначе не примет KeyboardClassServiceCallback?

    Да, непосредственно откуда всё это вызывать? У меня план либо повесить таймер 100 раз в секунду, либо сразу когда мой юзерлэнд поток будет говорить с моим драйвером. Реально?

    Кстати интересно, \\Device\\KeyboardClass0, их может быть несколько? Или просто так называется (0)?
     
  11. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    В первом варианте, который я описывал выше, подключиться в стек к функциональному драйверу необходимо, чтобы перехватить connect-запрос. Больше ничего не нужно, данные затем перехватываешь в колбеке уже. Во втором варианте подключаться в стек опять же нужно, чтобы перехватывать завершение Read-запросов с данными и менять их там, при необходимости. Там, во втором варианте, только одно ограничение: не получится инжектировать свои данные сразу же после запуска драйвера, - либо ждёшь очередного Read-запроса, либо перезагружаешь систему и только после этого твой фильтр начинает работать.

    Что вызывать?
    О чём речь вообще?

    Что за ересь?
    Забудь об этой хрени.

    Да, вполне. Шлёшь своему драйверу I/O-запрос какой-нибудь, хоть Device I/O, хоть просто Write обычный, в буферах передаёшь новые данные, твой драйвер сохраняет их где-нибудь в очереди своей внутренней, ну и в подходящий момент подставляет эти данные куда нужно, либо сразу в колбек (вариант #1), либо ждёт вызова функции завершения и там меняет содержимое буферов в IRP (вариант #2).

    Да, как правило, сколько реальных железок, столько и этих девайсов.
     
  12. assorted

    assorted New Member

    Публикаций:
    0
    Регистрация:
    7 авг 2006
    Сообщения:
    227
    Так, собсвтенно, это и есть проблема. Очередной IRP_MJ_READ можно ждать бесконечно. А после перезагрузки нужно обеспечить чтобы фильтр установился в тот момент, когда PointerClass0 уже создался, но IRP_MJ_READ еще не приходил. Как это обеспечить?
     
  13. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Ответил там.
     
  14. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    x64
    Ага, спасибо, проморгал.

    mcbain
    Насчет той ф-ии ничего сказать не могу -- ни разу не использовал.

    all
    А почему интерфейс на мышку не реагирует? VM пришлось кнопкой перезагружать...
     
  15. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Может как раз потому что проморгал? Код исправлял?
    А так хрен тебя знает, в отладчике смотреть надо, что висит.
    Сделай дамп памяти ядра во время зависания, выложи сюда, глянем.
     
  16. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Нет, код еще исправить не успел. Вечером попробую.
     
  17. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Исправил, попробовал, эффект тот же. Здесь minidump.
     
  18. Llirik

    Llirik Member

    Публикаций:
    0
    Регистрация:
    18 июл 2008
    Сообщения:
    468
    А если мышей вообще callback в mouclass будет работаеть? И mcbain, если у Вас USB-клава, то к \\Device\\KeyboardClass0 Вы не подключитесь.
     
  19. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Я не просил минидамп.
     
  20. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Наркоман, что ле?

    Да ну?
    С чего бы это?