Одной из неотъемлемых частей операционной системы Windows являются драйверы. В общем случае драйвер — это специальное программное обеспечение, которое обеспечивает работу внешних устройств, а также некоторой базовой функциональности операционной системы.

Драйверы используются не только как механизм управления аппаратными устройствами, но и как составная часть прикладного программного обеспечения. В частности, к подобным решениям относятся различные виртуальные дисководы, технологии защиты от копирования, механизмы шифрования, антивирусное программное обеспечение и многое другое. В своей статье я хотел бы прояснить вопросы о том, как драйверы загружаются в систему, как работают и что делать, если вдруг они начинают давать сбой. Дополнительная информация приведена во врезке «Литература».

Сначала давайте рассмотрим общие моменты, касающиеся взаимоотношений между операционной системой и драйверами, с точки зрения их последующего администрирования.

Прежде всего стоит заметить, что, несмотря на то что драйвер — это обычная программа, в операционной системе Windows она исполняется особым образом и к ней предъявляются специфические требования. В основном это касается контекста работы драйверов — они в большинстве своем работают в нулевом кольце защиты процессора.

Кольца защиты

В процессорах семейства х86 существует защитный механизм, условно называемый кольцами защиты или уровнями привилегий. Всего уровней привилегий четыре, нумеруются они от нулевого до третьего. Самый привилегированный — нулевой уровень. Операционная система Windows использует всего два уровня привилегий, нулевой и третий. Это связано с тем, что изначально система создавалась для нескольких процессоров, в частности для процессоров Alpha, у которых было всего два таких уровня. Конечно, было бы намного лучше, если бы операционная система использовала все эти уровни и располагала ядро на нулевом уровне привилегий, а все остальное — на других уровнях. Тогда код и данные ядра были бы защищены более надежно. К слову сказать, в будущей версии серверной операционной системы Microsoft Windows 2008, ранее известной как Longhorn, предусмотрены отдельные компоненты, использующие первый уровень привилегий.

На нулевом уровне расположено ядро системы, ее управляющие структуры данных. Кроме того, здесь расположены драйверы. Именно по этой причине при написании драйверов нужно соблюдать осторожность и очень внимательно относиться к коду. Неверно написанный драйвер может повредить системные данные ядра или другие драйверы, что приведет к появлению «голубого экрана» BSOD. Этот режим в терминах Windows называется режимом ядра (kernel-mode).

На третьем уровне привилегий расположены собственно пользовательские приложения. Стоит заметить, что из приложений, выполняющихся на третьем уровне привилегий, невозможно получить прямой доступ к памяти, находящейся в нулевом кольце. То есть нельзя ни читать, ни писать туда. Таким образом, уровень ядра аппаратно изолирован от приложений пользовательского уровня. Однако, обладая административными правами в системе, пользователь может установить драйвер, который загрузится в пространство ядра и получит полную власть над операционной системой. Поэтому всегда нужно следить за тем, что и как устанавливают приложения. Кроме того, работая с административными привилегиями, вы подвергаете свою систему риску, поскольку любое приложение может без вашего ведома установить в систему вредоносный драйвер, а вы даже не узнаете об этом. Чтобы этого избежать, в Windows Vista применяется механизм UAC. Этот режим в терминах Windows называется пользовательским (user-mode).

Процесс загрузки

Следующим немаловажным элементом взаимодействия между системой и драйверами является порядок их загрузки. С этой точки зрения драйверы можно разделить на загружаемые в процессе запуска операционной системы, так называемые драйверы этапа BOOT-START, и загружаемые после старта ядра драйверы этапа SYSTEM-START.

BOOT-START. Эти драйверы необходимы для процесса загрузки и инициализации операционной системы. К таким драйверам, например, относятся драйверы файловых систем и драйверы шин. Эти драйверы загружаются в память загрузчиком до запуска ядра операционной системы. Сначала загрузчик читает ветвь реестра SYSTEM. В этой ветви осуществляется поиск драйверов, имеющих значение START, равное нулю, что означает SERVICE_BOOT_START. Эти драйверы загружаются, а инициализирует их диспетчер ввода/вывода после старта ядра.

SYSTEM-START. Эти драйверы загружаются и инициализируются PnP-менеджером (см. врезку «PnP-менеджер») после того, как будут инициализированы драйверы этапа boot-start и построено дерево устройств. Кроме того, после инициализации драйверов устройств PnP-менеджер загружает и инициализирует драйверы, помеченные как SYSTEM-START, но до сих пор не загруженные. Эти драйверы не относятся к каким-либо устройствам или создают неперечисляемые в дереве устройств элементы.

Типы драйверов

Существуют различные классификации драйверов Windows, порой не совсем соответствующие официальной документации. Каждый автор, вероятно, придерживается своей классификации. Попробуем на их основе представить в общем виде структуру типов драйверов.

Согласно MSDN, на базовом уровне драйверы разделяются на два уровня:

  • драйверы пользовательского уровня — исполняются в пользовательском режиме и предоставляют интерфейс между приложениями и драйверами уровня ядра. К ним относятся драйверы принтеров и драйверы виртуальных устройств;
  • драйверы уровня ядра — выполняются на уровне ядра, обладают максимальными возможностями в системе. В сущности, они могут делать в системе и с системой практически все. Они могут сделать даже так, что вы не сможете обнаружить их стандартными средствами. Обычно такие драйверы разделяются на подуровни. В основном верхние уровни получают информацию от приложений, обрабатывают ее и передают драйверам нижнего уровня. К этой категории относятся, к примеру, драйверы файловых систем.

С точки зрения документации MSDN драйверы уровня ядра делятся на следующие слои, опишем их на примере драйверов файловых систем.

1. Драйверы высокого уровня. К ним относятся драйверы файловых систем, которые поддерживают файловые системы, например FAT, NTFS, CDFS. Драйверы высокого уровня всегда зависят от драйверов нижних уровней.

2. Драйверы промежуточного уровня. К ним относятся драйверы, обеспечивающие поддержку виртуальных дисков и зеркалирования. Драйверы промежуточного уровня зависят от драйверов нижнего уровня. Кроме того, они подразделяются на следующие подклассы:

  • функциональные драйверы — управляют конкретным типом устройств. Драйверы шин предоставляют устройства функциональным драйверам через диспетчер PnP;
  • драйверы фильтров дополняют функциональный драйвер. Можно сказать, расширяют его функциональность. Могут находиться как до, так и после своего функционального драйвера, в очереди обработки запроса к этому драйверу. Они могут быть как непосредственно фильтрами данного функционального драйвера, так и фильтрами класса драйверов.

3. Драйверы нижнего уровня. Контролируют ввод/вывод шины, к которой подключено периферийное устройство. Здесь также существуют разные виды драйверов.

  • Драйверы шин — управляют логическими или физическими шинами, такими как PCI, USB. Драйверы шин отвечают за распознавание устройств, подключенных напрямую к этим шинам, оповещение диспетчера PnP об этих устройствах и управление параметрами электропитания шины.
  • Драйверы, не поддерживающие WDM.

Вся эта структура изображена на рисунке.

Рисунок. Уровни драйверов

Реестр

Основным механизмом управления процессом загрузки и настройки драйверов является реестр. В реестре хранится вся системная информация, описывающая драйверы, процесс их загрузки, последовательность загрузки и конфигурация. Настройка драйверов и правила их загрузки описаны в следующих раздела реестра:

HKLMSYSTEMCURRENTCONTROLSETENUM. В этом разделе реестра хранится список оборудования, которое когда-либо было обнаружено или установлено в системе. На первом уровне этого раздела описаны перечисленные выше шины. В подразделе каждой шины — обнаруженные на ней устройства. Внутри подразделов устройств можно найти различные параметры драйвера устройств, таких как DeviceDesc, FriendlyName. Параметр Driver является ссылкой на раздел HKLMSYSTEMCURRENTCONTROLSETSERVICES, в котором описан файл драйвера.

Кроме того, в этих подразделах есть важный параметр ClassGUID, описывающий класс, к которому данное устройство относится. По большому счету это ссылка на раздел HKLMSYSTEMCURRENTCONTROLSETCONTROLCLASS.

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

HKLMSYSTEMCURRENTCONTROLSETCONTROLCLASS. В этом разделе реестра описаны все классы устройств, присутствующие в системе. Параметры классов могут быть следующими:

  • (default) — описывает дружественное имя класса;
  • Class — описывает имя класса;
  • EnumPropPages32 — описывает библиотеку, которая предоставляет графический интерфейс настройки драйвера. Здесь может содержаться имя библиотеки и имя точки входа;
  • Install32 — библиотека, обеспечивающая установку драйверов данного класса;
  • Icon — идентификатор ресурсов в библиотеке установки, указывающий на значок, который применяется везде, где приводится информация о данном классе.

Есть еще несколько необязательных параметров, наиболее важными из которых в контексте данной статьи являются:

  • UpperFilters и LowerFilters. Здесь описаны имена драйверов-фильтров, которые привязаны к данному классу. Менеджер PnP загружает эти драйверы для каждого устройства, относящегося к этому классу.

HKLMSYSTEMCURRENTCONTROLSETSERVICES. В этом разделе описан сам файл драйвера. В нем есть:

  • ImagePath — путь к исполняемому образу драйвера;
  • Type — тип драйвера: 1 — режим ядра, 2 — пользовательский режим;
  • Start — тип загрузки: 0 — boot-start, 1 — system-start, 2 — auto, 3 — manual, 4 — disabled. Тип загрузки привязан не только к драйверам, но и к системным службам. Параметры 0 и 1 относятся к драйверам;
  • ErrorControl — значение 1 говорит о том, что в случае ошибки при загрузке система должна записать ошибку в журнал и выдать сообщение о ней.

Замечу, что здесь описаны не только драйверы, но и службы, которые выполняются в системе.

Процесс загрузки драйверов

Теперь пришло время рассмотреть самое интересное — алгоритм просмотра реестра и загрузки драйверов. В общем случае предусмотрено несколько основных режимов загрузки, в рамках этой статьи я коснусь двух из них: обычного режима и безопасного режима (safe boot).

Вообще этот процесс многоуровневый, он касается многих компонентов системы, в частности PnP-менеджера. Здесь мы будем рассматривать его лишь в отношении загрузки драйверов.

Обычный режим. Обычный режим на то и обычный, что в нем загружаются все драйверы, которые указаны в реестре. Происходит это так:

  • драйвер шины, обнаружив устройство, передает его уникальный идентификатор PnP-менеджеру;
  • PnP-менеджер, получив этот идентификатор, находит в разделе HKLMSYSTEMCURRENTCONTROLSETENUM соответствующее ему устройство и определяет, какие файлы необходимо загрузить, используя ссылки на ключи HKLMSYSTEMCURRENTCONTROLSETSERVICES и HKLMSYSTEMCURRENTCONTROLSETCONTROLCLAS;
  • загружается драйвер, указанный в параметре LowerFilter самого драйвера устройства;
  • загружается драйвер, указанный в параметре LowerFilter класса устройств, к которым относится драйвер
  • загружается драйвер самого устройства — функциональный драйвер;
  • загружается драйвер, указанный в параметре UpperFilter самого драйвера устройств;
  • загружается драйвер, указанный в параметре UpperFilter класса устройств, к которым относится драйвер.

Эта последовательность загрузки влияет на последовательность обработки запросов к драйверам. Запросы обрабатываются в порядке, обратном загрузке, т.е. начиная от UpperFilter-драйверов.

Безопасный режим. В безопасном режиме алгоритм загрузки такой же. Исключение составляет раздел HKLMSYSTEMCURRENTCONTROLSET CONTROLSAFEBOOT. Этот раздел имеет два подраздела: Minimal и Network. Их название говорит само за себя. При загрузке в обычном защищенном режиме загружаются только драйверы, которые есть в списке подраздела Minimal. Когда же вы выбираете параметр загрузки с поддержкой сетевых драйверов, используется список подраздела Network.

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


Андрей Вернигора (eosfor@gmail.com)  — администратор баз данных и системный администратор на одном из предприятий компании «Укртранснафта». Имеет сертификат MCP


Литература

  1. Russinovich M. E., Solomon D. A. Microsoft Windows Internals, Fourth Edition: Microsoft Windows Server 2003, Windows XP and Windows 2000. Microsoft Press
  2. Walter. O. Programming the Microsoft Windows Driver Model. 2nd ed.

PnP-менеджер

PnP-менеджер — это компонент операционной системы, который отвечает за обнаружение изменений в аппаратном обеспечении и реагирование системы на них. Проще говоря, если вы подключаете новое оборудование, за его обнаружение, настройку и загрузку драйверов отвечает именно он. Основные задачи, которые выполняет PnP-менеджер, следующие:

  • распознает установленные устройства, перечисляет устройства, установленные в систему во время загрузки и в процессе работы;
  • распределяет между устройствами такие ресурсы системы, как прерывания, память, шины и устройства ввода/вывода;
  • загружает драйверы устройств;
  • обеспечивает оповещение приложений о появлении/изъятии устройств.