Процесс на старте создаёт мютекс, чтобы блокировать вторичный запуск. Этот же процесс запускает драйвер. При завершении процесса (без крайних мер) приложение посылает драйверу сигнал о выгрузке (DriverUnload). Мютекс закрывается виндой. Если приложение закрыть принудительно (например прибить процесс из ТМ), мютекс остается висеть в системе, не давая больше запустить прогу. Драйвер тоже не выгружается. С драйвером можно по-деревенски - проверять по тикам таймера наличие процесса, если процесс исчез - самовыгрузиться через DriverUnload. А как быть с мютексом? Может ли работающий драйвер цивилизованными способами отследить исчезновение парентского процесса и прикрыть мютекс? PsSetCreateProcessNotifyRoutine не помогает.
По-моему, такие объекты как мьютексы, семафоры и т.д. уничтожаются самой системой при уничтожении его хэндла. В MSDN про это хорошо написано.
можно передавать хэндл мьютекса в драйвер, где звать (аналог в драйвере?) WaitForSingleObject и проверять возвращённое значение на WAIT_ABANDONED Return code/value WAIT_ABANDONED 0x00000080L Description The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
Можно так: 1) После старта драйвера приложение посылает ему запрос через DeviceIOControl 2) Драйвет устанавливает для этого IRP Cancel routine, используя IoSetCancelRoutine, делает IoMakrIrpPending и возвращает STATUS_PENDING 3) Приложение как-то закрывается, система отменяет все IRP процесса, и таким образом вызывается заданная ранее Cancel routine ЗЫ вообще-то странно что мутекс не убивается
Драйвер о мютексе не знает. С мютексом как-нибудь потом. Тут более важная проблема: как из драйвера выгрузить его самого? В DriverEntry запускаю поток, в котором контролирую наличие родительского процесса: Код (Text): PKSTART_ROUTINE UnloadProc(PVOID Context){ NTSTATUS Status; LARGE_INTEGER Wait; UNICODE_STRING uDeviceName; Wait.LowPart = -10000000; Wait.HighPart = -1; while (TRUE){ KeDelayExecutionThread (KernelMode, FALSE, &Wait); if (!g_UnloadActive) break; //приложение закрылось нормально if (g_ParentID && !ParentPresent()){ //приложение закрыто принудительно DbgPrint("Thread About Term"); g_UnloadActive = FALSE; DriverUnload(g_DriverObject); break; } } PsTerminateSystemThread (STATUS_SUCCESS); return 0; } из вызова DriverUnload поток не возвращается (возможно эту процедуру нельзя вызывать самому) Если вызвать ZwUnloadDriver то ошибка "файл не найден", хотя передаю как нарисовано в msdn имя ключа в реестре RtlInitUnicodeString(&uDeviceName, L"\\Registry\\Machine\\CurrentControlSet\\Services\\MyDriver"); Status = ZwUnloadDriver(&uDeviceName); [edited] Ключ реестра неправильно указал, если указать правильно - BSOD
Ничего лучше перехвата ZwTerminateProcess и возврата ACCESS_DENIED не придумал И драйвер не надо выгружать, и мютекс закрывать.
CARDINAL Решение было изначально в кармане (с перехватом). Можно было и не задавать вопрос. Было интересно, как из драйвера выгрузить драйвер. Я не нашёл способа. Если знаешь - колись.
1) Выделить память через ExAllocatePool 2) Скопировать туда код выгружающий драйвер 3) Запустить этот код в новом потоке (PsCreateSystemThread) 4) В этом коде делать ZwUnloadDriver и завершение потока.
Есть какие-либо особенности запуска потока во внешней памяти? Пробовал традиционным способом: Код (Text): __asm{ lea eax,TrustedPresent sub eax,ExternThread mov [cb],eax } DbgPrint("Code size = %d", cb); //пауза, чтобы прочесть DbgPrint :) KeDelayExecutionThread (KernelMode, FALSE, &Wait); pExt = ExAllocatePool(PagedPool,cb); if (pExt){ DbgPrint ("Copy memory"); KeDelayExecutionThread (KernelMode, FALSE, &Wait); memcpy (pExt, &ExternThread, cb); DbgPrint ("Try to start extern thread"); KeDelayExecutionThread (KernelMode, FALSE, &Wait); Status = PsCreateSystemThread (&hThread, THREAD_ALL_ACCESS, 0, 0, 0, (PKSTART_ROUTINE)pExt, 0); DbgPrint ("Status = %08X", Status); KeDelayExecutionThread (KernelMode, FALSE, &Wait); if (Status == STATUS_SUCCESS) ZwClose (hThread); } Последняя выведенная в DbgView строка - "Try to start extern thread". Дальше перезагрузка без комментариев. Копируемая процедура такая (до её выполнения дело не доходит): Код (Text): PKSTART_ROUTINE ExternThread(PVOID Context){ UNICODE_STRING uDeviceName; NTSTATUS Status; LARGE_INTEGER Wait; Wait.LowPart = -30000000; Wait.HighPart = -1; DbgPrint("Driver About Unload"); KeDelayExecutionThread (KernelMode, FALSE, &Wait); RtlInitUnicodeString(&uDeviceName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\MyDriver") ; DbgPrint ("%S", uDeviceName.Buffer); KeDelayExecutionThread (KernelMode, FALSE, &Wait); Status = ZwUnloadDriver(&uDeviceName); KeDelayExecutionThread (KernelMode, FALSE, &Wait); PsTerminateSystemThread (STATUS_SUCCESS); return 0; }
ЛОЛ! ну ты блин даешь... Разве можно так писать? Код должен быть базонезависимым, иначе у тебя все call указывают после переноса в космос и естественно все падает. Заполняй таблицу с адресами апи, размещай ее в памяти перед кодом, получай дельту (или лучше линамически забивай адрес таблицы в код) и тогда будет работать. З.Ы. для тех кто в танке напомню что и все данные используемые кодом (например строки) тоже надо выносить. З.З.Ы. ты айс юзать пробовал? а то такие вопросы бы сами отпали.
Хм, я почему-то думал, что тут в отличие от юзера, единое адресное пространство, и я могу свободно обращаться к памяти драйвера Т.е. делая из внешнего потока например KeDelayExecution, я выполняю call dword ptr[KeDelayExecution], и этот dword ptr указывает на валидную ячейку в секции драйвера с адресом ф-ции. Ну раз это не так - переделываем.
Во-первых call может быть не call dword ptr[KeDelayExecution], а call jmp_KeDelayExecution, тоесть кол на переходник который идет по относительному адресу. Во-вторых, если ты будешь производить выгрузку драйвера, то надо быть готовым что в один прекрасный момент весь его образ просто пропадет из памяти, а значит ничем там пользоваться нельзя. И юзай айс чтобы понять запустился у тебя поток или нет и че там твориться.
Да ничем Сайс не приживается на компе, по windbg нет никакого материала (примера). Вот и использую метод проб и ошибок. Реально только DbgPrint кое-какую помощь оказывает. Ты наверное заметил мои "брейкпоинты" на основе KeDelayExecutionThread Это всё