Вызов Функций Windows В Режиме Ядра

Многие из вас, уважаемые хабровцы, пользуются функциями ядра Windows. Однако не все понимают, как называются эти функции.

А знание некоторых механизмов ядра может оказаться весьма полезным.

Этот текст не предназначен для авторов драйверов, которые (теоретически) знают это даже на более глубоком уровне.

Начнем с того, что режим ядра имеет гораздо больше функций, чем всем известный WinAPI. Это связано с тем, что ядро содержит множество недокументированных функций (однако с выходом Win7 и Win8 ситуация улучшилась, многие такие функции попадают в MSDN).

Список таких функций можно посмотреть, например, Здесь.

Эти функции можно разделить на несколько групп:

  • API ядра - функции расположены в ntoskrnl.exe (фактически обычная dll), основные функции ядра.

  • Оконный API - функции находятся в gdi32.dll, функции для работы с окнами и графикой.

  • API обмена сообщениями - функции расположены в user32.dll, функции обработки сообщений.

Чем все это вызвано? Начнем с вызова из пользовательского режима.

- Прежде всего, мы обратимся к NtDll.dll — «прослойка» между пользовательским режимом и режимом ядра.

Он содержит нужную нам функцию ядра.

Ээта функция помещает в регистр ЕАХ твой номер.

Это индекс двух таблиц, известных ядру: ServiceTable и ArgumentTable. Характерно, что это число специфично для каждой версии ОС.

Он часто меняется не только при переходе, скажем, с WinXP на Vista, но даже при переходе с Vista на Vista SP1. - Дальше, в ЭДКС размещается адрес вершины стека параметров, в большинстве случаев это значение регистра ESP .

Казалось бы, зачем копировать уже существующее значение? Дело в том, что после выполнения прерывания все состояние процессора сбросится в стек, и ESP уже не будет тем, что нам нужно.

— Наконец, он переключается в режим ядра.

На старых процессорах и системах это делается с помощью прерывания 0x2e, но на современных для этого существует специальная инструкция процессора: SysEnter для Интел, системный вызов для АМД.

— Результатом вызова является выполнение процессором кода, адрес которого находится в глобальной таблице прерываний в конкретной ячейке.

Этот код вызывает либо КиСистемСервис(), в случае прерывания или КиFastCallEntry(), в случае специальной инструкции процессору.

Кстати, второй прописан в реестре MSR, что обеспечивает быстрый доступ к нему.

— Далее код, работающий в ядре, выполняется немного по-разному, в зависимости от того, откуда поступил вызов функции, из режима ядра или из пользовательского режима.

Задача кода ядра: используйте внутреннюю таблицу функций для вызова функции из EAX. Эта таблица называется KiServiceDescriptorTable .

Это структура с тремя полями:

  • обращение к таблице ServiceTable (nt!KiServiceTable) — массив функций
  • адрес в ArgumentTable (nt!KiArgumentTable) — количество байт, занимаемых параметрами
  • количество элементов в этих таблицах
Когда вызываются функции SysEnter и SysCall, им необходимо отправить вызов функциям ОС.

Каждый поток имеет стек пользовательского режима и режима ядра.

ОС берет значение ячейки таблицы ArgumentTable, которая показывает, сколько байт параметры занимают в стеке (для этого мы вспомнили EDX).

Затем он копирует это количество байтов в стек ядра.

И после этого он вызывает функцию через ServiceTable. Вся эта заморочка с двумя стеками нужна, конечно, для того, чтобы никакие изменения в пользовательском режиме не повредили выполнению функции в ядре.

- После вызова и выполнения функции, а также завершения ее работы, происходит возврат из режима ядра с помощью инструкции ирет или СисВыход/СисРет. Вызов функций ядра в режиме ядра.

В принципе у нас всё то же самое, но.

Если вы внимательно посмотрите на список функций ядра, то заметите, что там есть функции, полностью похожие на нт- функции, но с префиксом zw- .

Все они однозначно сопоставлены с функцией nt. Однако в режиме ядра они работают по-другому.

Разница в том, что функции zw не проверяют параметры.

Другими словами, при вызове из пользовательского режима система тщательно отслеживает передаваемые в функцию параметры — не дай бог программист что-то упустит, и здравствуй, синий экран.

В режиме ядра в основном работают с драйверами, а там система уже предполагает, что вы сами проверите все параметры и гарантируете их достоверность, потому что дополнительные проверки съедят драгоценное время.

Работает это так: если вызывается zw, то он загружает номер функции в EAX, помещает указатель на стек ядра в EDX, а затем вызывает опцию nt, которая не выполняет проверку.

Возникает вопрос: что, если я удалю функцию zw из пользовательского режима? Простит ли система все? Не совсем.

Если zw вызывается в пользовательском режиме, он просто вызывает своего двойника nt. Вот, в общем-то, и вся основная информация о вызовах функций ядра.

Надеюсь, вам было интересно.

Теги: #Windows #режим ядра #программирование

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.