Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
195
Добавлен:
20.02.2016
Размер:
43.01 Кб
Скачать

Лабораторная работа №3

Цель работы

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

Создание драйвера будет заключаться в модификации драйвера №3 (simple3) из л/р №1.

Создание прикладной программы будет заключаться в модификации диалоговой прикладной программы управления драйверами из л/р №2.

Драйвер №4

Имя проекта rw

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

Для выполнения работы изучить:

  • Лекция lect7_8.doc п.[7.2] Структура IRP, в особенности п.[7.2.2.] Поля в Стеке размещения Ввода - вывода IRP.

  • [7.3] Описание Буфера Данных

  • [7.4] Коды Функции Ввода - вывода

  • [8.1] Передача данных посредством IRP и диспетчерские точки входа драйвера, в особенности п. [8.1.1] Запросы чтения и записи IRP_MJ_READ и IRP_MJ_WRITE

Принцип реализации:

Драйвер должен создать 3 устройства – по одному устройству на каждый из способов передачи буфера: buffered i/o, direct i/o и neither i/o. Соответственно, после создания каждого устройства функцией IoCreateDevice() в поле Flags объекта-устройство устанавливается требуемый способ передачи буфера (DO_BUFFERED_IO, DO_DIRECT_IO или ничего не устанавливается для метода neither i/o). Устройства должны иметь расширения устройств (в IoCreateDevice() указывается размер структуры DeviceExtension). Структура DeviceExtension определяется разработчиком драйвера. В нашем случае она должна содержать буфер из 16 байт.

#define THE_BUFFER_LENGTH 16

typedef struct _DEVICE_EXTENSION

{

unsigned char Image[THE_BUFFER_LENGTH];

}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

Диспетчерская функция драйвера должна обрабатывать все запросы (IRP_MJ_CREATE, IRP_MJ_CLOSE, IRP_MJ_READ, IRP_MJ_WRITE). Это делается с помощью присваивания адреса этой функции соответствующим элементам массива DriverObject->MajorFunction.

При получении запроса на чтение или запись диспетчерская функция должна проверить поле Flags объекта-устройство, полученного в качестве первого параметра диспетчерской функции. В соответствии со значением этого поля запрос чтения/записи следует обрабатывать как buffered, direct или neither (см. лекцию №7-8 для получения информации о местонахождении буфера данных, его размере и о способе указания числа реально прочитанных/записанных байт).

Пример получения буфера и его размера для запроса записи с прямым в/в:

PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;

switch (stack->MajorFunction)

{

...

case IRP_MJ_WRITE:

buf_size = stack->Parameters.Write.Length;

if (pDeviceObject->Flags & DO_BUFFERED_IO)

{

...

}

else

if (pDeviceObject->Flags & DO_DIRECT_IO)

{

buf = MmGetSystemAddressForMdl( Irp->MdlAddress );

}

else

{/*NEITHER I/O*/

...

}

break;

...

}

Запрос записи должен записывать полученный в пакете IRP блок данных в буфер внутри DeviceExtension соответствующего устройства (устройства, для которого послан запрос).

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

При выполнении запросов чтения и записи необходимо проверять размеры буферов на переполнение (не записывать в DeviceExtension больше 16 байт и не записывать в буфер в IRP больше размера буфера).

switch (stack->MajorFunction)

{

case IRP_MJ_READ:

RtlMoveMemory(

buf,

DeviceExtension->Image,

bufsize>THE_BUFFER_LENGTH?THE_BUFFER_LENGTH:bufsize);

Irp->IoStatus.Information = bufsize>THE_BUFFER_LENGTH?THE_BUFFER_LENGTH:bufsize;

break;

case IRP_MJ_WRITE:

RtlMoveMemory(

DeviceExtension->Image,

buf,

bufsize>THE_BUFFER_LENGTH?THE_BUFFER_LENGTH:bufsize);

Irp->IoStatus.Information = bufsize>THE_BUFFER_LENGTH?THE_BUFFER_LENGTH:bufsize;

break;

}

Irp->IoStatus.Status = STATUS_SUCCESS;

IoCompleteRequest( Irp, IO_NO_INCREMENT );

Модификация диалоговой прикладной программы управления драйверами для тестирования драйвера №4

В класс TScMgr добавить 2 функции: чтение из файла и запись в файл.

BOOL TScMgr::Read(HANDLE hDevice, void* buf, DWORD bsize);

BOOL TScMgr::Write(HANDLE hDevice, void* buf, DWORD bsize);

hDevice – описатель устройства, открытого с помощью функции TScMgr::OpenDevice() (Это та функция, где вызывается CreateFile())

buf, bsize – буфер и размер буфера для чтения и записи.

Реализация этих функций должна использовать WIN32-функции ReadFile() и WriteFile() (см. MSDN Library).

В случае неуспешного завершения этих функций вывести информацию об ошибке с помощью TScMgr::PrintLastError().

При успешном завершении вывести число реально прочитанных/записанных байт и первые 4 байта прочитанного буфера.

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

Драйвер №5

Имя проекта devioctl

Реализация обработки драйвером запросов управления в/в при различных режимах передачи буфера с данными.

Для выполнения работы изучить:

  • Лекция lect7_8.doc п.[8.1.2] IRP_MJ_DEVICE_CONTROL и IRP_MJ_INTERNAL_DEVICE_CONTROL

  • Особое внимание обратить на таблицы в п. [7.3], [8.1.2.2], [8.1.2.3].

Принцип реализации:

Драйвер должен создавать одно устройство.

С помощью макроса CTL_CODE должны быть созданы 4 кода управления в/в для каждого из 4 методов передачи буфера. Например:

#define FILE_DEVICE_IOCTL 0x00008301

#define IOCTL_MY_NEITHER CTL_CODE(FILE_DEVICE_IOCTL, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)

#define IOCTL_MY_BUFFERED CTL_CODE(FILE_DEVICE_IOCTL, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define IOCTL_MY_INDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x802, METHOD_IN_DIRECT, FILE_ANY_ACCESS)

#define IOCTL_MY_OUTDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x803, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

В диспетчерской функции необходимо проверить код управления в/в для данного пакета IRP, и в зависимости от него обработать запрос. Обработка запроса будет состоять в получении адреса буферов InBuffer и OutBuffer и размеров буферов и вывода этой информации с помощью DebugPrint(). О получении адресов буферов и их размеров читай в лекциях №7 и 8.

Пример обработки IOCTL_MY_INDIRECT:

case IOCTL_MY_INDIRECT:

SimplPrint( ("IOCTL.SYS: IOCTL_INDIRECT:\n"));

InBuffer = Irp->AssociatedIrp.SystemBuffer;

InLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;

OutBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress);

OutLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;

SimplPrint( ("IOCTL.SYS: InB=%08lx len=%lx, OutB=%08lx, len=%lx\n",

(ULONG)InBuffer, InLength, (ULONG)OutBuffer, OutLength));

break;

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

method = irpStack->Parameters.DeviceIoControl.IoControlCode & 0x03L;

и вставить обработку для каждого метода

switch(method)

{

case METHOD_BUFFERED:

case METHOD_IN_DIRECT:

case METHOD_OUT_DIRECT:

case METHOD_NEITHER:

}

Обработка будет совпадать с обработкой соответствующих контрольных кодов IOCTL_MY_NEITHER … IOCTL_MY_OUTDIRECT

Модификация диалоговой прикладной программы управления драйверами для тестирования драйвера №5

Модифицировать будем программу, полученную после реализации драйвера №4 (добавлены кнопки чтения и записи).

В класс TScMgr добавить функцию: отправки кода управления в/в.

BOOL TScMgr::SendCtlCode(HANDLE hDevice, DWORD CtlCode,

void* InBuf, DWORD InBufSize,

void* OutBuf, DWORD OutBufSize);

Реализация функции должна использовать WIN32-функцию DeviceIoControl() (См. MSDN Library).

В случае неуспешного завершения этой функции вывести информацию об ошибке с помощью TScMgr::PrintLastError().

При успешном завершении вывести число реально прочитанных/записанных байт и первые 4 байта буфера OutBuf.

В класс диалогового окна добавить кнопку отправки контрольного кода и обработчик ее нажатия. Функция – обработчик должна вызывать TScMgr::SendCtlCode() 8 раз и каждый раз передавать буфер InBuffer размером 8 байт и OutBuffer размером 16 байт. Каждый раз передавать разное значение кода в/в.

С помощью макроса CTL_CODE определить 8 разных кодов управления в/в: 4 таких же, как были определены в драйвере, и 4 новых, неизвестных драйверу:

#define FILE_DEVICE_IOCTL 0x00008301

#define IOCTL_MY_NEITHER CTL_CODE(FILE_DEVICE_IOCTL, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)

#define IOCTL_MY_BUFFERED CTL_CODE(FILE_DEVICE_IOCTL, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define IOCTL_MY_INDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x802, METHOD_IN_DIRECT, FILE_ANY_ACCESS)

#define IOCTL_MY_OUTDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x803, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

#define IOCTL_UNK_NEITHER CTL_CODE(FILE_DEVICE_IOCTL, 0x804, METHOD_NEITHER, FILE_ANY_ACCESS)

#define IOCTL_UNK_BUFFERED CTL_CODE(FILE_DEVICE_IOCTL, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define IOCTL_UNK_INDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x806, METHOD_IN_DIRECT, FILE_ANY_ACCESS)

#define IOCTL_UNK_OUTDIRECT CTL_CODE(FILE_DEVICE_IOCTL, 0x807, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)

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

4

Соседние файлы в папке Лабы по драйверам