Оперируя статьей http://www.wasm.ru/article.php?article=drvw2k13 И http://www.wasm.ru/article.php?article=drvw2k14 Делаю синхронизацию между ядром и юзермодом. Упрощенно схема взаимодействия: В драйвере установен перехватчик на функцию NtOpenFile При вызове в глобальную строку записывается имя файла. Юзермоде до этого создает событие, передает ее указатель в ядро. Там при наступлении события перехвата функций вызвается KeSetEvent(g_pkEventObject, 0, FALSE); Тем самым юзермод начинает брать данные через DeviceIoControl и обработчик запроса IOCTL_GET_PROCESS_DATA. Юзермод: Код (Text): while not b do begin WaitForSingleObject( hEvent, INFINITE); FillChar(buff,4096,0); d:= DeviceIoControl(hDriver, IOCTL_GET_PROCESS_DATA, @hEvent, sizeof(hEvent), @Buff, sizeof(Buff), returned, nil ); .. Все работает, данные сливаются, однако если открывать много файлов, то юзермод не успевает схватить свежие данные, а когда хватает, то там оказываются уже переписанные (обновленные) данные. То есть уже от новогоперехваченного вызова NtOpenFile. Но вот если в обрботчике NtOpenFile поставить паузу после Код (Text): KeSetEvent(g_pkEventObject, 0, FALSE); KeDelayExecutionThread (KernelMode, FALSE, &Wait); Допустим 50 мс, то юзермод успевает схавать все. Ставить паузу - не решение, 1. Слишком тормозит работу, 2. На разных компах она может потребоваться разной. Вспомнил про мьютексы. Сделал: В DriverEntry я создаю мьютекс, Код (Text): KeInitializeMutex( &g_kMutex, 0); Далее в обработчике NtOpenFile Код (Text): KeWaitForMutexObject( &g_kMutex, Executive, KernelMode, FALSE, NULL); И после этого заношу в буфер свежие данные и вызываю событие, чтобы юзермод очухался. После этого юзермод отправляет запросик DeviceIoControl Его обработчик возвращяет в пользовательский буфер содержание глобальной строки, и потом вызывает Код (Text): KeReleaseMutex(&g_kMutex, FALSE); Типа переключиться в состояние "готов", и уже тогда начнет обработку очередная ntOpenFile Касяк в том, что если не комментировать KeReleaseMutex, то дело заканчивается синим экраном. (правда отлаживаю не на процедуре перехвата открытия файлов, а при поступлении данных через WriteFile , что смысла не меняет.) Вопрос: почему БДОС? В статье упоминалось что только один поток может захватить мьютекс, но в одном потоке можно делать много раз. А у меня как получается? Захватывает в одном, освобождает в другом? Этот момент не понимаю.. Посоветуйте как поступить. Или другой способ синхронизации.. Спсибо.
Возможно удобней было бы сделать так: 1 создать в ядре двунаправленный список и семафор 2 при вызове NtOpenFile вставить новый элемент списка с путем к файлу, зарелизить семафор 3 в юзермоде ждать на описателе семафора, после активации посылать запрос драйверу, который извлечет первый элемент списка и вернет юзермоду ?
driver, юхермод на Паскале, драйвер на С. Velheart, Щас посмотрю что такое двунаправленный список. Можно поподробнее про семафор? Где бы почитать.. Чем от от Eventov отличается?
test555 погугли KLOG, вроде на rootkits.com исходник лежит, там такая стратегия используется при перехвате клавиш, но только передаются не в юзермод значения, а в рабочий поток, если не найдешь, могу посмотреть у себя и выложить исходник. А про семафор у Рихтера или Руссиновича можно посмотреть, хотя наверно и мсдн/ддк-хелпа должно хватить. зы кстати этот KLOG подробно разбирается в "Руткиты, внедрение в ядро Windows", если чего там будет непонятно, можно посмотреть в этой книге, гугл на нее много ссылок дает.
Спасибо. Руткиты как-то читал, но еще до того как начал программировать драйвер (2 недели занимаюсь).. Почитал про двунаправленный список, но не понял какое он мне даст приемущество, если только то что накапливать несколько порций информации для последующей передачи в юзермод.. Листаю Руссиновича. Хотя все же хотелось знать, почему мьютексы не работают у меня?
Ну просто не так будет тормозить вся система, если ты в функции перехвата вызываешь Wait-функцию, то "нечестно" отбираешь у вызывающего потока процессорное время причем неопределенное количество, а если после того, как ты захватил мютекс, юзермодный процесс завершится, получится, что он не даст возможности потоку, который вызывал NtOpenFile продолжить выполнение. + Релизить мьютекс может только поток, который его захватил, иначе -- БСОД add: т.е. ты захватываешь его в потоке, который вызывает NtOpenFile, а освобождаешь в том, который вызывает драйвер из юзермода, поэтому и БСОД
Velheart, спасибо за пояснение, так и думал что в этом касяк. А если семафоры использовать, такое сработает? (В таком случае задержки можно будет убрать, но прийдется заботиться о корректности работы при аварийном завершении юзермода - это уже другая проблема..)
Должно, хотя нет функции ZwCreateSemaphore, можно наверно (тут я совсем не уверен) либо создать семафор через ObCreateObject -- KeInitializeSemaphore и открывать из юзермода по имени, либо создать безымянный через KeInitializeSemaphore и сделать хэндл целевому процессу, либо создать в юзермоде, и открыть в ядре по имени или приаттачиться к процессу и получить по хэндлу объект, т.к. в ядре с семафором по хэндлу работать нельзя, хотя возможно я плохо посмотрел.
а что если заменить мьютексы на семафоры? И служить они будут чисто для синхронизации самого драйвера.. Нарыл функции KeInitializeSemaphore, KeReleaseSemaphore, KeReleaseSemaphore Буду гадать для чего нужны параметры и эксперименты.. Но вопрос еще открыт..
Так а смысл-то? Семафор нужен, чтобы иметь возможность синхронизированного доступа к списку, в котором может накапливаться информация, если обрабатывается медленней, чем появляется, фишка в том, чтобы не тормозить поток, вызывающий перехваченную функцию на период считать путь -- передать в юзермод -- просигналить из юзермода + избавиться от очень неприятной ситуации, когда какие-то накладки в юзермодном обработчике могут стать причиной зависания какого-то левого процесса..
Velheart, спасибо, Вас понял. Все реализовал, все работает. Через семафоры, но без ассоциативных списков. Т.к. в драйвере будет фильтр, отметающий почти все файлы, то проблем с тормозами быть не должно. То есть "подключаться" фишка будет только например при записи файлов на флешку.. А там тормозностью можно принебречь. Хотя если освоюсь, быть может и перепешу. Всем спасибо. Буду работать дальше. Основная проблема решена. Кому интересно: Создаю семафор: Код (Text): #define SEMAPHORE_LIMIT 6 .. KeInitializeSemaphore(&g_pksemaphore, SEMAPHORE_LIMIT, SEMAPHORE_LIMIT); В некоторой процедуре, которую перехватываем (таймаут 50 мс, если юзермод не подобрал событие) Код (Text): Wait.LowPart = -500000; Wait.HighPart = -1; KeWaitForSingleObject(&g_pksemaphore,Executive, KernelMode, FALSE, &Wait); //KeWaitForSingleObject(&g_pksemaphore,Executive, KernelMode, FALSE, NULL); После этого юзермод дает запрос, обработчик которого делает Код (Text): if ( KeReadStateSemaphore(&g_pksemaphore) < SEMAPHORE_LIMIT) KeReleaseSemaphore(&g_pksemaphore,0 ,1, FALSE); Это избавит от ДБОСа, т.к. не будет сбоев при "лишнем" освобождении семафора..