Intermediate / Драйвер для английского языка

Драйвер для английского языка

однажды меня попросили написать драйвер. В тот день мои знания C / C были ограничены программой Hellow Word, и поэтому на вопрос: «Написать?» Я уверенно ответил: «Конечно». На следующий день я узнал, что есть MSDN и DDK. Вскоре я понял, что не все Windows одинаковы, оказалось, что мой драйвер должен работать под Win2000 / NT. Мне потребовалось более месяца, чтобы скомпилировать и запустить ваш первый драйвер. По правде говоря, это был не мой Драйвер, а скорее - это был генпорт от NTDDK. Но я как минимум написал свою ОС.

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

Люди, которые знают, что такое IOCTL, DEVICE_EXTENSION, MajorFunction и DriverEntry, не найдут здесь ничего нового. Эта статья для тех, кто, возможно, никогда не слышал слова DDK и кто до сих пор никогда не смотрел на исходный код драйверов. И все же я скорее подробно опишу многие, даже очевидные вещи, поэтому позвольте мне напомнить вам, что эта статья предназначена для людей с очень небольшим опытом программирования, который у меня был, когда я начинал писать драйверы.

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

-
1. Свен Шрайбер "Недокументированная Windows 2000". Издательство "Питер", 2002 год.
Здесь очень хорошо описан механизм динамической загрузки драйвера.
-
2. Рудаков с. И., Финогенов, К. Г., "Язык ассемблера: уроки программирования" Диалог MIFI 2001.
Очень полезная книга для понимания того, как писать драйверы без каких-либо Wizard-ов.
-
3. Светлана Сорокина, Андрей Тихонов, Андрей Щербаков, «Программирование драйверов и систем безопасности». Издательство "БХВ-Петербург", 2002.
Здесь хорошо описаны многоуровневые модели драйверов.

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

, поэтому я обращаюсь к человеку, который решил написать драйвер уровня ядра под Win2000 / NT. Я надеюсь, что эти заметки помогут сэкономить массу времени и усилий.

Прежде всего, я бы не рекомендовал (исходя из моего собственного опыта) использовать различные библиотеки (такие как NuMega и все виды других мастеров). Главным образом из-за того, что даже для написания простого драйвера вам нужно хотя бы поверхностное представление о том, как он работает. И самый простой способ получить представление об этом - написать драйвер самостоятельно. Например, у меня не хватило терпения разобраться с NuMega, и я даже предпочел переписать оболочку функций динамической загрузки / выгрузки драйверов, предложенную Свеном Шрайбером в моей книге.

Итак, начнем. Сначала вам нужно установить Visul C 6.0 на компьютер MSDN и NTDDK, желательно установить в таком порядке. Лично я использую редактор UltraEdit для работы с текстами драйверов, но, в принципе, исходный код драйвера можно набирать в любом текстовом редакторе, даже в NotePad.

Создайте папку, в которой мы будем работать с драйвером (пусть это будет C: myDriver). В этой папке мы создадим 5 файлов:
1. myDrv.c
2. myDrv.h
3. myDrv.rc
4. MAKEFILE
5. ИСТОЧНИКИ

Начнем с последнего файла. В ИСТОЧНИКАХ скопируйте следующее:

#define FIRST_IOCTL_INDEX 0x800
#define FILE_DEVICE_myDRV 0x00008000


#define TEST_SMTH CTL_CODE (FILE_DEVICE_myDRV, \
FIRST_IOCTL_INDEX 101, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)

#include "ntddk. h "
#include" myDrv.h "
#include" parallel.h "

#define NT_DEVICE_NAME L "\\ Device \\ myDrv"
#define DOS_DEVICE_NAME L "\\ DosDevices \\ myDrv"

// структура расширения устройства
typedef struct _DEVICE_EXTENSION
<
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
РУЧКА Ручка;

// прототипы функций
NTSTATUS
DriverDeviceControl (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

VOID
DriverUnload (IN PDRIVER_OBJECT DriverObject);

NTSTATUS
DriverOpen (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

NTSTATUS
DriverClose (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

NTSTATUS
DriverEntry (IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
<
PDEVICE_OBJECT deviceObject;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
Расширение PDEVICE_EXTENSION;
NTSTATUS ntStatus;

if (! NT_SUCCESS (ntStatus)) return ntStatus;

DriverObject-> MajorFunction [IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl;
DriverObject-> DriverUnload = DriverUnload;
DriverObject-> MajorFunction [IRP_MJ_CREATE] = DriverOpen;
DriverObject-> MajorFunction [IRP_MJ_CLOSE] = DriverClose;

extension = (PDEVICE_EXTENSION) deviceObject-> DeviceExtension;
extension-> DeviceObject = deviceObject;
extension-> DriverObject = DriverObject;

// Создать счетную строковую версию нашего имени устройства Win32.
RtlInitUnicodeString ( Информация = 4;

перерыв;


по умолчанию:
Irp-> IoStatus.Status = STATUS_INVALID_PARAMETER;
перерыв; <
>

ntStatus = Irp-> IoStatus.Status;

IoCompleteRequest (Irp, IO_NO_INCREMENT);

return ntStatus;
>


ниже приведены прототипы используемых функций. Этим функциям могут быть присвоены произвольные имена, НО их сигнатура (список возвращаемых значений параметров типа) жестко запрограммирована системой. [2]: Программная часть драйвера начинается с обязательной функции DriverEntry (), которая автоматически вызывается системой при загрузке драйвера. Эта функция должна содержать всю свою инициализацию. В качестве первого параметра наша функция получает указатель на объект драйвера типа PDRIVER_OBJECT.

При загрузке системный драйвер создает объект драйвера (объект драйвера), воплощает образ драйвера в памяти. С другой стороны, объект драйвера - это структура, содержащая необходимые для работы данные драйвера и функции адресации. В процессе инициализации драйвера (в DriverEntry ()) создается один или несколько объектов устройства (device device), которые воплощают устройства, на которых будет запускаться драйвер. Это объект устройства, необходимый для правильной работы драйвера, и он создается (как в нашем случае), даже если драйвер не связан с каким-либо реальным устройством.
<
Далее в первой строке DriverEntry мы определяем используемые данные, в том числе указатель на объект устройства, и двухсимвольную строку UNICODE_STRING с именами устройства. Системные программы связываются с объектом устройства, созданным драйвером, посредством указателя на него. Однако для прикладного программного обеспечения устройство объекта является одним из файловых объектов, и ссылается на него по имени (мы будем использовать функцию CreateFile ()).

Мы должны помнить, что объект устройства должен иметь два имени: одно в пространстве имен NT, а другое в пространстве имен Win32. Эти имена должны быть структурой UNICODE_STRING. Имена объектов устройства составляются в соответствии с определенными правилами. Имя NT имеет префикс устройства, а имя Win32 - префикс? (или DosDevice). При указании имен в программе si, обратный слеш удваивается. Чтобы указать в драйвере имя программы, которая будет использоваться в приложении для открытия устройства, необходимо создать символическую ссылку между двумя указанными именами устройств. Для этого мы используем функцию IoCreateSymbolicLink (). Следующая обязательная операция - создание объекта устройства реализуется вызовом функции IoCreateDevice (). Первым параметром этой функции является указатель на объект драйвера, который входит в DriverEntry ().Второй параметр определяет размер расширения устройства - структуры, которая служит для передачи данных между функциями драйвера (состав этой структуры произвольный и полностью определяется разработчиком). Третий параметр - это ранее созданное имя устройства NT. Далее: тип устройства (FILE_DEVICE_UNKNOWN), специальные характеристики (0), FALSE означает, что у нас однопоточное устройство. Наконец, последний параметр - это вывод - через него функция возвращает указатель на созданный объект устройства.

Далее необходимо ввести адреса основных функций, включенных программистом в текст драйвера, в объект драйвера. Массив MajorFunction является одним из элементов структурной переменной. В этом массиве мы вводим адреса основных функций (то есть функций, которые автоматически вызываются системой в ответ на определенные действия приложения или устройства). Функция завершается оператором return, указывающим код успеха.

Функция DriverUnload () вызывается при выгрузке драйвера. Здесь мы должны выполнить шаги, чтобы удалить объект устройства, созданный в DriverEntry ().


В нашем случае функции DriverOpen и DriverClose ничего не делают и просто возвращают STATUSS_SUCCESS. Кстати, все эти функции также могут иметь произвольные имена, но при этом параметры передачи строго фиксированы.

[2]: Здесь мы переходим к осмысленным, с точки зрения прикладного программирования, функциям DriverDeviceControl (). Эта функция вызывается каждый раз, когда в драйвер приходит IRP-пакет с любым кодом IOCTL_. Грубо говоря, пакет IRP - это структура, передающая указатель, который приложение может связывать с драйвером (как, впрочем, и драйвер может связываться с другим драйвером). Более подробное описание того, что такое IRP-пакет, можно найти здесь http://www.lcard.ru/

IRP-пакет содержит так называемый системный буфер обмена, используемый для обмена информацией (переменная SystemBuffer). Таким образом, нам нужен доступ к IRP-пакету, а через него к SystemBuffer. Для этого необходимо объявить переменную типа указателя irpStack в области стека ввода-вывода PIO_STACK_LOCATION и, кроме того, переменную ioBuffer, которая получает адрес системного буфера обмена. В нашем случае тип этой переменной - PULONG, фактически тип передаваемых данных может быть любым. С помощью функции IoGetCurrentIrpStackLocation () в переменную помещается область ввода-вывода стека адресов irpStack, а переменная ioBuffer заполняется адресом системного буфера из структуры IRP. Системный буфер обмена является членом Association (union) с именем AssociatedIrp, поэтому мы используем дизайн Irp-> AssociatedIrp.SystemBuffer. Design switch-case анализирует содержимое ячейки IoControlCode и в зависимости от значений кода выполняет определенные действия. В нашей программе только один код действия TEST_SMTH. Отправка в буфер обмена адреса функции DriverEntry () через указатель на этот буфер. В переменной Irp-> IoStatus.Recorded указан номер информации (4) отправленных байтов. Для завершения пакета IRP называется IoCompleteRequest ().

водитель, которого мы написали. Теперь мы должны скомпилировать это. Поскольку процесс компиляции идет из командной строки, тогда эту цель гораздо проще использовать. файл летучей мыши. Создайте небольшое имя файла bat, например, Crt.bat со следующим содержимым:


NTDDK Я установил в корне C :, если Вы делаете иначе, вместо C: NTDDKbin и C: NTDDK укажите полный путь к соответствующим папкам.

так что теперь запустите наш Crt.bat. После компиляции в папке C: myDriverobjfrei386 найдите желающий драйвер myDrv.sys. Наш драйвер может только быть загружен / выгружен и по специальному запросу отправляет приложение для решения одной из своих процедур.

Теперь напишем приложение, которое работает с нашим драйвером. Еще раз напоминаю, что мы работаем под Win2000.Эта ОС позволяет реализовать динамическую загрузку / выгрузку драйвера.

Точнее, динамическая загрузка / выгрузка сервисов (сервисов), но поскольку в Win2000 вы также можете рассматривать драйвер как сервис, я буду использовать оба эти термина, подразумевая в этой статье наш драйвер. <

Для загрузки и выгрузки драйверов используйте Service Manager SC Manager (Service Control Manager). Прежде чем вы сможете работать с интерфейсом SC, вы должны получить дескриптор менеджера сервисов. Для этого вызовите функцию OpenSCManager (). Дескриптор диспетчера служб должен использоваться при доступе к функциям CreateServise () и OpenService (). Дескрипторы, возвращаемые этими функциями, должны использоваться при доступе к вызовам, связанным с конкретной службой. Такие вызовы включают функции ControlService (), DeleteService () и StartService (). Чтобы освободить дескрипторы обоих типов, используйте вызов CloseServiceHandle ().

Загрузка и запуск сервиса включает в себя следующие действия:

Вызов функции OpenSCManager () для получения дескриптора диспетчера

Вызов CreateServise () для добавления службы в систему. Если такая служба уже существует, CreateServise () сгенерирует код ошибки 1073 (код ошибки можно прочитать GetLastError ()) Эта ошибка означает, что служба уже существует, и вам нужно использовать OpenService () вместо CreateServise ().

Вызов StartService () для перевода сервиса в рабочее состояние. <

Если служба успешно запущена, вы можете вызвать CreateFile (), чтобы получить дескриптор, который мы будем использовать непосредственно при доступе к драйверу.

И в конце работы не забудьте дважды обратиться к CloseServiceHandle (), чтобы освободить диспетчерские и сервисные дескрипторы.

Если на каком-то этапе этой последовательности возникает ошибка, вам необходимо выполнить операции, обратные тем, которые вам удалось выполнить до ошибки. Имейте в виду, что при доступе к таким функциям, как CreateServise (), вы должны указать полное имя исполняемого файла службы (в нашем случае полный путь и имя myDrv.sys).

Давайте рассмотрим исходный код простого консольного приложения, написанного на Visual C 6.0:

<
#include
#include "LoadDRV.h"
#include
#include

void main ()

LPTSTR m_name = new char [20];
strcpy (m_name, "myDrv.sys");

if (drvLoad (m_name)) TestSmth ();

drvUnLoad (m_name);
удалить m_name;
> <

DeviceIoControl (hDevice, IOCTL_TEST_SMTH, NULL, 0,
CloseHandle (hDevice)) ошибка (_CloseHandle);
hDevice = INVALID_HANDLE_VALUE;

>


if (hService)

status = ControlService (hService, SERVICE_CONTROL_STOP,

Английский язык онлайн обучение
С чего начать учить с ребенком английский язык
Самое лучшее приложение для изучения английского языка
Профессии для которых не нужен английский язык
Славянск на кубани репетитор по английскому языку