10,99 €
Ядро Windows таит в себе большую силу. Но как заставить ее работать? Павел Йосифович поможет вам справиться с этой сложной задачей: пояснения и примеры кода превратят концепции и сложные сценарии в пошаговые инструкции, доступные даже начинающим. В книге рассказывается о создании драйверов Windows. Однако речь идет не о работе с конкретным "железом", а о работе на уровне операционной системы (процессы, потоки, модули, реестр и многое другое). Вы начнете с базовой информации о ядре и среде разработки драйверов, затем перейдете к API, узнаете, как создавать драйвера и клиентские приложения, освоите отладку, обработку запросов, прерываний и управление уведомлениями.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 397
Переводчик Е. Матвеев
Литературный редактор М. Петруненко
Корректоры Н. Викторова, М. Молчанова (Котова)
Павел Йосифович
Работа с ядром Windows. — СПб.: Питер, 2021.
ISBN 978-5-4461-1680-5
© ООО Издательство "Питер", 2021
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
В этой главе более подробно рассматриваются функции API, структуры и определения режима ядра. Также будут описаны некоторые механизмы выполнения кода в драйвере. Наконец, вся новая информация будет объединена для построения нашего первого функционального драйвера.
В этой главе:
• Общие рекомендации программирования ядра
• Отладочные и конечные сборки
• API режима ядра
• Функции и коды ошибок
• Строки
• Динамическое выделение памяти
• Списки
• Объект драйвера
• Объекты устройств
Для разработки драйверов ядра необходим пакет Windows Driver Kit (WDK) с соответствующими заголовочными файлами и библиотеками. API режима ядра состоит из функций C, которые имеют много общего с функциями пользовательского режима. Впрочем, есть и некоторые различия. В табл. 3.1 приведена сводка основных различий между программированием пользовательского режима и программированием режима ядра.
Таблица 3.1. Различия в разработке для режима ядра и пользовательского режима
Пользовательский режим
Режим ядра
Необработанное исключение
Фатальный сбой процесса
Фатальный сбой системы
Завершение
При завершении процесса вся приватная память и ресурсы освобождаются автоматически
Если драйвер выгружается без освобождения всех используемых им ресурсов, возникает утечка, которая будет исправлена только при следующей загрузке
Возвращаемые значения
Ошибки API иногда игнорируются
Ошибки (почти) никогда не должны игнорироваться
IRQL
Всегда PASSIVE_LEVEL(0)
Может быть DISPATCH_LEVEL(2) и выше
Ошибки программирования
Обычно локализуются в процессе
Могут иметь общесистемные последствия
Тестирование и отладка
Тестирование и отладка обычно выполняются на машине разработчика
Отладка должна выполняться на другой машине
Библиотеки
Может использовать практически любые библиотеки C/C++ (например, STL и boost)
Не может использовать большинство стандартных библиотек
Обработка исключений
Может использовать исключения C++ или структурированную обработку исключений (SEH)
Может использовать только SEH
Использование C++
Доступна вся среда времени выполнения C++
Среда времени выполнения С++ недоступна
Исключения, происходящие в пользовательском режиме и не перехваченные программой, приводят к преждевременному завершению программы. С другой стороны, код режима ядра, который неявно считается пользующимся доверием, не может восстановиться из необработанного исключения. Такое исключение приведет к общему сбою системы с печально известным «синим экраном смерти», или BSOD (Blue Screen Of Death) (в новых версиях Windows экраны общего сбоя используют более разнообразные цвета). На первый взгляд BSOD создает неудобства, но по сути это защитный механизм. Дело в том, что возможное продолжение выполнения кода может причинить непоправимый вред Windows (например, удаление важных файлов или повреждение реестра), из-за которого система не сможет загрузиться. А значит, лучше немедленно остановить работу, чтобы предотвратить возможные повреждения. BSOD более подробно рассматривается в главе 6.
Все сказанное ведет к одному простому выводу: код режима ядра следует писать очень внимательно и осторожно, уделяя особое внимание всем мелочам и проверкам ошибок.
Когда процесс завершается по любой причине — нормальным образом, из-за необработанного исключения или из внешнего кода, — он никогда не оставляет после себя никаких утечек: вся приватная память освобождается, все дескрипторы закрываются и т.д. Конечно, преждевременное закрытие дескрипторов может привести к потере некоторых данных (например, при закрытии дескриптора файла перед записью части данных на диск), но утечки ресурсов не будет: это гарантируется ядром.
С другой стороны, драйверы ядра такой гарантии не дают. Если драйвер выгружается в тот момент, когда он все еще удерживает выделенную память или открытые дескрипторы режима ядра, такие ресурсы не будут освобождены автоматически. Освобождение произойдет только при следующей загрузке системы.
Почему это происходит? Разве ядро не может отслеживать выделение памяти и использование ресурсов драйверами, чтобы автоматически освобождать их при выгрузке драйвера?
Теоретически это возможно (хотя в настоящее время ядро не следит за использованием ресурсов). Настоящая проблема в том, что такие попытки освобождения ресурсов со стороны ядра были бы слишком опасными. Представьте, что драйвер выделил буфер в памяти, а затем передал его другому драйверу, с которым он взаимодействует. Второй драйвер использует буфер в памяти и в конечном итоге освобождает его. Если ядро попытается освободить буфер при выгрузке первого драйвера, то во втором драйвере попытка обращения к освобожденному буферу приведет к нарушению прав доступа и общему сбою системы.
Этот пример снова подчеркивает, что драйвер ядра должен тщательно прибрать за собой: никто другой этого не сделает.
В типичном коде пользовательского режима значения, возвращаемые функциями API, иногда игнорируются. Разработчик оптимистично полагает, что неудачная попытка вызова функции маловероятна. Насколько уместно такое предположение? Это зависит от конкретной функции. В худшем случае необработанное исключение приведет к сбою процесса, однако система не пострадает.