Корректное исп-е семафора в драйвере
От: AviSergey  
Дата: 08.05.10 00:24
Оценка:
Доброго времени суток!
У меня имеется следующая проблема. Только начал разбираться с написанием драйверов, поэтому надеюсь на ваш более солидный опыт.

Один из модулей драйвера-фильтра, должен осуществлять анализ нжимаемых клавиш, поэтому подзадачей явл-ся написания подобия кейлоггера.
Создаваемый FDO-объект прикрепляется в цепочку устр-в классового драйвера KeyboardClass0. При получении моим драйвером IRP-пакета, регистрируется завершающая функция обратного вызова, к-я при прохождении пакета по стеку устр-в обратно и вызывается. Как известно, её вызов происходит на IRQL > PASSIVE_LEVEL, поэтому длительные операции обработки и анализа в ней производить нельзя. Для этого я передаю эти данные посредством очереди в анализирующий поток, работающий на PASSIVE_LEVEL, к-й их и производит. Для указания кол-ва эл-в в очереди используется семафор. В нем и собственно проблема:

Периодически(в зав-ти от интенсивности нажатия клавиш) на очередной попытке освобождения семафора получаем BSOD(DRIVER_IRQL_NOT_LESS_OR_EQUAL, STOP 0x000000D1) — попытка обратиться к страничной памяти, используя процесс ядра через IRQL высокого уровня. Объект семафора хранится в расширении данного FDO-объекта. То, что проблема в обращениях к семафору в т.ч. указывает работоспособность кода при коментировании вызова KeReleaseSemaphore() в в завершающей ф-и обр-го вызова. Насколько я понял KeReleaseSemaphore позволительно выз-ть на IRQL <= DISPATCH_LEVEL.
Прошу помочь разобраться с даннной проблемой. Спасибо.

Ниже привожу листинг функции обратного вызова:


NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pFDO, IN PIRP pIrp, IN PVOID Context)
{
    PKFILTER_DEVICE_EXTENSION dx = (PKFILTER_DEVICE_EXTENSION) pFDO->DeviceExtension;
    // В pIrp->AssociatedIrp.SystemBuffer содержится
    // адресс массива стр-р KEYBOARD_INPUT_DATA, а в
    // pIrp->IoStatus.Information его размер:
    PKEYBOARD_INPUT_DATA keys;
    int numKeys,i;    
    PKEY_DATA pkData;    // стр-ра, хранящая инфу об одном нажатии

    // Если запрос успешно обработан извлекаем инфу:
    if(pIrp->IoStatus.Status == STATUS_SUCCESS)
    {
        keys = (PKEYBOARD_INPUT_DATA) pIrp->AssociatedIrp.SystemBuffer;
        numKeys = pIrp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
    
        for(i=0; i<numKeys;i++)
        {
            DbgPrint("<KFilter >\t[OnReadCompletion]\t ScanCode= %x\n", keys[i].MakeCode);

            // Для размещения инф-и о нажатии выделяем небольшой
            // неперемещаемый пул памяти, к-й далее помещается в 
            // очередь:
            pkData = (PKEY_DATA) ExAllocatePool(NonPagedPool,sizeof(KEY_DATA));
            // Заполняем стр-ру полученной инф-ей о нажатии:
            pkData->kbd_inp_data = keys[i];
            // Добавляем инф-ю о нажатии в очередь, для
                        // её последующего извлечения анализирующим потоком:
            ExInterlockedInsertTailList(&(dx->QueueListHead),  // ук-ль на заголовок списка
                        &(pkData->listEntry),       // ук-ль на стр-ру LIST_ENTRY, вставляемого эл-та
                        &(dx->lockQueue));       // ук-ль на объект спин-блокировки для синхронизации доступа к списку
            // Увеличиваем счетчик семафора, отображая, что есть
            // событие для обработки в анализирующем потоке:
            KeReleaseSemaphore( &(dx->semQueue),0,1,TRUE);
            
        }
    }

    // Если необходима доп-я обработка - отмечаем:
    if(pIrp->PendingReturned)
        IoMarkIrpPending(pIrp);

    // Т.к. обработка нами IRP-пакета завершена, отмечаем это
    // уменьшив кол-во необработанных пакетов:
    dx->ulNumPendingIrps--;
    #ifdef _DEBUG
    DbgPrint("<KFilter >\t[DispatchRead]\t Count of Pending IRPs=%d.\n", dx->ulNumPendingIrps);
    #endif

    return pIrp->IoStatus.Status;

}


Описания стр-ры расширения устройства PKFILTER_DEVICE_EXTENSION и стр-ы, хранящей инфу о событии ввода KEY_DATA:



typedef struct _KFILTER_DEVICE_EXTENSION
{
    PDEVICE_OBJECT    pFDO;            // ук-ль на FDO-объект данного драйвера
    UNICODE_STRING    ustrSymLinkName;    // символьное Win32-имя данного драйвера
    PDEVICE_OBJECT  pTagFDO;        // ук-ль на след-е в цепочке устройство находящееся ниже данного фильтра
    PETHREAD    pThreadObj;        // ук-ль на объект анализирующего нажатия клавиш потока
    BOOLEAN        bThreadTerminate;    // флаг состояния потока(pThreadObj)
    LIST_ENTRY    QueueListHead;        // 
    KSPIN_LOCK    lockQueue;        // используется для синхронизации доступа к списку(очереди)
    KSEMAPHORE    semQueue;        // будет отображать кол-во эл-в(символов) в очереди
    BOOLEAN        bHookMode;        // флаг режима р-ты драйвера(TRUE-перехват событий ввода) 
    ULONG        ulNumPendingIrps;    // кол-во ожидающих завершения IRP-пакетов

} KFILTER_DEVICE_EXTENSION, *PKFILTER_DEVICE_EXTENSION;

// Стр-ру, представляющую собой 1 эл-т очереди
// событий ввода, к-я будет использоваться для передачи
// данных событий между процедурой OnReadCompletion, отлавливающей
// данные события, и анализирующим их потоком:
typedef struct _KEY_DATA
{
    KEYBOARD_INPUT_DATA kbd_inp_data;
    LIST_ENTRY listEntry;
} KEY_DATA, *PKEY_DATA;
Re: Корректное исп-е семафора в драйвере
От: AviSergey  
Дата: 08.05.10 01:37
Оценка:
Решение проблемы оказалось в 4-м пар-ре KeReleaseSemaphore. При зн-и FALSE вместо TRUE работа корректна.
Но теперь у меня появились сомнения, правильно ли я понимаю зн-е 2-го и 4-го аргумента данной функции.
Прошу пояснить?
Re[2]: Корректное исп-е семафора в драйвере
От: Геннадий Майко США  
Дата: 08.05.10 10:27
Оценка:
Здравствуйте, AviSergey,

AS>Решение проблемы оказалось в 4-м пар-ре KeReleaseSemaphore. При зн-и FALSE вместо TRUE работа корректна.

AS>Но теперь у меня появились сомнения, правильно ли я понимаю зн-е 2-го и 4-го аргумента данной функции.
--
1. Well, из приведенного выше текста сложно понять, что именно Вы не понимаете

Описание 4-го параметра достаточно подробно описано здесь.

Для понимания второго параметра, которые определяет priroty boost, просмотрите соответствующий раздел Priority Boost в главе Processes, Threads and Jobs известной книги Windows Internals, Russinovitch and Solomon.

2. А почему Вы используете semaphore, а не event?

С уваженим,
Генадий Майко
Re[3]: Корректное исп-е семафора в драйвере
От: AviSergey  
Дата: 08.05.10 18:47
Оценка:
Здравствуйте, Геннадий Майко.

Спасибо за ответ. С параметрами разобрался.

ГМ>2. А почему Вы используете semaphore, а не event?


Т.к кроме сигнализации анализирующему потоку о наличии события ввода в очереди, необходимо учитывать их кол-во. При испольлзовании event-a за время, возможно более длительной, операции обработки после вызова KeWaitFor*.. в очередь может поступить несколько новых эл-в, а след-й вызов KeWaitFor*.. сбросит event в несигнальное состояние, в рез-те вместо обработки всех поступивших будет обработано только первое.
Re[4]: Корректное исп-е семафора в драйвере
От: shrecher  
Дата: 08.05.10 19:51
Оценка: +1
Здравствуйте, AviSergey, Вы писали:

AS>Здравствуйте, Геннадий Майко.


AS>Спасибо за ответ. С параметрами разобрался.


ГМ>>2. А почему Вы используете semaphore, а не event?


AS>Т.к кроме сигнализации анализирующему потоку о наличии события ввода в очереди, необходимо учитывать их кол-во. При испольлзовании event-a за время, возможно более длительной, операции обработки после вызова KeWaitFor*.. в очередь может поступить несколько новых эл-в, а след-й вызов KeWaitFor*.. сбросит event в несигнальное состояние, в рез-те вместо обработки всех поступивших будет обработано только первое.


Это решается с помощью цикла, псевдокод

ThreadHandler:

do
{
wait(event); // should be auto reset even
while( pickItemFromQueue() )
{
// process item
}

}while(1);
Re[5]: Корректное исп-е семафора в драйвере
От: AviSergey  
Дата: 09.05.10 14:46
Оценка:
Здравствуйте, shrecher.

Ничего против такой реализации не имею.
Вариант на основе семафора мне так же кажется удовлетворительным.

Сейчас наращиваю проект, и след-м подэтапом необходим фильтр мыши. Попробывал сделать аналогично фильтру клавиатуры. Присоединил свой FDO-объект к цепочке устройств PointerClass0. Однако, даже при регистрации всех MajorFunction на одну функцию обработки в драйвер не один IRP-пакет от мыши не поступает. В DeviceTree созданное устр-во, добавленное к PointerClass0 отображаетя.

Поиск по Net-у четких рез-в не дал. Посредством каких пакетов при взаимодействии диспетчера ввода/вывода и драйвером mouclass передается инф-я о событии ввода (стр-ра MOUSE_INPUT_DATA)? И самое главное в чем может быть причина того что созданный FDO-объект фильтра мыши не получает IRP?

Надеюсь на ваши ответы. Спасибо.
Re[6]: Корректное исп-е семафора в драйвере
От: shrecher  
Дата: 09.05.10 15:02
Оценка: +1
Здравствуйте, AviSergey, Вы писали:

AS>Надеюсь на ваши ответы. Спасибо.


Есть же пример в WDK: src\input\moufiltr.
Re[7]: Корректное исп-е семафора в драйвере
От: AviSergey  
Дата: 09.05.10 17:08
Оценка:
Здравствуйте, shrecher, Вы писали:

S>Есть же пример в WDK: src\input\moufiltr.


Спасибо за наводку. Пример рассмотрю.
Беглый взгляд на данный код зародил пару вопросов:
1) Как я понял реализация перехвата осущ-ся посредством установки фильтра поверх безымянного устройства, создаваемого функциональным драйвером i8042prt под устройством Device\PointerClass0. Насколько мне известно, буду рад если я ошибаюсь, драйвер i8042prt обрабатывает запросы только от PS/2 клавиатуры, поэтому рассматриваемый метод будет не пригоден для перехвата данных, вводимых через USB или беспроводную клавиатуру. Поправьте если не так?
2) Неужели нет возможности организации фильтра посредством установки поверх устройства «\Device\PointerClass0», созданного классовым драйвером MouClass? Подобно тому как это возможно успешно сделать над драйвером KbdClass для клавиатуры, в чем принципиальная причина отсутствия аналогии?

Спасибо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.