39772

Простой драйвер, посылающий в приложение адреса своих ха

Реферат

Информатика, кибернетика и программирование

Для того чтобы приложение могло запросить у драйвера выполнение конкретного действия из числа предусмотренных в драйвере в качестве одного из параметров этой функции выступает код действия в данном случае IOCTL__DDR. Процедура драйвера вызываемая функцией Windows DeviceIoControl должна проанализировать поступивший в драйвер код действия и передать управление на соответствующий фрагмент драйвера. В программе драйвера для формирования кода действия использован макрос CTL_CODE который определен в файле NTDDK.

Русский

2013-10-08

62.5 KB

1 чел.

Простой драйвер, посылающий в приложение адреса своих характерных процедур

Текст драйвера начинается с оператора препроцессора #include, с помощью которого к программе подсоединяется файл NTDDK.H, содержащийся в пакете DDK NT. Этот файл включает значительную часть определений констант, типов переменных, прототипов функций и макросов, используемых в исходных текстах программ драйверов. Некоторая доля этих определений входит в другие заголовочные файлы, на которые имеются ссылки в файле NTDDK.H. Два следующих предложения программы служат для задания символических имен (в данном случае NT_DEVICE_NAME и WIN32_DEVICE_NAME) текстовым строкам с именами объекта устройства, который будет создан нашим драйвером.

Предложения вида

#define IOCTL_ADDR CTL_CODE \

(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)

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

Коды действия, называемые в документации DDK NT управляющими кодами ввода-вывода (I/O control codes), строятся по определенным правилам. Каждый код представляет собой слово длиной 32 бита, в отдельных полях которого размещаются компоненты кода (рис. 1).

Рис. 1. Поля кода действия

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

В поле "Тип устройства" помещается предопределенная константа, характеризующая устройство (FILE_DEVICE_CD_ROM, FILE_DEVICE_MOUSE и др.). В нашем случае можно использовать константу FILE_DEVICE_UNKNOWN, равную 0x22.

Поле доступа определяет запрашиваемые пользователем права доступа к устройству (чтение, запись, чтение и запись). Мы будем использовать константу FILE_ANY _ ACCESS, равную нулю.

Функциональный код может принимать произвольное значение в диапазоне 0x800...0xFFF (значения 0x000...0x7FF зарезервированы для кодов Microsoft). В рассматриваемом примере используется единственный код действия и для него выбран функциональный код, равный 0x800. В последующих примерах драйверов кодов действий будет больше и им будут присваиваться функциональные коды 0x801,0x802 и т. д.

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

Код действия можно сформировать "вручную", как это сделано в нашем приложении Windows:

#define IOCTL_ADDR (0x800«2) | (0x22«16)

В этом случае предполагаются константы FILE_DEVICE_UNKNOWN=0x22, METHOD_BUFFERED=0 и FILE_ANY_ACCESS=0 при значении функционального кода 0x800. В программе драйвера для формирования кода действия использован макрос CTL_CODE, который определен в файле NTDDK.H. Этот макрос позволяет обойтись без детального знания формата кода действия и значений конкретных констант.

Вслед за определением кода действия в тексте драйвера приведены прототипы используемых в нем функций. Этим функциям можно дать произвольные имена, однако их, как говорят, сигнатура, т. е. состав параметров вместе с типом возвращаемого значения, жестко заданы системой. Ключевое слово IN, с которого начинается описание каждого параметра, говорит о том, что этот параметр является для функции входным, т. е. передается в функцию при ее вызове. В других случаях может использоваться ключевое слово OUT, а также и комбинация IN OUT, если через данный параметр осуществляется как передача данного в функцию, так и возврат результата ее работы. По правилам языка Си, функция может изменять значения передаваемых в нее через параметры данных, если параметром является не само данное, а его адрес (указатель).

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

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

Типы объектов Windows, т. е. состав входящих в них структур данных и функций, известны заранее, однако сами объекты (или, как говорят, экземпляры объектов) создаются динамически по мере возникновения в них необходимости.

При загрузке драйвера система создает объект драйвера (driver object), олицетворяющий для системы образ драйвера в памяти. С другой стороны, объект драйвера представляет собой структуру, содержащую необходимые для функционирования драйвера данные и адреса (указатели) функций.

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

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

Дело усугубляется тем, что объект устройства должен иметь два имени, одно -в пространстве имен NT, другое - в пространстве имен Win32. Оба эти имени должны, во-первых, быть определены с помощью кодировки Unicode, в которой под каждый символ выделяется не 1, а 2 байта, и, во-вторых, представлять собой не просто символьные строки, а специальные структуры типа UNICODE_STRING, в которые входят помимо самих строк еще и их длины ("структуры со счетчиками"). Кодировка Unicode задается с помощью символа L, помещаемого перед символьной строкой в кавычках, а преобразование строк символов в структуры типа UNICODE_STRING осуществляется вызовами функции RtlInitUnicodeString(), которые можно найти далее по тексту программы драйвера.

Имена объектов устройств составляются по определенным правилам. NT-имя предваряется префиксом \Device\, a Win32-имя - префиксом \??\ (или \DosDevice\). При указании имен в Си-программе знак обратной косой черты удваивается.

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

Следующая обязательная операция - создание объекта устройства - осуществляется вызовом функции IoCreateDevice(), принимающей ряд параметров. Первый параметр, указатель на объект драйвера, поступает в функцию DriverEntry() при ее вызове из Windows (см. заголовок функции DriverEntry). Второй параметр определяет размер так называемого расширения устройства - области, служащей для передачи данных между функциями драйвера. В рассматриваемом драйвере расширение устройства не используется и на месте этого параметра указан 0. В качестве третьего параметра указывается созданное нами ранее NT-имя устройства. Наконец, последний параметр этой функции является выходным - через него функция возвращает указатель (типа DEVICE_OBJECT) на созданный объект устройства.

Последнее, что надо сделать на этапе инициализации драйвера, - это занести в объект драйвера адреса основных функций, включенных программистом в текст драйвера. Под основными функциями мы будем понимать те фрагменты драйвера, которые вызываются системой автоматически в ответ на определенные действия, выполняемые приложением или устройством. В наших примерах драйверов таких действий будет три: получение дескриптора драйвера функцией CreateFile(), запрос к драйверу на выполнение требуемого действия функцией DeviceIoControl() и закрытие драйвера функцией CloseHandle(). В более сложных драйверах основных функций может быть больше (вплоть до приблизительно трех десятков). Для хранения адресов основных функций в объекте драйвера предусмотрен массив (с именем MajorFunction) указателей на функции типа PDRIVER_DISPATCH. В файле NTDDK.H определены символические смещения элементов этого массива. Так, в первом элементе массива (смещение IRP_MJ_CREATE=0) должен размещаться указатель на функцию, которая вызывается автоматически при выполнении в приложении функции CreateFile(). В элементе со смещением IRP_MJ_CLOSE=2 размещается указатель на функцию, вызываемую при закрытии устройства (функцией CloseHandle()). Наконец, в элементе со смещением IRP_MJ_DEVICE_CONTROL=OxOE должен находиться адрес функции диспетчеризации, которой система передает управление в ответ на вызов в выполняемом приложении Windows функции DeviceIoControl() с указанием кода требуемого действия. Назначение функции диспетчеризации - анализ кодов действий, направляемых в драйвер приложением, и осуществление переходов на соответствующие фрагменты драйвера. В рассматриваемом примере три упомянутые функции имеют (произвольные) имена CtlCreate, CtlClose и CtlDispatch; структура нашего драйвера с указанием его функций.

Рис. 2. Структура простейшего драйвера

Массив MajorFunction является одним из элементов структурной переменной. Если бы эта структура была объявлена в программе с указанием ее имени (пусть это имя будет Driver-Object), то для обращения к элементу структуры с индексом 0 следовало бы использовать конструкцию с символом точки:

DriverObjеct.MajorFunction[0]=CtlCreate;

Однако у нас имеется не имя структурной переменной, а ее адрес pDriverObject, полученный в качестве первого параметра при активизации функции DriverEntry. В этом случае для обращения к элементу структуры следует вместо точки использовать обозначение->:

pDriverObjеct->MajorFunction[IRP_MJ_CREATE] =CtlCreate;

Разумеется, вместо численного значения индекса массива надежнее воспользоваться символическим.

Функция DriverEntry(), как, впрочем, и все остальные функции, входящие в состав драйвера, завершается оператором return с указанием кода успешного завершения STATUS_SUCCESS (равного нулю).

Как видно из прототипов функций CtlCreate(), CtlClose() и CtlDispatch(), все они принимают (из системы Windows) в качестве первого параметра указатель на объект драйвера, а в качестве второго - указатель на структуру типа IRP. Эта структура, так называемый пакет запроса ввода-вывода (in/out request packet, IRP), играет чрезвычайно важную роль в функционировании драйвера наряду с уже упоминавшимися объектами драйвера и устройства. Рассмотрим более детально создание и взаимодействие всех этих структур (рис. 3).

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

Загрузив драйвер, Windows активизирует его функцию инициализации DriverEntry(). Эта функция должна содержать вызов IoCreateDevice(), создающий объект устройства. В объекте устройства есть ссылка на объект драйвера, которому это устройство принадлежит, и, кроме того, адрес так называемого расширения устройства (device extension), поля произвольного размера, служащего для обеспечения передачи данных между запросами ввода-вывода. В настоящем примере драйвера расширение устройства не используется (и соответственно, не создается). Функция IoCreateDevice(), создав объект устройства, заносит его адрес в объект драйвера. Таким образом, обе эти структуры оказываются взаимосвязаны.

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

Пакет запроса ввода-вывода создается заново при каждом обращении приложения к драйверу, т. е. при каждом вызове функции DeviceIoControl(). В терминологии драйверов Windows NT этот вызов носит название запроса ввода-вывода (I/O request). Выполнение функции IoCompleteRequest(), которой завершается любая активизируемая из приложения функция драйвера, приводит к уничтожению этого пакета, который, таким образом, существует лишь в течение времени выполнения активизированной функции драйвера. Обычно приложение за время своей жизни обращается к драйверу неоднократно; следующий запрос ввода-вывода снова создаст пакет IRP, который, разумеется, ничего не будет знать о предыдущем.


 

А также другие работы, которые могут Вас заинтересовать

46773. Реконструкція будівель 29.5 KB
  Реконструкцію слід проводити у чіткій відповідності до проекту виконання робіт у якому розроблено методи і терміни їх виконання. Низька культура виробництва та зволікання зі строками робіт досить часто призводять до того що ще міцні будівлі у період реконструкції або після її закінчення потребують додаткового підсилення несівних конструкцій мають тріщини у стінах та інших конструкціях чи підвищену їхню вологість. Відомо два організаційнотехнологічних прийоми реконструкції: 1 виконання всіх робіт із розбирання старих конструкцій а...
46774. Расчет многофункционального контроллера МФК3000 4.46 MB
  Контроллер предназначен для измерения, контроля, регулирования, диагностики и управления производственными процессами, технологическими линиями и агрегатами средней и высокой сложности, в том числе для применения в системах противоаварийной защиты (ПАЗ).
46775. Л.С.Выготский «Проблема умственной отсталости» 29.5 KB
  Воля этот рычаг всех действий всех способностей отсутствует у умственно отсталого ребенка. Новая теория соглашается признать только две особенности отличающие интеллект слабоумного от интеллекта нормального ребенка. Тугоподвижность психических систем у отсталого ребенка при известных обстоятельствах может привести к тому что заместительная функция будет обнаруживаться не слабее а сильнее чем у нормального ребенка. Слабоумный ребенок не обнаруживает тех ступенчатых связных...
46776. The United Kingdom of Great Britain and Northern Ireland 30 KB
  The United Kingdom of Great Britain and Northern Ireland is situated on the British Isles. It consists of four parts: England, Wales, Scotland and Northern Ireland
46777. Информация и структура отраслевого рынка 32.03 KB
  Он рассматривает четыре группы автомобилей: новые и бывшие в употреблении хорошие и плохие или лимоны. Рассматривая рынок подержанных автомобилей Акерлоф предполагает что после использования машины в течение какого то периода у владельца складывается четкое мнение о ее качестве т. Материалыих классифяоценка и отраже в учете их движения. мат.
46778. Влияние дорожных условий на безопасность движения 29.95 KB
  Влияние дорожных условий на безопасность движения Большую роль в обеспечении безопасности движения играют основные техникоэксплуатационные показатели АД. полотна ширина и состояние обочин ровность и шероховатость покрытий видимость на кривых в плане и продольном профиле освещённость участков дороги в ночное время суток наличие разметки на проезжей части качество инженерного обустройства наличие средств регулирования в соответствии с фактической интенсивностью движения. условий на безопасность движения закладывается в процессе...
46779. Индустриализация и коллективизация 30.17 KB
  Объясняла кризис просчетами партийно-государственного руководства неверной налоговой ценовой инвестиционной политикой выступала против применения чрезвычайных мер весной 1929 года за стабилизацию положения в сельском хозяйстве на основе рыночных методов постепенное развертывание крупных коллективных зерновых хозяйств сравнительно умеренные темпы индустриализации на основе сбалансированного подъема тяжелой и легкой промышленности маневрирование и др. считали кризис неизбежным результатом ускоренной индустриализации при отсутствии...
46780. Государственное регулирование рыночной экономики 32.09 KB
  Многовековой опыт рыночного хозяйствования развитых стран мира многими интерпретируется как последовательное воплощение принципа свободы предпринимательства. И как аксиома предполагается предпочтительность экономического порядка
46781. Защита экологических прав граждан в судах общей юрисдикции 30.25 KB
  Особенности правового режима животного мира Юридическое понятие животного мира определено в Федеральном законе О животном мире. Отношения в области охраны и использования объектов животного мира содержащихся в полувольных условиях или искусственно созданной среде обитания в целях сохранения ресурса и генетического фонда объектов животного мира и в иных научных и воспитательных целях регулируются названным Федеральным законом другими федеральными законами и иными нормативными правовыми актами РФ а также законами и нормативными правовыми...