Выбрать главу

Четвёртый запрос – на выгрузку. Об этом пойдёт речь ниже.

А пока необходимо сделать ещё 2 важные вещи – создать логический объект устройства при помощи функции IoCreateDevice() и символическую связь, имя которой пользовательские приложения будут использовать для связи с драйвером при помощи функции CreateFile(). Символическая связь создаётся при помощи вызова IoCreateSymbolicLink():

; Инициализируем юникодовые строки с именами устройства и линка

invoke RtlInitUnicodeString, offset NtDeviceName, offset wsNtDeviceName

invoke RtlInitUnicodeString, offset Win32DeviceName, offset wsWin32DeviceName

; […]

; Создаём логический объект устройства

invoke IoCreateDevice, DriverObject, 0, offset NtDeviceName, FILE_DEVICE_UNKNOWN,0,FALSE,offset DeviceObject;

cmp eax,STATUS_SUCCESS ; Проверим, не было ли ошибки.

jnz @F

; Создаём symbolic link

invoke IoCreateSymbolicLink, offset Win32DeviceName, offset NtDeviceName ; в eax останется код результата

@@:

ret

Итак, только что мы завершили разбор процедуры инициализации.

3.3. Процедура выгрузки.

У нас она реализуется функцией OnUnload. Эта функция производит действия, обратные процедуре инициализации по отношению к связанным объектам: она удаляет символическую связь (вызов IoDeleteSymbolicLink()), и затем логическое устройство, сопоставленное драйверу (IoDeleteDevice()):

; Удаляем символическую связь

invoke IoDeleteSymbolicLink, offset Win32DeviceName

; Удаляем логическое устройство

invoke IoDeleteDevice, DeviceObject

3.4. Главная диспетчерская процедура.

Она называется OnDispatch и объявлена как

OnDispatch proc near, pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP

Здесь нам важен указатель на структуру с данными запроса pIrp. Данная структура довольно сложна. Вы можете найти её объявление в файле usewdm.inc.

Но нам понадобятся лишь некоторые данные.

Сначала мы должны определить код запроса – он будет один из трёх: IRP_MJ_CREATE, IRP_MJ_CLOSE или IRP_MJ_DEVICE_CONTROL.

Мы получаем этот код из структуры IO_STACK_LOCATION, указатель на которую мы получаем из структуры IRP(в свою очередь, указатель на irp был передан нам в пераметре pIrp):

mov ebx,pIrp

mov eax,(_IRP ptr [ebx]).Tail.Overlay.CurrentStackLocation ; Восстанавливаем указатель на структуру IO_STACK_LOCATION

mov pIrpStack,eax

mov ebx,pIrpStack

mov al,(IO_STACK_LOCATION ptr [ebx]).MajorFunction ; al – Код сообщения

Дальше отрабатываем запросы по-разному.

Для IRP_MJ_CREATE и IRP_MJ_CLOSEобработка фиктивная. Мы просто возвращаем код успеха STATUS_SUCCESS в регистреeax.

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

Мы размещаем эти данные в локальных переменных, чтобы потом вызвать вторичную функцию DeviceIoControlHandler, где и будет выполнена обработка.

Часть 4. Детализация.

Детализация заключается в размещении пользовательского кода во вторичной процедуре обработчика IRP_MJ_DEVICE_CONTROL.

Мы будем отрабатывать 2 запроса:

IOCTL_USER_REQUEST_1 – отправка переданной строки в отладочный вывод, и

IOCTL_USER_REQUEST_2 – перевод литер переданной строки в нижний регистр.

Коды запросов объявлены в файле-включении ioctlcodes.inc

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

Часть 5. Компиляция и сборка.

Для компиляции программы следует выполнить командный файл assemble.cmd.

Его содержимое:

..\..\bin\ml.exe –coff –Fl –c –Foasmdrv.obj main.asm

В результате мы получим листинг main.lst и объектный модульasmdrv.obj.

Дальше мы должны собрать бинарник драйвера из объектного модуля. Для этой цели существует команда link.cmd:

..\..\bin\link.exe @linkcmd.rsp

в файле linkcmd.rsp размещены настройки линкера. Полный список выглядит так:

-MACHINE:IX86

-STACK:32768,4096

-OPT:REF

-OPT:ICF

-INCREMENTAL:NO

-FORCE:MULTIPLE

-RELEASE

-DEFAULTLIB:wdm.lib

-DRIVER

-ALIGN:0x20

-SUBSYSTEM:NATIVE

-BASE:0x10000

-ENTRY:DriverEntry@8

-OUT:disk1\asmdrv.sys

asmdrv.obj

В результате сборки мы получаем файлAsmDrv.sys в подкаталоге Disk1.

Часть 6. Как правильно установить драйвер.

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

Это так называемый inf-файл.

Опять-таки, к счастью для вас, я уже написал этот файл – asmdrv.inf. Вы можете открыть его для просмотра и изучить.

Файл находится в подкаталоге Disk1 проекта.

Ну что же? – Пробуем установиться.

Открываем Панель управления, запускаем Мастер установки оборудования и указываем ему путь к файлу asmdrv.inf в режиме ручного выбора.