Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 18.01.13 17:26
Оценка:
При написании дров всегда юзаю Zw* функции (Nt* функции обошёл стороной).
На счёт Nt* функций знаю следующее:
1) всю полезную работу выполняет Nt* функция
2) Nt* функцию нужно выполнять в контексте системного потока
3) Nt* функция вызывается из функции KiFastSystemCall, которую в свою очередь вызывает каждая Zw* функция

Так вот хочется понять почему для Nt* функции необходим системный поток?
Что творит функция KiFastSystemCall по обеспечению нормального вызова Nt* функции? И что KiFastSystemCall делает со стеком?
kifastsystemcall
Re: Что происходит между вызовом Zw* и Nt* функции?
От: Аноним  
Дата: 18.01.13 17:38
Оценка:
Здравствуйте, meto, Вы писали:

M>При написании дров всегда юзаю Zw* функции (Nt* функции обошёл стороной).

M>На счёт Nt* функций знаю следующее:
M>1) всю полезную работу выполняет Nt* функция
M>2) Nt* функцию нужно выполнять в контексте системного потока
M>3) Nt* функция вызывается из функции KiFastSystemCall, которую в свою очередь вызывает каждая Zw* функция

M>Так вот хочется понять почему для Nt* функции необходим системный поток?

M>Что творит функция KiFastSystemCall по обеспечению нормального вызова Nt* функции? И что KiFastSystemCall делает со стеком?
Что мешает скачать WRK и посмотреть самому?
Re: Что происходит между вызовом Zw* и Nt* функции?
От: ononim  
Дата: 18.01.13 17:45
Оценка:
M>При написании дров всегда юзаю Zw* функции (Nt* функции обошёл стороной).
M>На счёт Nt* функций знаю следующее:
M>1) всю полезную работу выполняет Nt* функция
M>2) Nt* функцию нужно выполнять в контексте системного потока
M>3) Nt* функция вызывается из функции KiFastSystemCall, которую в свою очередь вызывает каждая Zw* функция

M>Так вот хочется понять почему для Nt* функции необходим системный поток?

M>Что творит функция KiFastSystemCall по обеспечению нормального вызова Nt* функции? И что KiFastSystemCall делает со стеком?
У потока есть в ETHREAD такой флажок — PreviousMode. Он бывает KernelMode или UserMode. Прямого API для модификации этого поля нету, а читать его — да пажалста — ExGetPreviousMode().
Когда вы создаете ядреный поток — он у него проставлен в KernelMode. Когда создается юзермодный поток (на самом деле просто поток, который потом пошлют APC-шкой исполнять юзермодный код) ему это поле выставляется в UserMode.
Далее — когда приходит управление в Ntфункцию, она первым делом проверяет какой PreviousMode у текущего потока. Если он UserMode — она проверяет чтобы все аргументы-указатели лежали юзерском в диапазоне адресов и при необходимости, проводит проверки безопасности (обычно это effective token vs opened object's SECURITY_DESCRIPTOR). Либо Nt* функция может вызвать другую функцию ядра, которая хавает previousmode в качестве аргумента — тогда эта другая функция и будет делать эти проверки. Если же PreviousMode у потока == KernelMode — Nt* функции обычно не проводят проверки валидности аргументов и безопасности.
Zw* заглушки соответственно выставляют PreviousMode в KernelMode, передают управление на Nt* функции, и по возврату — возвращают все назад.
Как много веселых ребят, и все делают велосипед...
Re[2]: Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 18.01.13 18:42
Оценка:
Здравствуйте, ononim, Вы писали:

O>Далее — когда приходит управление в Ntфункцию, она первым делом проверяет какой PreviousMode у текущего потока. Если он UserMode — она проверяет чтобы все аргументы-указатели лежали юзерском в диапазоне адресов и при необходимости, проводит проверки безопасности (обычно это effective token vs opened object's SECURITY_DESCRIPTOR). Либо Nt* функция может вызвать другую функцию ядра, которая хавает previousmode в качестве аргумента — тогда эта другая функция и будет делать эти проверки. Если же PreviousMode у потока == KernelMode — Nt* функции обычно не проводят проверки валидности аргументов и безопасности.


Действительно. Глянул под Идой несколько Nt* функций и увидел сиё действо.

O>Zw* заглушки соответственно выставляют PreviousMode в KernelMode, передают управление на Nt* функции, и по возврату — возвращают все назад.


Можно ли самому менять флаг Tcb.PreviousMode ?
Кроме этого что ещё нужно сделать для возможности вызова Nt* функции из user-потока (в драйвере) ?
Re[3]: Что происходит между вызовом Zw* и Nt* функции?
От: ononim  
Дата: 18.01.13 20:22
Оценка:
O>>Zw* заглушки соответственно выставляют PreviousMode в KernelMode, передают управление на Nt* функции, и по возврату — возвращают все назад.
M>Можно ли самому менять флаг Tcb.PreviousMode ?
Ну тока если захардкодить смещение на ETHREAD ли анализировать ExGetPreviousMode(). Но зачем удалять гланды через задницу хачить если есть документированный рабочий способ — вызывать Zw* ?

M>Кроме этого что ещё нужно сделать для возможности вызова Nt* функции из user-потока (в драйвере) ?

да можете и без этого вызывать Nt* функции из user-mode потока. Просто учитывайте все вышеописанные ограничения. Но опять же — зачем?
Как много веселых ребят, и все делают велосипед...
Re[4]: Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 19.01.13 07:24
Оценка:
Здравствуйте, ononim, Вы писали:

O>Ну тока если захардкодить смещение на ETHREAD ли анализировать ExGetPreviousMode(). Но зачем удалять гланды через задницу хачить если есть документированный рабочий способ — вызывать Zw* ?


Ну если нужно обойти SSDT хуки антивирусов, то это, наверное, самый лучший метод. Али нет?

O>да можете и без этого вызывать Nt* функции из user-mode потока. Просто учитывайте все вышеописанные ограничения.


Так, к примеру, вызов NtCreateFile из user-потока порождает BSOD (по дампу где то стек бъётся). Из kernel-потока таже функция нормально отрабатывает (Zw вариант работает из любого потока). Вот и хочу понять почему такое может происходить.
Re[5]: Что происходит между вызовом Zw* и Nt* функции?
От: ononim  
Дата: 19.01.13 10:25
Оценка:
O>>Ну тока если захардкодить смещение на ETHREAD ли анализировать ExGetPreviousMode(). Но зачем удалять гланды через задницу хачить если есть документированный рабочий способ — вызывать Zw* ?
M>Ну если нужно обойти SSDT хуки антивирусов, то это, наверное, самый лучший метод. Али нет?
Нет. Например если хочется открыть файл — лучше воспользоваться IoCreateFile, а еще лучшее — послать IRP прямо в драйвер FS. Ключи реестра открыть мона при помощи ObOpenObjectByName, впрочем, тут по хорошему тока два варианта — или ZwOpenKey или ObOpenObjectByName. NtOpenKey — не экспортируется. А вот value читать придецца черз Zw, тут без ваориантов
Как много веселых ребят, и все делают велосипед...
Re[6]: Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 19.01.13 14:20
Оценка:
Здравствуйте, ononim, Вы писали:

O>Нет. Например если хочется открыть файл — лучше воспользоваться IoCreateFile ...


Попробовал. Хэндл возвращается. Но появилась проблема с освобождением полученного хендла.
Функция NtClose возвращает ошибку STATUS_INVALID_HANDLE (ZwClose даже не пробовал, т.к. хочу отказаться от Zw*).
Сейчаз попробовал перед NtClose менять этот Tcb.PreviousMode на KernelMode — хэндл удачно освободился.
Так что, видимо, буду "удалять гланды через задницу". У меня уже дров в пару местах сканит опкоды — добавим ещё 1 скан ))
Re[7]: Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 22.01.13 19:18
Оценка:
Тестирование показало, что изменение флага Tcb.PreviousMode и вызов Nt* функций часто влечёт за собой BSOD. Также может вызвать зацикливание в Nt* функции.
Так что даже и не знаю как эмулировать системный трэд без использования IoQueueWorkItem. Печалька.
Re[8]: Что происходит между вызовом Zw* и Nt* функции?
От: ononim  
Дата: 22.01.13 20:59
Оценка:
M>Тестирование показало, что изменение флага Tcb.PreviousMode и вызов Nt* функций часто влечёт за собой BSOD.
А назад вы его возвращаете после возврата?

M>Так что даже и не знаю как эмулировать системный трэд без использования IoQueueWorkItem. Печалька.

А чем не устраивает IoQueueWorkItem?
Как много веселых ребят, и все делают велосипед...
Re[9]: Что происходит между вызовом Zw* и Nt* функции?
От: meto Россия  
Дата: 23.01.13 12:20
Оценка:
M>>Тестирование показало, что изменение флага Tcb.PreviousMode и вызов Nt* функций часто влечёт за собой BSOD.
O>А назад вы его возвращаете после возврата?

Да, конечно же. Написал такие вот FORCEINLINE функи:
TPREVIOUSMODE prevMode;
EnterPrevModeSection(&prevMode, KernelMode);
NtClose(hnd);
LeavePrevModeSection(&prevMode);


Да BSOD'ы, как оказалось, ловились по иной причине. А так кодес робит уже нормально (от XP до Win8).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.