Пишу драйвер перехватывающий обращения к файлам и возникла проблема: - Перехват работает но не в консольных приложениях. Выполняю команду type в эмуляции Дос (cmd.exe) с любым именем файла в качестве параметра и система уходит в БСОД. Причем вылетает, видимо, в месте, где программа выполняет return. Вот код: Код (Text): if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER; __try { wcsFileName = ObjectAttributes->ObjectName->Buffer; } __except(EXCEPTION_EXECUTE_HANDLER) { return STATUS_INVALID_PARAMETER; } pdest = wcsrchr(wcsFileName, ch); if (pdest != 0) { if (!wcscmp(pdest+1, L"test.exe")) return STATUS_ACCESS_DENIED ; } return TrueNtCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock, AllocationSize,FileAttributes,ShareAccess,CreateDisposition, CreateOptions,EaBuffer,EaLength);
Перехват делаешь в ядре? А как же открыть файл из ядра? Код (Text): if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER; Код (Text): __try { wcsFileName = ObjectAttributes->ObjectName->Buffer; } Над юзер-модными адресами обязательно нужно делать MmProbeAndLockPages Код (Text): wcscmp(pdest+1, L"test.exe") Здесь известна длина pdest, и pdest совсем не обязательно закнчивается NULL, поэтому wcsncmp() Код (Text): return STATUS_ACCESS_DENIED ; Опять то же самое - как система будет работать, если она не может открыть ни одного устройства? Под Dos может проявляться, например, потому, что требуется открыть для записи stdout, а в ответ возвращается фиг. Или обращение по неверному адресу в pdest
Кроме NtCreateFile еще часто юзается NtOpenFile. Обе перечисленные функции - обертки вокруг IoCreateFile. Более целесообразно перехватывать именно ее.
Да, все в ядре. Я запросто мог наделать ошибок, т.к. это мой первый драйвер. Извини, но мало что понял.... Здесь у меня безопасное извлечение пути к файлу, который хотят открыть/создать/т.п. Что еще тут нужно? С wcsncmp() понятно. За это спасибо - исправлю. Почему ниодного? Только один - тест.ехе. Или могут быть еще варианты?
Абсолютно все устройства в системе представлены в виде файлов, и их открытие происходит через функции XXXCreateFile. (Как заметил Zufyxe, таких функций действительно несколько.) Например, чтобы получить доступ к COM-порту, нужно открыть файл \??\COM1. Драйверы ОС, да и ее ядро тоже, вполне могут использовать для открытия любых устройств native-API. Соответственно, при попытке получить доступ к тому же Com1, система получит отказ. Рано или поздно она попытается открыть какое-нибудь критичное устройство и, получив отказ, упадет в синий экран. В общем все это достаточно подробно описано в Windows Internals by Mark Russinovich. Без понимания многих описанных там механизмов работы ОС в ядре лучше ничего не делать. Плюс для начала статьи Four-F. Это лучшее введение в написание драйверов и основы работы ОС, которое я видел.
Это извлечение не безопасное. В случае, если будет передан неверный адрес, try-except здесь не спасет. Перед обращением к юзерской памяти в ядре нужно вызывать MmProbeAndLockPages. Что-то в этом роде: Код (Text): if (ExGetPreviousMode() == UserMode) { pMdl = IoAllocateMdl(UserAddress, Length, FALSE, FALSE, NULL); __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla: error"); } } // Здесь можно обращаться к UserAddress ЗЫ: Синий экран у тебя в данном случае появляется, как я уже сказал, не по этой причине
С CreateFile все понятно, но у меня разрешено открытие всего кроме test.exe. Как это может помешать системе и все остальному, ведь ко всему остальному обращение/открытие/создание не блокируется!
Код (Text): if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER; А если это условие не выполняется по какой-то причине? Например, вызов ZwCreateFile из драйвера через ntoskrnl?
1) убери это условие; 2) выполняй Probe над аргументами, которые используешь в перехватчике (здесь тебе нужно сделать Probe для адресов ObjectAttributes, ObjectAttributes->ObjectName и ObjectAttributes->ObjectName->Buffer соответственно) И в случае, если правильно установлен перехват и корректно вызывается оригинальная функция, все будет работать
Если я тебя правильно понял, то так? Код (Text): void* pMdl; if (ExGetPreviousMode() == UserMode) { pMdl = IoAllocateMdl(ObjectAttributes, ObjectAttributes->Length, FALSE, FALSE, NULL); __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla1: error"); } IoFreeMdl(pMdl); pMdl = IoAllocateMdl(ObjectAttributes->ObjectName, ObjectAttributes->ObjectName->Length, FALSE, FALSE, NULL); __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla2: error"); } IoFreeMdl(pMdl); pMdl = IoAllocateMdl(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Buffer->Length, FALSE, FALSE, NULL); __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla3: error"); } IoFreeMdl(pMdl); }
Почти. Код (Text): void* pMdl; BOOLEAN locked1 = FALSE, locked2 = FALSE, locked3 = FALSE; if (ExGetPreviousMode() == UserMode) { pMdl1 = IoAllocateMdl(ObjectAttributes, sizeof(ObjectAttributes), FALSE, FALSE, NULL); if (pMdl1 == NULL) goto done; __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla1: error"); goto done; } locked1 = TRUE; pMdl2 = IoAllocateMdl(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), FALSE, FALSE, NULL); if (pMdl2 == NULL) goto done; __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla2: error"); goto done; } locked2 = TRUE; pMdl3 = IoAllocateMdl(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length, FALSE, FALSE, NULL); if (pMdl3 == NULL) goto done; __try { MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("bla-bla-bla3: error"); goto done; } locked3 = TRUE; // Здесь можно безопасно сравнивать имя done: if (locked1) MmUnlockPages(pMdl1); if (locked2) MmUnlockPages(pMdl2); if (locked3) MmUnlockPages(pMdl3); if (pMdl1 != NULL) IoFreeMdl(pMdl1); if (pMdl2 != NULL) IoFreeMdl(pMdl2) if (pMdl3 != NULL) IoFreeMdl(pMdl3) } В таком виде хук не должен валиться на любых исходных данных. В данном случае можно заменить IoModifyAccess на IoReadAccess
Параметры можно не проверять, только не забывай, что в ядре строки часто не заканчиваются нулем(вместе со строкой часто передается ее длина), поэтому функции типа wcsstr для обработки строк - это плохой вариант
Интересно, какие такие хитрые данные можно запихнуть в имя файла в NtCreateFile, что функа strncmp в перехватчике свалит систему? Проверка на 0 конечно присутствует