Проблема с перехватом ntCreateFile

Тема в разделе "WASM.WIN32", создана пользователем Progr, 8 ноя 2006.

  1. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Пишу драйвер перехватывающий обращения к файлам и возникла проблема:
    - Перехват работает но не в консольных приложениях.
    Выполняю команду type в эмуляции Дос (cmd.exe) с любым именем файла в качестве параметра и система уходит в БСОД. Причем вылетает, видимо, в месте, где программа выполняет return.
    Вот код:

    Код (Text):
    1.     if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER;
    2.     __try
    3.     {
    4.         wcsFileName = ObjectAttributes->ObjectName->Buffer;
    5.     }
    6.     __except(EXCEPTION_EXECUTE_HANDLER)
    7.     {
    8.         return STATUS_INVALID_PARAMETER;
    9.     }
    10.     pdest = wcsrchr(wcsFileName, ch);
    11.     if (pdest != 0) {
    12.         if (!wcscmp(pdest+1, L"test.exe"))
    13.             return STATUS_ACCESS_DENIED ;
    14.     }
    15.  
    16.     return TrueNtCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,
    17.                     AllocationSize,FileAttributes,ShareAccess,CreateDisposition,
    18.                             CreateOptions,EaBuffer,EaLength);
     
  2. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Перехват делаешь в ядре? А как же открыть файл из ядра?
    Код (Text):
    1. if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER;
    Код (Text):
    1.     __try
    2.     {
    3.         wcsFileName = ObjectAttributes->ObjectName->Buffer;
    4.     }
    Над юзер-модными адресами обязательно нужно делать MmProbeAndLockPages
    Код (Text):
    1. wcscmp(pdest+1, L"test.exe")
    Здесь известна длина pdest, и pdest совсем не обязательно закнчивается NULL, поэтому wcsncmp()
    Код (Text):
    1.  return STATUS_ACCESS_DENIED ;
    Опять то же самое - как система будет работать, если она не может открыть ни одного устройства?
    Под Dos может проявляться, например, потому, что требуется открыть для записи stdout, а в ответ возвращается фиг. Или обращение по неверному адресу в pdest
     
  3. Zufyxe

    Zufyxe New Member

    Публикаций:
    0
    Регистрация:
    13 авг 2004
    Сообщения:
    137
    Адрес:
    Russia
    Кроме NtCreateFile еще часто юзается NtOpenFile.
    Обе перечисленные функции - обертки вокруг IoCreateFile.
    Более целесообразно перехватывать именно ее.
     
  4. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Да, все в ядре. Я запросто мог наделать ошибок, т.к. это мой первый драйвер.
    Извини, но мало что понял....

    Здесь у меня безопасное извлечение пути к файлу, который хотят открыть/создать/т.п. Что еще тут нужно?

    С wcsncmp() понятно. За это спасибо - исправлю.

    Почему ниодного? Только один - тест.ехе. Или могут быть еще варианты?
     
  5. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Абсолютно все устройства в системе представлены в виде файлов, и их открытие происходит через функции XXXCreateFile. (Как заметил Zufyxe, таких функций действительно несколько.) Например, чтобы получить доступ к COM-порту, нужно открыть файл \??\COM1. Драйверы ОС, да и ее ядро тоже, вполне могут использовать для открытия любых устройств native-API. Соответственно, при попытке получить доступ к тому же Com1, система получит отказ. Рано или поздно она попытается открыть какое-нибудь критичное устройство и, получив отказ, упадет в синий экран.

    В общем все это достаточно подробно описано в Windows Internals by Mark Russinovich. Без понимания многих описанных там механизмов работы ОС в ядре лучше ничего не делать. Плюс для начала статьи Four-F. Это лучшее введение в написание драйверов и основы работы ОС, которое я видел.
     
  6. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Это извлечение не безопасное. В случае, если будет передан неверный адрес, try-except здесь не спасет. Перед обращением к юзерской памяти в ядре нужно вызывать MmProbeAndLockPages. Что-то в этом роде:
    Код (Text):
    1. if (ExGetPreviousMode() == UserMode) {
    2.     pMdl = IoAllocateMdl(UserAddress, Length, FALSE, FALSE, NULL);
    3.     __try {
    4.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    5.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    6.         DbgPrint("bla-bla-bla: error");
    7.     }
    8. }
    9. // Здесь можно обращаться к UserAddress
    ЗЫ: Синий экран у тебя в данном случае появляется, как я уже сказал, не по этой причине
     
  7. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    С CreateFile все понятно, но у меня разрешено открытие всего кроме test.exe.
    Как это может помешать системе и все остальному, ведь ко всему остальному обращение/открытие/создание не блокируется!
     
  8. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Код (Text):
    1. if ((ULONG *)ObjectAttributes > MmUserProbeAddress) return STATUS_INVALID_PARAMETER;
    А если это условие не выполняется по какой-то причине? Например, вызов ZwCreateFile из драйвера через ntoskrnl?
     
  9. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Так как же быть?
     
  10. opennetworks

    opennetworks New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2006
    Сообщения:
    436
    RTFM MSDN LIBRARY
     
  11. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    1) убери это условие;
    2) выполняй Probe над аргументами, которые используешь в перехватчике (здесь тебе нужно сделать Probe для адресов ObjectAttributes, ObjectAttributes->ObjectName и ObjectAttributes->ObjectName->Buffer соответственно)

    И в случае, если правильно установлен перехват и корректно вызывается оригинальная функция, все будет работать :)
     
  12. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Если я тебя правильно понял, то так?

    Код (Text):
    1. void* pMdl;
    2. if (ExGetPreviousMode() == UserMode) {
    3.     pMdl = IoAllocateMdl(ObjectAttributes, ObjectAttributes->Length, FALSE, FALSE, NULL);
    4.     __try {
    5.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    6.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    7.         DbgPrint("bla-bla-bla1: error");
    8.     }
    9.     IoFreeMdl(pMdl);
    10.     pMdl = IoAllocateMdl(ObjectAttributes->ObjectName, ObjectAttributes->ObjectName->Length, FALSE, FALSE, NULL);
    11.     __try {
    12.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    13.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    14.         DbgPrint("bla-bla-bla2: error");
    15.     }
    16.     IoFreeMdl(pMdl);
    17.     pMdl = IoAllocateMdl(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Buffer->Length, FALSE, FALSE, NULL);
    18.     __try {
    19.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    20.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    21.         DbgPrint("bla-bla-bla3: error");
    22.     }
    23.     IoFreeMdl(pMdl);
    24. }
     
  13. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Почти.
    Код (Text):
    1. void* pMdl;
    2. BOOLEAN locked1 = FALSE, locked2 = FALSE, locked3 = FALSE;
    3. if (ExGetPreviousMode() == UserMode) {
    4.     pMdl1 = IoAllocateMdl(ObjectAttributes, sizeof(ObjectAttributes), FALSE, FALSE, NULL);
    5.     if (pMdl1 == NULL)
    6.         goto done;
    7.     __try {
    8.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    9.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    10.         DbgPrint("bla-bla-bla1: error");
    11.         goto done;
    12.     }
    13.     locked1 = TRUE;
    14.     pMdl2 = IoAllocateMdl(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), FALSE, FALSE, NULL);
    15.     if (pMdl2 == NULL)
    16.         goto done;
    17.     __try {
    18.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    19.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    20.         DbgPrint("bla-bla-bla2: error");
    21.         goto done;
    22.     }
    23.     locked2 = TRUE;
    24.     pMdl3 = IoAllocateMdl(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length, FALSE, FALSE, NULL);
    25.     if (pMdl3 == NULL)
    26.         goto done;
    27.     __try {
    28.         MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
    29.     } __except(EXCEPTION_EXECUTE_HANDLER) {
    30.         DbgPrint("bla-bla-bla3: error");
    31.         goto done;
    32.     }
    33.     locked3 = TRUE;
    34.  
    35. // Здесь можно безопасно сравнивать имя
    36.  
    37. done:
    38.     if (locked1)
    39.         MmUnlockPages(pMdl1);
    40.     if (locked2)
    41.          MmUnlockPages(pMdl2);
    42.     if (locked3)
    43.         MmUnlockPages(pMdl3);
    44.     if (pMdl1 != NULL)
    45.         IoFreeMdl(pMdl1);
    46.     if (pMdl2 != NULL)
    47.         IoFreeMdl(pMdl2)
    48.     if (pMdl3 != NULL)
    49.         IoFreeMdl(pMdl3)
    50. }
    В таком виде хук не должен валиться на любых исходных данных. В данном случае можно заменить IoModifyAccess на IoReadAccess
     
  14. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Спасибо, буду пробывать
     
  15. green_newbie

    green_newbie New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2006
    Сообщения:
    51
    Параметры можно не проверять, только не забывай, что в ядре строки часто не заканчиваются нулем(вместе со строкой часто передается ее длина), поэтому функции типа wcsstr для обработки строк - это плохой вариант
     
  16. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Чтобы систему можно было свалить с юзер-мода? Не хотел бы я на такой машине работать...
     
  17. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    А какую использовать?
     
  18. Progr

    Progr New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2006
    Сообщения:
    48
    Все заработало. Огромное спасибо gilg за рзъеснения новичку.
    Удачи!
     
  19. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Дык всегда пожалуйста :)
     
  20. green_newbie

    green_newbie New Member

    Публикаций:
    0
    Регистрация:
    18 окт 2006
    Сообщения:
    51
    Интересно, какие такие хитрые данные можно запихнуть в имя файла в NtCreateFile, что функа strncmp в перехватчике свалит систему? Проверка на 0 конечно присутствует