Разработка драйверов виртуальных устройств.

05.04.2019

Получите комплект разработки драйверов для Windows 10 (WDK) и другие средства, необходимые для создания, тестирования и развертывания драйверов и приложений Магазина Windows. В Windows 10 среда разработки драйверов и отладчики Windows встроены в Visual Studio.

Комплект разработки драйверов для Windows 10 (WDK)

Ознакомьтесь с подборкой нового и измененного содержимого для Windows 10, связанного с драйверами. К областям улучшения относятся камера, печать, дисплей, функция NFC, беспроводная сеть, функция Bluetooth и пр.

Универсальные драйверы Windows

Напишите один драйвер, который будет работать как с версией Windows 10 для классических выпусков, так и с Windows 10 для мобильных устройств, а также другими выпусками Windows 10, имеющими общий набор интерфейсов.

Примеры

Примеры помогут вам в разработке драйверов для Windows. Примеры кода станут ценными помощниками и в разработке нового драйвера, и в портировании старого драйвера в новую версию Windows.

Windows Driver Framework

Платформы драйверов Windows Driver Frameworks (WDF) – это набор библиотек, который можно использовать для разработки драйверов устройств, способных работать с Windows. Комплект WDF состоит из платформы драйверов, работающих в режиме ядра (KMDF), и платформы драйверов, работающих в пользовательском режиме (UMDF).

Платы разработки оборудования

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

Разработка партнерских приложений

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

Информация по программированию драйверов Windows. С чего начать. Где скачать DDK. Что читать.

Видимо, перед вами стоит задача взаимодействия с аппаратурой. Наверное, эта аппаратура подключена не к COM порту. Для работы с RS232 Windows API имеет практически все возможности, за исключением взаимодействия с микроконтроллерами по протоколу с девятым адресным битом, да и это возможно осуществить. А вот если требуется вывести байт данных в параллельный порт или еще куда, то тут OpenFile("LPT",... ) уже не работает. На ассемблере тоже бесполезно. Наверное все уже в курсе, что код типа [ out dx,al ] под 2000 -XP ничего кроме ошибки не дает. Что же делать? Надо сделать драйвер под Windows . И тут возникает вопрос, а как бы побыстрее научиться писать драйвера , а еще лучше разработать один драйвер для Windows и и забыть, как о кошмарном сне. Возможно многие сочтут, что программировать драйвера, а особенно отлаживатьдрайверапод Windows , не самое приятное занятие.

Радует, тот факт, что за последние 5 лет появилась рускоязычная литература на тему разработки драйверов ибо осваивать эту тему по документации Microsoft DDK весьма утопичное занятие.

Xочется отметить книгу : " Программирование драйверов для Windows." . Издательство: Бином. ISBN: 5-9518-0099-4

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

Понятно, что для создания дравера необходимо инструментальное средство разработки драйверов , и чем оно мощнее, тем быстрее вы достигните цели. Самое примитивное из средств рахзработки драйверов это , это DDK, Driver Development Kit.

И вот что досадно, если в 2000-2002 году DDK 2000 можно было скачать бесплатно , то сейчас бесплатно доступна только Windows Server 2003 DDK , причем скачать нельзя, можно только получить CD по почте, при этом необходимо иметь кредитку, т.к. DDK то бесплатно, но пересылка диска будет стоить 25 $. Деньги не великие, так что если имеете кредитку и желаете DDK 2003 , вот ссылка http://www.microsoft.com/whdc/devtools/ddk/default.mspx

Более навороченный продукт DDK Suite 3 , обойдется уже в 199 $ плюс те же 25 за доставку.

Найти DDK на рынке за 60 рублей, наверное можно но сложно, слишком редко востребуемый продукт. Ну а если нет кредитки или времени на ожидание диска, не отчаивайтесь, и не благодарите:)

Скачивайте все файлы что там есть. Распакуете ddk.rar и запускайте ksetup.exe. Спасибо Яндексу за 67 мегабайт.

Правда писать драйвера при помощи только DDK не самый удобный на сегодня способ , а посему предлагаю обратить внимания на два продукта.

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

    Работающие через некий универсальный драйвер.

    Полноценные драйвера работающие в режиме ядра.

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

Мастер создания драйверов, DriverWizard (Jungo) сгенерит код, который вы сможете вставить в свои программы и обращаться к портам в-в, памяти и даже использовать прерывания. Все очень просто: Утром установите WinDriver , вечером ваша программа будет работать с аппаратурой, но остерегайтесь WinDrivera . Покупать вы его конечно не будете, и при установке, выберете 30-дневную копию. В течении месяца все будет работать и Driver Wizard и все программы его использующие. Потом DriverWizard работать перестанет, но к тому времени вы то уже поймете, что он и не нужен. Нужна только библиотека WINDRVR.SYS, к оторая и обеспечивает взаимодействие с портами Вашей программе. Так вот этот самый WINDRVR.SYS, через который будет работать ваша программа, в отличии от DriverWizarda не подает никаких признаков того, что срок истек и он больше работать не будет. Драйвер открывается как и раньше, все функции возвращают результат SUCCESS однако программа не работает, потому что драйвер пишет не то и не туда и читает не оттуда и не всегда. При этом можно подумать, что проблемы с аппаратурой, поэтому при использовании WinD ri vera лучше отыскать serial number и зарегистрировать. Слишком коварная у него система защиты.

Numega Driver Studio .имеет в своем составе аналогичный компонент: Driver Agent сгенерит все необходимое для использования универсального драйвера. Вы даже сможете создать свой файл.sys, который будет работать в составе ядра и делать там все, что вы запрограммируете, например обрабатывать прерывания. При этом вникать опять же ни во что не придется. За день разработаете свой драйвер.

Оба пакета содержат средства для написания настоящих драйверов, НО при помощи DriverStudio или WinDriver это делать значительно проще, чем при помощи только DDK , в дополнение они имеют хорошую документацию касающуюся общих вопросов драйверов, более читаемую чем в DDK . Кстати DDK для работы с ними необходимо установить .

Установив Numega Driver Works, Вы открываете студию (не Driver , а Microsoft Visual Studio ), выбираете там NewProject и видете в окне мастера рядом с
MFC App Wizard
NT/WDM Driver Wizard
Мастер за 9 шагов, сгенерит проект из которого получается драйвер и exe-шник, который этот драйвер тестирует. Кроме того в Driver Studio входит (я бы назвал это Driver Developmen Foundational Classes ) набор классов, которые содержат все необходимое для разработки драйверов, так же как MFC для разработки приложений.

Универсальный драйвер, который позволяет обращаться к портам ввода-вывода. Больше он ничего не может, но в большинстве случаев можно обойтись и этим. Драйвер этот называется PortIo.sys и входит в состав примеров прилагаемых к Numega Driver Works. Я его скомпилировал, вам остается скачать и использовать. Драйвер предоставляет 4 функции: Open, Close,Read и Write. Есть тестовое приложение которое демонстрирует как эти функции использовать.
Чтобы установить драйвер надо:

  1. Поместить файл portio.sys в C:\WINDOWS\SYSTEM32\DRIVERS\
  2. Прописать его в реестре. Для XP и 2000 это делается командой regini portio.ini в результате в разделе HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services появится раздел PortIo .
    В нем параметры:
    ErrorControl 0x00000001
    ImagePath \SystemRoot\System32\Drivers\portio.sys
    Type 0x00000001
    Start 0x00000002
    Перезагрузите систему.

    Драйвер установлен можно использовать.
    Смотрите тестовое приложение.

Как писать драйвера (часть 5)

Итак, мы возвращаемся к драйверам.

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

Сегодня мы поговорим о коммуникации программы с драйвером.

В одной из предыдущих статей описаны были функции типа Filter:

extern NTSTATUS FilterOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

extern NTSTATUS FilterClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

extern NTSTATUS FilterRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

extern NTSTATUS FilterWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

extern NTSTATUS FilterIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

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

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

Для этого используются вышеназванные функции.

FilterOpen вызывается когда в программе вызвано обращение к драйверу с помощью функции CreateFile

FilterClose – CloseHandle()

FilterRead/FilterWrite – ReadFile/WriteFile

FilterIoControl – DeviceIoControl() соответственно.

Для правильного завершения работы каждой из этих функций – нужно обеспечить передачу в программу необходимых данных.

NTSTATUS FilterOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

// инициализация любых управляющих параметров, например структуры управляющих данных

Irp->IoStatus.Status = NDIS_STATUS_SUCCESS; // Возращаемое значение – ошибка или нормальное. При нормальном завершении – будет передан HANDLE на устройство, в нашем случае на драйвер.

Irp->IoStatus.Information = 0; // Количество переданных вверх байт – в нашем случае 0 потому как нет передаваемых параметров.

// Завершение работы.

return NDIS_STATUS_SUCCESS; // Нормальный код возврата.

Эта форма будет использоваться в том или ином виде в каждой из этих функций.

Точно так же выглядит и функция закрытия:

NTSTATUS FilterClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

// Код окончания работы с драйвером.

Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;

Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return NDIS_STATUS_SUCCESS;

В драйвере можно создать например просто элемент для нашего примера – например, описать глобальную переменную DWORD Port; Ее будем испрользовать для задания номера порта для перехвата.

Определим Default значение для порта равное 80 (стандартный порт http протокола) и проведем его инициализацию в функции Open и де инициализацию в Close. Так мы сможем контролировать старт активной фазы работы драйвера и ее окончание.

Функции Write & Read можно использовать для передачи любого количества информации в драйвер и обратно.

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

В нашем примере передавать в драйвер и назад нечего поэтому напишем Write/Read функции в виде готовых болванок, но так как наша цель построить работающий пример – то передадим абстрактную последовательность вверх в аппликацию.

Для этого создайте в этом же месте глобальную переменную вот такого вида:

unsigned char TestStr = "abcdefghi";

NTSTATUS FilterRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

ULONG BytesReturned = 0;

////////////////////////////////////////////////////////////////////////

// Get input parameters

PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); // Содержит стек Irp

ULONG BytesRequested = IrpStack->Parameters.Read.Length; // Длина принятых данных –равна параметру максимально запрошенной длины в функции ReadFile

if (BytesRequested <10) // Если запрошено меньше нашей тестовой длины – вернуть ошибку

BytesReturned = 0;

Status = STATUS_INVALID_BUFFER_SIZE;

// Если все в порядке – копировать буфер в выходной буфер стека.

NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer, TestStr, 10);

BytesReturned = 10;

Status = NDIS_STATUS_SUCCESS;

// Отправить

Irp->IoStatus.Status = Status;

Irp->

IoCompleteRequest(Irp, IO_NO_INCREMENT);

///////////////////////////////////////////////////////////////////////////////////////////////

NTSTATUS FilterWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

ULONG BytesReturned = 0;

// Здесь все работает аналогично.

Irp->IoStatus.Status = Status;

Irp->IoStatus.Information = BytesReturned;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

Функции симметричны.

Теперь мы подошли к функции управления.

Она сама работает точно также как и все функции перечисленные выше – с одной разницей: В ней принимаемым параметром является код операции, который надо установить в драйвер.

Можно конечно придумать свой формат данных – передаваемых в WriteFile, который расшифровывать внутри драйвера и так решать, что делать или не делать, однако стоит использовать уже готовый механизм, предоставленный Microsoft-ом.

Описание кода комманды выглядит так:

#define IOCTL_SET_COMMAND1 // наш код управления

CTL_CODE (FILE_DEVICE_UNKNOWN, // Тип кода

0xF07, // Цифровое значение

METHOD_BUFFERED, // Метод операции

FILE_ANY_ACCESS) // Права доступа.

Итак мы описали код управления, вызов которого будет выглядеть в программе так:

res = DeviceIoControl(

hFile, // Handle драйвера из функции CreateFile

(DWORD) IOCTL_SET_COMMAND1, // Комманда

(LPVOID)0, (DWORD)0, (LPVOID)NULL, (DWORD)0, (LPDWORD)&bytesReturned, NULL

Вызов такой функции приведет к обращению драйвером к функции FilterIoControl!

NTSTATUS FilterIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

ULONG BytesReturned = 0;

PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);

ULONG IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;

PVOID InfoBuffer = Irp->AssociatedIrp.SystemBuffer;

ULONG InputBufferLen = IrpStack->Parameters.DeviceIoControl.InputBufferLength;

ULONG OutputBufferLen = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;

switch(IoControlCode) {

case IOCTL_SET_COMMAND1:

// Здесь мы можем сменить наш номер порта с 80 на, к примеру, 25.

Irp->IoStatus.Status = Status;

Irp->IoStatus.Information = BytesReturned;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

Описания Input/Output буферов привожу для того, чтобы при необходимости получения и еще каких либо сопутствующих параметров, было ясно, где их получать, скажем, в драйвере нашего примера, команда 1 может нести в качестве параметра новый номер порта для перехвата.

Давайте теперь опишем логику управления драйвером перехватчиком.

Для перехвата определяются в начале параметры перехвата, адрес, порт и т.д.

Вносится список возможных портов к перехвату (по необходимости).

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

Например, тип режима – прозрачный, в этом случае не перехватывается ничего.

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

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

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

На сегодня пока все.

Из книги Журнал «Компьютерра» №45 от 01 декабря 2005 года автора Журнал «Компьютерра»

ПИСЬМОНОСЕЦ: Писать или дарить? Здравствуйте!Пишу двумя пальцами, ибо остальные: забинтованы…Эх, люди, вы наивно думаете, что судный день еще далеко, и всякие там толпы киборгов-убийц, бродящих по догорающим развалинам в поисках остатков человеческого рода, - сценарий для

Из книги Блоги. Новая сфера влияния автора Попов Антон Валерьевич

Что писать? Мост длиною в блог Метки: блоговедение, темы блога, что такое блогПисать обо всем сразу – это как плыть в броуновском движении, не сдвигаясь с места. Блог должен быть похож на мост: когда по нему идешь или едешь, то понимаешь, что рано или поздно окажешься на

Из книги Как писать драйвера автора

Как писать 33 буквы в руках мастера Метки: блогословие, приманкиВ любом учебнике по журналистике написано о том, что статья теряет читателей после каждого абзаца. А абзац, встречающий читателя, – это заголовок. В некоторых RSS-агрегаторах вообще не видно ничего, кроме

Из книги Пишем драйвер Windows на ассемблере автора Компьютеры Автор неизвестен -

Как писать драйвера (часть 1) Предисловие. Драйвера под Windows являются для большей массы программистов, "тайной за семью печатями". И вовсе не потому, что это что-то архисложное, сколько по причине абсолютной недокументированности идеологии.Начав заниматься этой темой я

Из книги Facebook: как найти 100 000 друзей для вашего бизнеса бесплатно автора Албитов Андрей

Часть первая: "Что нужно для компиляции простейшего драйвера?" Для разных типов Windows вам понадобиться разный набор программ.В любом случае надо скачать Win DDK (Driver Development Kit), для той платформы, под которую пишется драйвер. Его можно брать с разных источников, лично я

Из книги Ководство автора Лебедев Артём Андреевич

Как писать драйвера (часть 2) Прежде, чем хвататься за описание самого драйвера, давайте определимся с типами существующих драйверов.По существующему в DDK разделению сам Microsoft подразделяет драйвера на следующие типы:– Kernel-Mode Drivers;– Kernel Streaming Drivers;– Graphics Drivers;– Network

Из книги Интернет – легко и просто! автора Александров Егор

Из книги Прибыльный блог: создай, раскрути и заработай автора Литвин Евгений

Как писать драйвера (часть 5) Итак, мы возвращаемся к драйверам.Справедливости ради, стоит отметить, что на сайте эта тема – одна из самых популярных, так что, кому нужны более глубокие знания, может обращаться к нам на форум, там обсуждаются конкретные проблемы.Сегодня мы

Из книги Быстрые деньги в Интернете автора Парабеллум Андрей Алексеевич

Часть 2. API для WDM драйвера. Большинство функций драйверного API, которые нас интересуют, предоставляются модулем ntoskrnl.exe.Для их использования надо сделать следующее:1) Объявить типы данных и определить константы.Большинство определений для C находятся в файлах ntdef.h и wdm.h.2)

Из книги IT-безопасность: стоит ли рисковать корпорацией? автора Маккарти Линда

На каком языке писать сообщения? Если ваш бизнес ориентирован на одну страну или языковую группу, то эта проблема перед вами не стоит. Другой вопрос, если группа международная. Вот скриншот (см. рис. 49), демонстрирующий подобный пример. В группе из 70 тысяч друзей 40 %

Из книги Программист-фанатик автора Фаулер Чед

§ 55. Как писать слово «интернет»? - Ну что, Знайка? - стали спрашивать коротышки, подбегая к нему. - Как ты объяснишь это? - Что же тут объяснять? - развел Знайка руками?… Н. Носов. Незнайка на Луне В Академии наук Заседает князь Дундук. Говорят, не подобает Дундуку

Из книги автора

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

Из книги автора

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

Из книги автора

Из книги автора

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

Из книги автора

Совет 3 Умения писать код мало Недостаточно выбрать технологию, на которую стоит сделать ставку. В конце концов, разве знание технологии - не товар, который нужно продать? Ты не сможешь расслабленно совершенствовать навыки программирования, оставив связанные с бизнесом

Драйвер-это основа взаимодействия системы с устройством в ОС Windows.Это одновременно удобно и неудобно.
Про удобства я разъяснять не буду — это и так понятно,
а заострюсь я именно на неудобствах драйверов.
В сложившейся ситуации пользователь полностью подчинён воле производителя
— выпусти тот драйвер — хорошо, а не выпустит…
Только продвинутый пользователь, имеющий голову на плечах
(особенно, если он ешё и программер) не станет мириться с таким положением дел
— он просто возьмёт и сам напишет нужный драйвер.
Это нужно и взломщику: драйвер — это удобное окошко в ring0,
которое является раем для хакера. Но хоть написать драйвер и просто,
да не совсем — есть масса подводных камней. Да и документированность данного вопроса на русском языке оставляет желать лучшего.
Этот цикл статей поможет тебе во всём разобраться.
Приступим.

Интра

Хочу сразу же сделать несколько предупреждений.
Данная статья всё-таки подразумевает определённый уровень подготовки.
Драйвера-то ведь пишутся на C(++) с большим количеством ассемблерных вставок.
Поэтому хорошее знание обоих языков весьма желательно (если не сказать — обязательно).
Если же ты пока не можешь этим похвастаться,
но желание писать драйвера есть — что ж, так как эта статья вводная, в конце её будет приведён список полезной литературы,
ссылок и т.д. Но помни: учить тебя в этом цикле статей программированию как таковому я тебя не буду.
Может как-нибудь в другой раз. Согласен? Тогда поехали!

Теория

Скоро здесь, возможно, будет стоять твоё имя.

Практически в любом деле, как мне кажется, нужно начинать с теории.
Вот и начнём с неё. Для начала уясним себе поточнее основные понятия.
Первое: что есть драйвер? Драйвер — в сущности
кусок кода ОС, отвечающий за взаимодействие с аппаратурой.
Слово «аппаратура» в данном контексте следует понимать в самом широком смысле.
С момента своего появления как такого до сегодняшнего дня драйвер беспрерывно эволюционировал.
Вот, скажем, один из моментов его развития. Как отдельный и довольно независимый модуль драйвер сформировался не сразу.
Да и сейчас этот процесс до конца не завершён:
ты наверняка сталкивался с тем, что во многих
дистрибутивах никсов для установки/перестановки etc драйверов нужно перекомпилировать ядро,
т.е. фактически заново пересобирать систему.
Вот, кстати ещё один близкий моментец: разные принципы работы с драйверами в Windows 9x и NT.
В первом процесс установки/переустановки драйверов проходит практически без проблем,
во втором же случае это тяжёлое и неблагодарное дело,
для «благополучного» завершения которого нередко приходится прибегать к полной переустановке ОС.
А зато в Windows 9x… так,стоп,открывается широкая и волнующая тема,
которая уведёт меня далеко от темы нынешней статьи,
так что вернёмся к нашим баранам… ой,то есть к драйверам.
В порядке общего развития интересно сравнить особенности драйверов в Windows и *nix(xBSD) системах:

1) Способ работы с драйверами как файлами (подробнее см. ниже)
2) Драйвер, как легко заменяемая честь ОС (учитывая уже сказанные выше примечания)
3) Существование режима ядра

Теперь касательно первого пункта. Это значит,
что функции, используемые при взаимодействии с файлами,
как и с драйверами, практически идентичные (имеется в виду лексически):
open, close, read и т.д. И напоследок стоит отметить идентичность механизма
IOCTL (Input/Output Control Code-код управления вводом-выводом)
-запросов.

Драйвера под Windows делятся на два типа:
Legacy (устаревший) и WDM (PnP). Legacy драйверы (иначе называемые «драйверы в стиле
NT") чрезвычайно криво работают (если работают вообще)
под Windows 98, не работают с PnP устройствами, но зато могут пользоваться старыми функциями
HalGetBusData, HalGetInterruptVector etc, но при этом не имеют поддержки в лице шинных драйверов.
Как видишь, весьма средненький драйвер. То ли дело
WDM: главный плюс — поддержка PnP и приличненькая совместимость:
Windows 98, Me, 2000, XP, 2003, Server 2003 и т.д. с вариациями; но он тоже вынужден за это расплачиваться:
например, он не поддерживает некоторые устаревшие функции
(которые всё таки могут быть полезны). В любом случае,
не нужно ничего воспринимать как аксиому, везде бывают свои исключения.
В некоторых случаях лучше написания Legacy драйвера ничего не придумать.

Как ты наверняка знаешь, в Windows есть два мода работы:
User Mode и Kernel Mode — пользовательский режим и режим ядра соответственно.
Первый — непривилегированный, а второй — наоборот.
Вот во втором чаще всего и сидят драйвера (тем
более, что мы в данный момент говорим именно о драйверах режима ядра).
Главные различия между ними: это доступность всяких привилегированных команд процессора.
Программировать (а уж тем более качественно) в Kernel mode посложнее будет,
чем писать прикладные незамысловатые проги.
А драйвера писать без хорошего знания Kernel mode — никак.
Нужно попариться над назначением выполнения разнообразных работ отдельному подходящему уровню IRQL, желательно выучить новое API (так как в Kernel mode API отличается от прикладного)…
в общем, предстоит много всяких радостей. Но тем не менее,
это очень интересно, познавательно, и даёт тебе совершенно иной уровень власти над компьютером.

А раз уж я упомянула про IRQL, разьясню и это понятие.
IRQL (Interrupt Request Level — уровень приоритета выполнения) — это приоритеты,
назначаемые специально для кода, работающего в режиме ядра.
Самый низкий уровень выполнения — PASSIVE_LEVEl. Работающий поток может быть прерван потоком только с более высоким
IRQL.

Ну и напоследок разъясним ещё несколько терминов:

1) ISR (Interrupt Service Routine) — процедура обслуживания прерываний.
Эта функция вызывается драйвером в тот момент,
когда обслуживаемая им аппаратура посылает сигнал прерывания.
Делает самые необходимые на первый момент вещи:
регистрирует callback — функцию и т.д.

2) DpcForISR (Deferred Procedure Call for ISR) — процедура отложенного вызова для обслуживания прерываний.
Эту функцию драйвер регистрирует в момент работы ISR для выполнения основной работы.

3) IRP (Input/Output Request Packet) — пакет запроса на ввод — вывод.
Пакет IRP состоит из фиксированной и изменяющейся частей.
Вторая носит название стека IRP или стека ввода — вывода (IO stack).

4) IO stack location — стек ввода — вывода в пакете IRP.

5) Dispatch Routines (Рабочие процедуры) — эти функции регистрируются в самой первой (по вызову) процедуре драйвера.

6) Major IRP Code — старший код IRP пакета.

7) Minor IRP Code — соответственно, младший код IRP пакета.

8) DriverEntry — эта функция драйвера будет вызвана первой при его загрузке.

9) Layering (Многослойность) — данной возможностью обладают только WDM — драйвера.
Она заключается в наличии реализации стекового соединения между драйверами.
Что такое стековое соединение? Для этого необходимо знать про Device
Stack (стек драйверов) — поэтому я обязательно вспомню про всё это чуточку ниже.

10) Device Stack, Driver Stack (стек устройств, стек драйверов) — всего лишь
объемное дерево устройств. Его, кстати, можно рассмотреть во всех подробностях с помощью программы
DeviceTree (из MS DDK), например.

11) Стековое соединение — как и обещала, объясняю. В стеке драйверов самый верхний драйвер — подключившийся позднее.
Он имеет возможность посылать/переадресовывать IRP запросы другим драйверам,
которые находятся ниже его. Воти всё. Правда,просто?

12) AddDevice — функция, которую обязательно должны поддерживать WDM драйверы.
Её название говорит само за себя.

13) Device Object, PDO, FDO (Объект устройства, физический,
функциональный) — при подключении устройства к шине она создаёт PDO.
А уже к PDO будут подключаться FDO объекты WDM драйверов.
Обьект FDO создаётся самим драйвером устройства при помощи функции IOCreateDevice.
Обьект FDO также может иметь свою символическую ссылку, от которой он будет получать запросы от драйвера.
Это что касается WDM драйверов. С драйверами «в стиле NT» ситуация несколько иная.
Если он не обслуживает реальных/PnP устройств,
то PDO не создаётся. Но для связи с внешним миром без FDO не обойтись.
Поэтому он присутствует и тут.

14) Device Extension (Расширение обьекта устройства) — «авторская» структура,
т.е. она полностью определяется разработчиком драйвера.
Правилом хорошего тона считается, например,
размещать в ней глобальные переменные.

15) Monolithic Driver (Монолитный драйвер) — это драйвер,
который самостоятельно обрабатывает все поступающие
IRP пакеты и сам работает с обслуживаемым им устройством
(в стеке драйверов он не состоит). Данный тип драйверов используется только если обслуживается не
PnР устройство или же всего лишь требуется окошко в ring0.

16) DIRQL (уровни аппаратных прерываний) —
прерывания, поступающие от реальных устройств, имеют наивысший приоритет IRQL,
поэтому для них решено было придумать специальное название
(Device IRQL).

17) Mini Driver (Мини — драйвер) — чуть меньше «полного» драйвера.
Обычно реализуется в виде DLL-ки и имеет оболочку в виде «полного» драйвера.

18) Class Driver (Классовый драйвер) — высокоуровневый драйвер,
который предоставляет поддержку класса устройств.

19) РnP Manager (PnP менеджер) — один из главных компонентов операционной системы.
Состоит из двух частей: PnP менеджера пользовательского и «ядерного» режимов.
Первый в основном взаимодействует с пользователем;
когда тому нужно, например, установить новые драйвера и т.д.
А второй управляет работой, загрузкой и т.д. драйверов.

20) Filter Driver (фильтр — драйвер) — драйверы, подключающиеся к основному драйверу либо сверху
(Upper), либо снизу (Lower). Фильтр драйверы (их может быть несколько) выполняют фильтрацию IRP пакетов.
Как правило, для основного драйвера Filter Drivers неощутимы.

21) Filter Device Object — объект устройства, создаваемый фильтр — драйвером.

22) HAL (Hardware Abstraction Layer) — слой аппаратных абстракций.
Данный слой позволяет абстрагироваться компонентам операционной системы от особенностей конкретной платформы.

23) Synchronization Objects (Обьекты синхронизации) — с помощью этих
объектов потоки корректируют и синхронизируют свою работу.

24) Device ID — идентификатор устройства.

25) DMA (Direct Memory Access) — метод обмена данными между устройством и памятью
(оперативной) в котором центральный процессор не принимает участия.

25) Polling — это особый метод программирования, при котором не устройство посылает сигналы прерывания драйверу,
а сам драйвер периодически опрашивает обслуживаемое им устройство.

26) Port Driver (Порт-драйвер) — низкоуровневый драйвер,
принимающий системные запросы. Изолирует классовые драйверы устройств от аппаратной специфики последних.

Ну вот, пожалуй, и хватит терминов. В будущем,
если нужны будут какие-нибудь уточнения по теме,
я обязательно их укажу. А теперь, раз уж эта статья
теоретическая, давай-ка взглянем на архитектуру Windows NT с высоты птичьего полёта.

Краткий экскурс в архитектуру Windows NT

Наш обзор архитектуры Windows NT мы начнём с разговора об уровнях разграничения привилегий. Я уже упоминала об user и kernel mode.
Эти два понятия тесно связаны с так называемыми кольцами (не толкиеновскими).
Их (колец) в виде всего четыре: Ring3,2,1 и 0. Ring3 — наименее привилегированное кольцо,
в котором есть множество ограничений по работе с устройствами,
памятью и т.д. Например, в третьем кольце нельзя видеть адресное пространство других приложений без особого на то разрешения. Естественно,
трояну вирусу etc эти разрешения получить будет трудновато, так что хакеру в третьем кольце жизни никакой. В третьем кольце находится user mode. Kernel mode сидит в нулевом кольце — наивысшем уровне привилегий. В этом кольце можно всё:
смотреть адресные пространства чужих приложений без каких — либо ограничений и разрешений, по своему усмотрению поступать с любыми сетевыми пакетами, проходящими через машину, на всю жизнь скрыть какой-нибудь свой процесс или файл и т.д. и т.п. Естественно,
просто так пролезть в нулевое кольцо не получиться:
для этого тоже нужны дополнительные телодвижения. У легального драйвера с этим проблем нет:
ему дадут все необходимые API — шки, доступ ко всем нужным системным таблицам и проч. Хакерской же нечисти опять приходиться туго:
все необходимые привилегии ему приходиться «выбивать»
незаконным путём. Но это уже тема отдельной статьи, и мы к ней как-нибудь ещё вернёмся. А пока продолжим.

У тебя наверняка возник законный вопрос:
а что же сидит в первом и втором кольцах? В том то всё и дело,
что программисты из Microsoft почему — то обошли эти уровни своим вниманием. Пользовательское ПО сидит в user mode,а всё остальное (ядро,
драйвера…) — в kernel mode. Почему они так сделали — загадка, но нам это только на руку. А теперь разберёмся с компонентами (или, иначе говоря, слоями) операционной системы Windows
NT.

Посмотри на схему — по ней многое можно себе уяснить. Разберём её подробнее.
С пользовательским режимом всё понятно. В kernel mode самый низкий уровень аппаратный. Дальше идёт HAL, выше — диспетчер ввода — вывода и драйвера устройств в одной связке, а также ядрышко вместе с исполнительными компонентами. О HAL я уже говорила, поэтому поподробнее поговорим об исполнительных компонентах. Что они дают? Прежде всего они приносят пользу ядру. Как ты уже наверняка уяснил себе по схеме, ядро отделено от исполнительных компонентов. Возникает вопрос:
почему? Просто на ядре оставили только одну задачу:
просто управление потоками, а все остальные задачи (управление доступом,
памятью для процессов и т.д.) берут на себя исполнительные компоненты (еxecutive). Они реализованы по модульной схеме, но несколько компонентов её (схему) не поддерживают. Такая концепция имеет свои преимущества:
таким образом облегчается расширяемость системы. Перечислю наиболее важные исполнительные компоненты:

1) System Service Interface (Интерфейс системных служб)
2) Configuration Manager (Менеджер конфигурирования)
3) I/O Manager (Диспетчер ввода-вывода,ДВВ)
4) Virtual Memory Manager,VMM (Менеджер виртуальной памяти)
5) Local Procedure Call,LPC (Локальный процедурный вызов)
6) Process Manager (Диспетчер процессов)
7) Object Manager (Менеджер объектов)

Так как эта статья — первая в цикле, обзорная, подробнее на этом пока останавливаться не будем. В процессе практического обучения написанию драйверов, я буду разъяснять все неясные термины и понятия. А пока перейдём к API.

API (Application Programming Interface) — это интерфейс прикладного программирования. Он позволяет обращаться прикладным программам к системным сервисам через их специальные абстракции. API-интерфейсов несколько, таким образом в Windows-системах присутствуют несколько подсистем. Перечислю:

1) Подсистема Win32.
2) Подсистема VDM (Virtual DOS Machine — виртуальная ДОС — машина)
3) Подсистема POSIX (обеспечивает совместимость UNIX — программ)
4) Подсистемиа WOW (Windows on Windows). WOW 16 обеспечивает совместимость 32-х разрядной системы с 16-битными приложениями. В 64-х разрядных системах есть подсистема WOW 32,
которая обеспечивает аналогичную поддержку 32 — битных приложений.
5) Подсистема OS/2. Обеспечивает совместимость с OS/2 приложениями.

Казалось бы, всё вышеперечисленное однозначно говорит в пользу WINDOWS NT систем!
Но не всё так хорошо. Основа WINDOWS NT (имеются ввиду 32-х разрядные версии) — подсистема Win32. Приложения, заточенные под одну подсистему не могут вызывать функции другой. Все остальные (не Win32) подсистемы существуют в винде только в эмуляции и реализуются функции этих подсистем только через соответствующие функции винды. Убогость и ограниченность приложений, разработанных, скажем, для подсистемы POSIX и запущенных под винду — очевидны.
Увы.

Подсистема Win32 отвечает за графический интерфейс пользователя, за обеспечение работоспособности Win32 API и за консольный ввод — вывод. Каждой реализуемой задаче
соответствуют и свои функции: функции, отвечающие за графический фейс,
за консольный ввод — вывод (GDI — функции) и функции управления потоками,
файлами и т.д. Типы драйверов, наличествующие в Windows, я уже упоминала в разделе терминов:
монолитный драйвер, фильтр — драйвер и т.д. А раз так, то пора закругляться. Наш краткий обзор архитектуры Windows NT можно считать завершённым. Этого тебе пока хватит для общего понимания концепций Windows NT, и концепций написания драйверов под эту ось — как следствие.

Инструменты

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

Без чего нельзя обойтись ни в коем случае — это Microsoft DDK (Driver Development Kit). К этому грандиозному пакету прилагается и обширная документация. Её ценность — вопрос спорный. Но в любом случае, хотя бы ознакомиться с первоисточником информации по написанию драйверов для Windows — обязательно. В принципе, можно компилять драйвера и в Visual Studio, но это чревато долгим и нудным копанием в солюшенах и vcproj-ектах, дабы код твоего драйвера нормально откомпилировался. В любом случае, сорцы придётся набивать в визуальной студии, т.к. в DDK не входит
нормальная IDE. Есть пакеты разработки драйверов и от третьих фирм:
WinDriver или NuMega Driver Studio, например. Но у них есть отличия от майкрософтовского базиса функций (порой довольно большие) и многие другие мелкие неудобства. Так что DDK — лучший вариант. Если же ты хочешь писать драйвера исключительно на ассемблере, тебе подойдёт KmdKit (KernelMode Driver DevelopmentKit) для MASM32. Правда, этот вариант только для Win2k/XP.

Теперь можно поговорить о сторонних утилитах. Некоторые уже включены в стандартную поставку
Windows: редактор реестра. Но их в любом случае не хватит. Надо будем инсталлить отдельно.
Множество наиполезнейших утилит создали патриархи системного кодинга в
Windows: Марк Руссинович, Гарри Нэббет, Свен Шрайбер… и т.д. Вот о них и поговорим.
Марк Руссинович создал много полезных утилит:
RegMon, FileMon (мониторы обращений к реестру и файлам соответственно), WinObj (средство просмотра директорий имен
объектов), DebugView,DebugPrint (программы просмотра, сохранения и т.д. отладочных сообщения) и проч. и проч. Все эти утилиты и огромное количество других можно найти на знаменитом сайте Руссиновича
http://www.sysinternals.com .

На диске, прилагающемся к знаменитой книге «Недокументированные возможности Windows 2000» Свена Шрайбера,
есть замечательные утилиты w2k_svc, -_sym, -_mem, позволяющие просматривать установленные драйвера, приложения и службы, работающие в режиме ядра, делать дамп памяти и т.д. Все эти утилиты, а также другие программы с диска можно скачать с
http://www.orgon.com/w2k_internals/cd.html .

Напоследок нельзя не упомянуть такие хорошие проги, как PE
Explorer, PE Browse Professional Explorer, и такие незаменимые, как дизассемблер IDA и лучший отладчик всех времён и народов SoftICE.

Заключение

Ну вот и подошла к концу первая статья из цикла про написание драйверов под Windows. Теперь ты достаточно «подкован» по
теоретической части, так что в следующей статье мы перейдём к практике. Желаю тебе удачи в этом интереснейшем деле — написании драйверов! Да не облысеют твои пятки!

Похожие статьи