Учебная работа. Курсовая работа: Протоколирование обмена информацией между компьютером и внешним запоминающим USB-устройством
Кафедра «Программное обеспечение ЭВМ и информационные технологии»
Курсовой проект
по системному программированию
Расчётно-пояснительная записка
Тема:
«Протоколирование обмена информацией
меж компом и наружным запоминающим
USB
‑устройством»
Оглавление
Введение. 3
1. Аналитический раздел. 4
1.1 Постановка задачки. 4
1.2 Архитектура WindowsNT 5. 4
1.3 шина USB.. 7
1.3.1 Внутренняя организация шины USB.. 8
1.4 Драйверная модель WDM.. 16
1.4.1 Драйверные слои. 17
1.4.2 Точки входа WDM-драйвера. 19
1.5 Пакет запроса ввода / вывода (IRP)20
1.6 Уровни запроса прерываний. 24
1.7 Извещение о окончании запросанижестоящим драйвером. 25
1.8 Работа с файлами в режиме ядра. 26
1.9 Работа с реестром в режиме ядра. 29
1.10 MDL‑списки. 31
2. Конструкторский раздел. 32
2.1 Точки входа разрабатываемого драйвера. 32
2.1.1 Функция DriverEntry. 32
2.1.2 Функция AddDevice. 32
2.1.3 Функция DriverUnload. 33
2.1.4 Функция DispatchRoutine. 33
2.1.5 Функция DispatchInternalDeviceControl33
2.2 Размещение кода драйвера в памяти. 35
2.3 установка драйвера в системе. 35
3. Технологический раздел. 38
3.1 Выбор языка и средств программирования. 38
3.1.1 драйвер-фильтр. 38
3.1.2 Управляющее приложение. 39
3.2 Структуры данных драйвера-фильтра. 39
3.2 интерфейс управляющего приложения. 41
3.3 Тестирование драйвера-фильтра. 42
Заключение. 44
Перечень литературы и веб-ресурсов. 45
Введение
При решении широкого круга задач возникает необходимость в получении инфы о функционировании какого-нибудь наружного устройства компа. К группы этих задач можно отнести разработку систем информационной сохранности, что весьма животрепещуще в современном мире, где информация является одним из важных ресурсов.
Одним из компонент системы информационной сохранности быть может модуль, выполняющий протоколирование обмена информацией меж компом и неким наружным запоминающим устройством, к примеру USB‑накопителем.
1. Аналитический раздел
1.1 Постановка задачки
В согласовании с заданием на курсовую работу нужно создать программный комплекс, обеспечивающий слежение за обменом информацией меж компом и наружным запоминающим USB‑устройством.
Перечислим требования, предъявляемые к программному комплексу:
· Разрабатываемый комплекс должен выслеживать запросы на чтение и запись, приходящие к устройству;
· От программки не требуется определять, к каким файлам выполнялось воззвание, а только то, какие данные считывались и записывались;
· Сохраняемая информация обязана владеть структурированностью, таковым образом, что при анализе лог-файла можно было найти, передавалась либо принималась информация и в котором количестве;
· Программный комплекс не должен приводить к сбоям в работе операционной системы;
· программка установки обязана корректно обрабатывать попытку установки на одно устройство в 2-ух экземплярах.
1.2 Архитектура
WindowsNT 5
Архитектура WindowsNT 5 соответствует традиционным представлениям о проектировании операционных систем. Более всераспространены реализации данной ОС для платформы Intelx86 в одно- либо многопроцессорных конфигурациях, но есть также версии для DECAlpha и MIPS. Данная операционная система употребляет защищённый режим центрального микропроцессора, реализует механизмы виртуальной памяти и многозадачности.
Исполняемый код в WindowsNT 5 имеет два уровня льгот: код пользовательского режима и код режима ядра. Уровень льгот накладывает определённые ограничения: в пользовательском режиме не могут производиться привилегированные аннотации микропроцессора, не разрешено воззвание к защищённым страничкам памяти. Эти ограничения накладываются для обеспечения сохранности работы системы. Пользовательское приложение не обязано иметь возможность в итоге ошибки либо целенаправленно заносить конфигурации в критичные таблицы операционной системы либо в память остальных приложений. А именно, такие ограничения воспрещают пользовательскому приложению впрямую управлять наружными устройствами, поэтому что каждое из их является разделяемым ресурсом.
В WindowsNT 5 обеспечение обмена данными и управление доступом к наружному устройству как к разделяемому ресурсу возлагается на его драйвер. Ввод и вывод в драйверах осуществляется средством IRP‑пакетов (Input/OutputRequestPacket). Запросы на ввод / вывод, посылаемые приложениями либо иными драйверами, обрабатываются драйвером, опосля что запрашивающей программке в том же пакете посылается статус окончания операции. Подробнее о пакетах ввода / вывода будет сказано дальше, общий же принцип взаимодействия проиллюстрирован на Рис. 1.2.1.
Рис. 1.2.1 Архитектура ввода / вывода WindowsNT 5
Применительно к поставленной задачке, из вышеизложенного следует, что полное протоколирования обмена данными с наружным устройством быть может осуществлено лишь на уровне драйвера.
Управление наружным устройством в общем случае сводится к наполнению его регистров необходимыми данными. Монопольный доступ драйвера к сиим регистрам гарантируется операционной системой. Разумеется, что при данных обстоятельствах требуется, чтоб драйвер устройства производился в режиме ядра.
Обобщённая систематизация драйверов WindowsNT 5 быть может представлена последующим образом:
· Драйверы режима ядра:
o Унаследованные драйверы;
o Драйверы файловой системы;
o Видеодрайверы;
o Драйверы PnP (Plug And Play):
— Драйверы WDM.
· Драйверы пользовательского режима.
1.3 шина
USB
Спецификация USB была разработана консорциумом компаний, включая Intel и Microsoft. Целью новейшего эталона было обеспечение организации дешевый среднескоростной шины в таковых областях внедрения, как передача цифровых изображений, компьютерная телефония и мультимедийные игры. Текущими версиями спецификации USB является версии 1.1 и 2.0 (во вторую заложены наиболее высочайшие скоростные свойства).
Предельная скорость передачи данных по шине USB спецификации 1.1 составляет 12 Мбит/с (FullSpeed). Неспешные устройства употребляют низкую скорость передачи – 1,5 Мбит/с (LowSpeed). Эталон USB версии 2.0 поддерживает физическую скорость передачи до 480 Мбит/с (HighSpeed). Данные передаются поочередно по паре проводников. Питание для неких устройств доступно по отдельным проводникам питания и заземления (для устройств с маленьким энергопотреблением).
Устройства USB могут быть подключены 5-метровым кабелем (а фактически – и наиболее длинноватым). Внедрение USB‑хаба (hub– концентратор) дозволяет прирастить дальность размещения устройств от хост-контроллера, а так же количество устройств, подключаемых к одной шине USB. Поочередно можно подключить до 5 хабов, обеспечив длину соединения 30 метров. К хост-контроллеру можно подключить до 127 устройств, шинный адресок которых устанавливается динамически при подключении устройств.
На рисунке 1.3.1 приведен пример конфигурации сети USB‑устройств:
Рис. 1.3.1 сеть USB‑устройств
Работа программера, создающего драйвер наружного (не находящегося на материнской плате) USB устройства сводится к тому, чтоб пользоваться программным интерфейсом системных драйверов шины USB, общение с которым происходит с помощью пакетов, именуемых URB (USBRequestBlock) пакетами. Работа с регистрами USB контроллеров на материнской плате сейчас стала уделом узенького круга профессионалов – разрабов материнских плат и операционных систем. Всем остальным разрабам USB‑устройств в операционной системе Windows предлагается довольно развитый программный интерфейс WDM‑драйверов, которые берут на себя все аппаратно-ориентированные операции.
1.3.1 Внутренняя организация шины
USB
Все операции по передаче данных по шине USB инициируются хостом. Периферийные устройства не могут сами начать обмен данными, они могут лишь реагировать на команды хоста. Разглядим общую схему обмена данными по шине USB.
Система USB делится на три логических уровня с определенными правилами взаимодействия. Устройство USB содержит интерфейсную, логическую и многофункциональную части. Хост тоже делится на три части: интерфейсную, системную и программное обеспечение. Любая часть отвечает лишь за определенный круг задач. Логическое и реальное взаимодействие меж ними показано на рисунке 1.3.1.1.
Рис. 1.3.1.1 Взаимодействие компонент USB
Таковым образом, операция обмена данными меж прикладной программкой и шиной USB производится методом передачи буферов памяти через последующие уровни:
· уровень клиентского программного обеспечения в хосте – обычно представляется драйвером устройства USB, обеспечивает взаимодействие юзера с операционной системой с одной стороны и системным драйвером с иной;
· уровень системного программного обеспечения USB в хосте (USBD, UniversalSerialBusDriver) – управляет нумерацией устройств на шине, управляет распределением пропускной возможности шины и мощности питания, обрабатывает запросы пользовательских драйверов;
· хост-контроллер интерфейса шины USB (HCD, HostControllerDriver) – конвертирует запросы ввода / вывода в структуры данных, по которым хост-контроллер делает физические транзакции, работает с регистрами хост-контроллера.
Уровень клиентского программного обеспечения описывает тип передачи данных, нужный для выполнения затребованной прикладной программкой операции. Опосля определения типа передачи данных этот уровень передает системному уровню последующее:
· буфер памяти, именуемый клиентским буфером;
· пакет IRP, указывающий тип нужной операции. Конкретной обработкой запроса занимается системный драйвер USB.
Уровень системного драйвера USB нужен для управления ресурсами USB. Он отвечает за выполнение последующих действий:
· распределение полосы пропускания шины USB;
· предназначение логических адресов устройств любому физическому USB‑устройству;
· планирование транзакций.
Логическое устройство USB представляет собой набор независящих конечных точек, с которыми клиентское программное обеспечение обменивается информацией. Любому логическому устройству USB назначается собственный адресок, неповторимый на данной шине USB. Любая конечная точка логического устройства идентифицируется своим номером и направлением передачи (IN – передача к хосту, OUT – от хоста).
Транзакция на шине USB – это последовательность обмена пакетами меж хостом и периферийным устройством, в процессе которой быть может передан либо принят один пакет данных. Когда клиентское программное обеспечение передает IRP уровню системного драйвера, USB‑драйвер конвертирует их в одну либо несколько транзакций шины и потом передает получившийся список транзакций драйверу контроллера хоста.
Системный драйвер USB состоит из драйвера USB и драйвера хост-контроллера. Когда клиентский уровень передает IRP уровню системного обеспечения USB, USB‑драйвер конвертирует их в одну либо несколько транзакций шины и потом передает получившийся список транзакций драйверу контроллера хоста. драйвер контроллера хоста воспринимает от системного драйвера шины список транзакций и делает последующие деяния:
· планирует выполнение приобретенных транзакций, добавляя их к списку транзакций;
· извлекает из перечня еще одну транзакцию и передает ее уровню хост-контроллера интерфейса шины USB;
· выслеживает состояние каждой транзакции прямо до ее окончания.
При выполнении всех связанных с командным пакетом транзакций системный уровень уведомляет о этом клиентский уровень.
Уровень хост-контроллера интерфейса шины USB получает отдельные транзакции от драйвера контроллера хоста (в составе уровня системного обеспечения USB) и конвертирует их в подобающую последовательность операций шины. В итоге этого USB‑пакеты передаются вдоль всей физической иерархии хабов до периферийного USB‑устройства.
Нижний уровень периферийного USB‑устройства именуется уровнем интерфейса шины USB. Он ведет взаимодействие с интерфейсным уровнем шины USB на стороне хоста и передает пакеты данных от хоста к периферийному устройству в формате, определяемом спецификацией USB. Потом он передает пакеты ввысь – уровню логического USB‑устройства.
Средний уровень периферийного устройства USB‑устройства именуется уровнем логического USB‑устройства. Каждое логическое USB‑устройство представляется набором собственных конечных точек, с которыми может вести взаимодействие системный уровень USB‑хоста. Эти точки являются источниками и приемниками всех коммуникационных потоков меж хостом и периферийными USB‑устройствами.
Самый верхний уровень периферийного USB‑устройства именуется многофункциональным уровнем. Этот уровень соответствует уровню клиентского обеспечения хоста. Исходя из убеждений клиентского уровня, нижележащие уровни необходимы для организации меж ним и конечными точками прямых «каналов данных», которые идут прямо до многофункционального уровня. А исходя из убеждений нашей схемы многофункциональный уровень делает последующие деяния:
· получает данные, посылаемые клиентским уровнем хоста из конечных точек каналов данных нижележащего уровня логического USB‑устройства;
· отправляет данные клиентскому уровню хоста, направляя их в конечные точки каналов данных нижележащего уровня логического USB‑устройства.
Логически передача данных меж конечной точкой и программным обеспечением делается при помощи выделения канала и обмена данными по этому каналу, а исходя из убеждений представленных уровней, передача данных смотрится последующим образом:
Рис. 1.3.1.2 Уровни передачи данных
Конечная точка (Endpoint) – это часть USB‑устройства, которая имеет неповторимый идентификатор и является получателем либо отправителем инфы, передаваемой по шине USB. Проще говоря, это буфер, сохраняющий несколько б. Обычно это блок данных в памяти либо регистр микроконтроллера. Данные, хранящиеся в конечной точке, могут быть или принятыми данными, или данными, ожидающими передачу. хост также имеет буфер для приема и передачи данных, но хост не имеет конечных точек.
Конечная точка имеет последующие главные характеристики:
· частота доступа к шине;
· допустимая величина задержки обслуживания;
· требуемая ширина полосы пропускания канала;
· номер конечной точки;
· метод обработки ошибок;
· наибольший размер пакета, который конечная точка может принимать либо отправлять;
· применяемый конечной точкой тип посылок;
· направление передачи данных.
Хоть какое USB‑устройство имеет конечную точку с нулевым номером (EndpointZero). Эта точка дозволяет хосту опрашивать устройство с целью определения его типа и характеристик, делать инициализацию и конфигурирование устройства.
Не считая нулевой точки, устройства, обычно, имеют доп конечные точки, которые употребляются для обмена данными с хостом. Доп точки могут работать или лишь на прием данных от хоста (входные точки, IN), или лишь на передачу данных хосту (выходные точки, OUT).
Нулевая точка устройства доступна опосля того, как устройство подключено к шине, включено и получило сигнал сброса по шине (busreset). Все другие конечные точки опосля включения питания либо сброса находятся в неопределенном состоянии и недосягаемы для работы до того времени, пока хост не выполнит функцию конфигурирования устройства.
Спецификация шины описывает четыре разных типа передачи данных для конечных точек:
· управляющие передачи (ControlTransfers) – употребляются хостом для конфигурирования устройства во время подключения, для управления устройством и получения статусной инфы в процессе работы. Протокол обеспечивает гарантированную доставку таковых посылок;
· передачи массивов данных (BulkDataTransfers) – используются по мере необходимости обеспечения гарантированной доставки данных от хоста к функции либо от функции к хосту, но время доставки не ограничено;
· передачи по прерываниям (InterruptTransfers) – употребляются в том случае, когда требуется передавать одиночные пакеты данных маленького размера. Любой пакет требуется передать за ограниченное время. Операции передачи носят спонтанный нрав и должны обслуживаться не медлительнее, чем того просит устройство;
· изохронные передачи (IsochronousTransfers) – используются для обмена данными в «настоящем времени», когда на любом временном интервале требуется передавать строго определенное количество данных, но доставка инфы не обещана (передача данных ведется без повторения при сбоях, допускается утрата пакетов).
канал(pipe) – это логическое соединение меж конечной точкой устройства и ПО хоста. Существует две модели каналов:
· потоковый канал (либо просто поток, streamingpipe) – это канал для передачи данных, структура которых определяется клиентским ПО . Потоки употребляются для передачи массивов данных, передачи данных по прерываниям и изохронной передачи данных. Поток постоянно однонаправленный. один и этот же номер конечной точки может употребляться для 2-ух различных потоковых каналов – ввода и вывода. Передачи данных в потоковых каналах подчиняются последующим правилам:
· запросы клиентских драйверов для различных каналов, поставленные в определенном порядке друг относительно друга, могут производиться в другом порядке;
· запросы для 1-го канала будут исполняться строго в порядке их поступления;
· если во время выполнения какого-нибудь запроса происходит суровая ошибка (STALL), поток останавливается;
· канал сообщений (messagepipe либо controlpipe) – это канал для передачи данных, структура которых определяется спецификацией USB. Каналы этого типа двунаправленные и используются для передачи управляющих посылок. Каналы сообщений строго синхронизированы – спецификация USB воспрещает одновременную обработку нескольких запросов: недозволено начинать передачу новейшего сообщения, пока не завершена обработка предшествующего. В случае появления ошибки передача сообщения быть может прервана хостом, опосля что хост может начать передачу новейшего сообщения.
Главными чертами каналов являются:
· полоса пропускания канала;
· применяемый каналом тип передачи данных;
· свойства, надлежащие конечной точке: направление передачи данных и наибольший размер пакета.
Полоса пропускания шины делится меж всеми установленными каналами. Выделенная полоса закрепляется за каналом, и если установление новейшего канала просит таковой полосы, которая не списывается в уже имеющееся распределение, запрос на выделение канала отвергается. Архитектура USB предугадывает внутреннюю буферизацию всех устройств, при этом, чем большей полосы пропускания просит устройство, тем больше должен быть его буфер. Шина USB обязана обеспечивать обмен с таковой скоростью, чтоб задержка данных в устройстве, вызванная буферизацией, не превосходила нескольких миллисекунд.
канал сообщений, связанный с нулевой конечной точкой, именуется Главным каналом сообщений (DefaultControlPipe либо ControlPipe 0). обладателем этого канала является USBD, и он употребляется для конфигурирования устройства. Главный канал сообщений поддерживает лишь управляющие передачи. Другие каналы (они именуются клиентскими каналами, ClientPipe) создаются в процессе конфигурирования устройства. Их обладателями являются драйверы устройств. По клиентским каналам могут передаваться как потоки, так и сообщения при помощи всех типов передач.
Набор клиентских каналов, с которыми работает драйвер устройства, именуется интерфейсом устройства либо связкой клиентских каналов.
1.4 Драйверная модель
WDM
WDM (WindowsDriverModel) – новенькая модель архитектуры драйверов, предложенная Microsoft для Windows 2000, хотя эта архитектура развивалась, начиная с Windows 3.11, продолжая развиваться и в Windows 98 и WindowsNT, но по-настоящему полной она стала лишь в Windows 2000.
Исходя из убеждений WDM, существует три типа драйверов:
· драйвер шины – драйвер, обслуживающий контроллер шины, адаптер, мост либо любые остальные устройства, имеющие дочерние устройства. Для всякого типа шины в операционной системе имеется собственный драйвер;
· Многофункциональный драйвер – главный драйвер устройства, предоставляющий его многофункциональный интерфейс. Этот драйвер обязателен не считая тех случаев, когда ввод-вывод осуществляется драйвером шины либо драйвером фильтров шины. Многофункциональный драйвер по определению владеет более полной информацией о собственном устройстве. Обычно лишь этот драйвер имеет доступ к специфичным регистрам устройства;
· драйвер фильтра – драйвер, поддерживающий доп функциональность устройства (либо имеющегося драйвера) либо изменяющий запросы ввода / вывода и ответы на их от остальных драйверов. Таковых драйверов быть может несколько, хотя их присутствие необязательно. Они могут работать как на наиболее высочайшем уровне, чем многофункциональный драйвер либо драйвер шины, так и на наиболее низком.
В среде WDM один драйвер не может надзирать все нюансы устройства: драйвер шины информирует диспетчера PnP о устройствах, присоединенных к шине, в то время как многофункциональный драйвер управляет устройством.
1.4.1 Драйверные слои
Согласно вышеперечисленным типам драйверов, существует три типа
объектов:
· Объекты физических устройств (PDO, PhysicalDeviceObject) – эти объекты создаются для всякого на физическом уровне идентифицируемого элемента аппаратуры, присоединенного к шине данных;
· Объекты многофункциональных устройств (FDO, FunctionalDeviceObject) – предполагает единицу логической функциональности устройства;
· Объекты фильтров устройств (FiDO, FilterDeviceObject) – предоставляют доп функциональность.
В WindowsNT 5 последовательность загрузки драйверов устройств таковая:
1. Во время загрузки операционной системы делается загрузка шинных драйверов для каждой известной системе шины (перечень шин создается при установке операционной системы и сохраняется в реестре);
2. Вызывается DriverEntry
, а потом AddDevice
для всякого шинного драйвера. В AddDevice
создается FDO для драйвера системной шины. Потом на сделанный FDO отчаливает запрос IRP_MN_START_DEVICE;
3. Шинный драйвер составляет перечень всех устройств, присоединенных к шине. Для всякого отысканного устройства создается объект PDO;
4. На любой PDO посылается запрос IRP_MN_QUERY_DEVICE_RELATION, в ответ на который шинный драйвер возвращает идентификаторы всех отысканных устройств;
5. На эти PDO отправляют запрос IRP_MN_QUERY_ID, в ответ на который драйвер системной шины докладывает идентификаторы этих устройств;
6. Получив идентификаторы, система пробует отыскать и загрузить драйверы устройств;
7. Обнаружив драйвер для устройств, система загружает его в память, вызывая его DriverEntry
. Позже вызывается AddDevice
, где создается FDO для устройства. Если устройств, управляемых сиим драйвером, несколько, то AddDevice
будет вызвана для всякого устройства. Если в реестре зарегистрированы доп фильтры, то они также загружаются в память. Потом система отправляет на FDO запрос IRP_MN_START_DEVICE;
8. Происходит посылка на FDO запроса IRP_MN_QUERY_DEVICE_RELATIONS. Если устройство само является шиной либо держит на для себя остальные устройства, которыми само не управляет, то для устройства на нем повторяется вся последовательность действий, начиная с пт 5.
Функция AddDevice
, вызываемая для всякого FDO, вызывает IoCreateDevice
и IoAttachDeviceToStack
, обеспечивая построение стека устройств. Стек устройств обеспечивает прохождение запросов от пользовательских программ до аппаратного (нижнего) уровня драйверов (Рис. 1.4.1.1).
Рис. 1.4.1.1 Стек устройств
Из вышесказанного становится понятным, что разрабатываемый драйвер должен являться драйвером-фильтром нижнего уровня, связанным с клиентским драйвером USB‑накопителя. Необходимость работы с клиентским USB‑драйвером разъясняется тем, что конкретно на этом уровне перехватываемая информация владеет требуемой структурированностью – передаются конкретно файлы, а не блоки инфы (кадры либо составленные из их транзакции), определяемые протоколом обмена по USB.
1.4.2 Точки входа
WDM-драйвера
WDM‑драйверы различаются от унаследованных драйверов тем, что должны содержать доп точки входа для поддержки PnP, и, в целом, они наиболее логичны по структуре. Приведем перечень точек входа и коротко охарактеризуем их предназначение:
NTSTATUSDriverEntry
(
INPDRIVER_OBJECTDriverObject, // указатель на объект драйвера
INPUNICODE_STRINGRegistryPath) // путь к подразделу регистра,
// относящегося к драйверу
Эта функция производится при загрузке драйвера операционной системой. В WDM‑драйверах на DriverEntry
возложены обязанности по регистрации всех других точек входа драйвера.
NTSTATUS AddDevice
(
IN PDRIVER_OBJECT DriverObject, // указательнаобъектдрайвера
INPDEVICE_OBJECTPhysicalDeviceObject) // указатель на родительский PDO
В драйверах, поддерживающих PnP, через эту точку входа МенеджерPnP отправляет драйверу извещение о обнаружении устройства, за которое должен отвечать драйвер. ФункцияAddDevice
обязана сделать объект устройства при помощи вызова IoCreateDevice
и по мере необходимости присоединить его к стеку устройств при помощи IoAttachDeviceToDeviceStack
.
NTSTATUS DriverUnload
(
IN PDRIVER_OBJECT DriverObject) // указательнаобъектдрайвера
Вызывается при выгрузке драйвера. В данной функции должны осво
бождаться все затребованные драйвером ресурсы. Драйверы WDM‑модели
делают эти деяния в обработчике запросов IRP_MJ_PNP с субкодом IRP_MN_REMOVE_DEVICE, другими словами при удалении устройства из системы.
Следует выделить отдельный класс точек входа драйвера, которые предусмотрены для обработки IRP‑пакетов с разными кодами операций. Эти точки входа регистрируются при загрузке драйвера в функции DriverEntry
. Регистрация делается методом наполнения частей массива MajorFunction адресами диспетчеризуемых функций. Индексом в этом массиве являются коды IRP_MJ_XXX, другими словами описанные числами типы пакетов IRP. Диспетчер ввода / вывода, ориентируясь на наполнение этого массива, вызывает нужные функции драйвера.
Так как для драйвера важны лишь адреса рабочих процедур, то все рабочие процедуры могут иметь совсем произвольные имена.
1.5 Пакет запроса ввода / вывода (
IRP)
Пакеты ввода / вывода (IRP‑пакеты) употребляются для передачи запросов к драйверу от его клиентов. Они являются структурами данных переменной длины, и состоят из обычного заголовка, содержащего общую учетную информацию, и 1-го либо нескольких блоков характеристик, именуемых ячейками стека ввода / вывода (I/OStackLocation).
Приведем структуру заголовка IRP‑пакета:
Таблица 1.5.1. структура заголовка IRP‑пакета.
Поля
Описание
IO_STATUS_BLOCK IoStatus
Статус запроса
PVOID AssociatedIrp. SystemBuffer
Указатель на системный буфер для варианта, если устройство поддерживает буферизованный ввод / вывод
PMDL MdlAddress
Указатель на MDL‑перечень в случае, если устройство поддерживает прямой ввод / вывод
PVOID UserBuffer
адресок пользовательского буфера для ввода / вывода
BOOLEAN Cancel
Индикатор того, что IRP‑пакет должен быть аннулирован
Основное предназначение ячеек стека ввода / вывода заключается в том, чтоб хранить многофункциональный код и характеристики запроса на ввод / вывод. Ниже, в таблице 1.5.2 приводятся поля ячеек стека ввода / вывода, к которым драйвер может обращаться конкретно по указателю (что не рекомендуется созодать для других полей):
Таблица 1.5.2. структура ячейки стека ввода / вывода
Поля
Описание
UCHAR MajorFunction
Код IRP_MJ_XXX, описывающий предназначение операции
UCHAR MinorFunction
Субкод операции
PDEVICE_OBJECT DeviceObject
Указатель на объект устройства, которому был адресован данный объект IRP
PFILE_OBJECT FileObject
Файловый объект для данного запроса, если он задан
unionParameters (трактовка определяется значением MajorFunction)
struct Read
характеристики для IRP типа IRP_MJ_READ:
ULONG Length
ULONG Key
LARGE_INTEGER ByteOffset
struct Write
характеристики для IRP типа IRP_MJ_WRITE:
ULONG Length
ULONG Key
LARGE_INTEGER ByteOffset
struct DeviceControl
характеристики для IRP типа IRP_MJ_DEVICE_CONTROL:
ULONG OutputBufferLength
ULONG InputBufferLength
ULONG IoControlCode
PVOID Type3InputBuffer
Приведем графическое
Рис. 1.5.1 структура IRPпакета
Общение с USB‑накопителями в ОС WindowsNT 5 на уровне драйверов, как уже было сказано в разделе 1.3.1, происходит средством передачи URB‑пакетов. Указатели на URB‑пакеты содержат ячейки стека IRP‑пакета, доступ к сиим указателям осуществляется последующим образом:
…
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PURB Urb = IrpSp->Parameters. Others. Argument1;
…
Приведем частичное объявление структуры из справочной документации Microsoft. Отметим лишь поля, внедрение которых нужно в рамках данной курсовой работы:
typedef struct _URB {
union {
struct _URB_HEADER UrbHeader;
struct _URB_SELECT_INTERFACE UrbSelectInterface;
struct _URB_SELECT_CONFIGURATION UrbSelectConfiguration;
struct _URB_BULK_OR_INTERRUPT_TRANSFER UrbBulkOrInterruptTransfer;
}
} URB, *PURB;
Поле UrbHeader хранит информацию о коде URB‑пакета, по которому можно найти, какая операция запрашивается.
Поля UrbSelectInterface и UrbSelectConfiguration служат для запроса по выбору интерфейса и конфигурации устройства, которые будут употребляться при работе с устройством. Пакеты данной структуры отправляются хостом к устройству сначала его работы, при конфигурировании.
Поле UrbBulkOrInterruptTransfer несет более важную в рамках данной курсовой работы информацию – указатели на блоки ввода / вывода USB‑устройства. Приведемописаниеструктуры_URB_BULK_OR_INTERRUPT_TRANSFER:
struct _URB_BULK_OR_INTERRUPT_TRANSFER {
struct _URB_HEADER Hdr;
USBD_PIPE_HANDLE PipeHandle;
ULONG TransferFlags;
ULONG TransferBufferLength;
PVOID TransferBuffer;
PMDLTransferBufferMDL;};
Поля данной структуры описаны в последующей таблице:
Таблица 1.5.3 Поляструктуры URB_BULK_OR_INTERRUPT_TRANSFER
Поле
Описание
struct _URB_HEADER Hdr
Обычный заголовок URB‑пакета, содержащий код запроса
USBD_PIPE_HANDLE PipeHandle
Дескриптор канала, на который передаются данные
ULONG TransferFlags
Флаги, определяющие направление передачи данных и метод обработки ошибок
ULONG TransferBufferLength
Длина передаваемого блока данных в б
PVOID TransferBuffer
Указатель на передаваемый буфер. Буфер находится в нестраничной памяти
PMDL TransferBufferMDL
Указатель на MDL‑перечень, несущий передаваемую информацию. Буфер находится в страничной памяти
Необходимо подчеркнуть, что один из указателей TransferBuffer либо TransferBufferMDL равен NULL, другими словами в границах 1-го пакета передается лишь одна порция данных.
задачка протоколирования обмена информацией сводится к перехвату и сохранению буферов TransferBuffer и TransferBufferMDL.
1.6 Уровни запроса прерываний
В любой момент времени центральный микропроцессор находится на одном из уровней IRQL (InterruptRequestLevel– уровень запросов прерываний). Уровни IRQL размещаются в порядке убывания от HIGHEST_LEVEL до PASSIVE_LEVEL. Любому из прерываний (прерывания от наружных устройств, системные часы, и т.д.) соответствует собственный уровень IRQL. Особым действиям операционной системы также назначены IRQL. Они отмечены в нижней части приведённой таблицы:
Таблица 1.6.1. Уровни запросов прерываний.
Уровень
Предназначение
HIGHEST_LEVEL
Наивысший уровень. Все прерывания заблокированы
POWER_LEVEL
Прерывания по отказу питания
IPI_LEVEL
Межпроцессорное взаимодействие
CLOCK2_LEVEL
Прерывание по системному таймеру 2
СLOCK1_LEVEL
Прерывание по системному таймеру 1
PROFILE_LEVEL
Прерывание по таймеру замера производительности
уровни DRQL
Обыденные прерывания устройств
DISPATCH_LEVEL
Диспетчеризация потоков и выполнение отложенных процедур
APC_LEVEL
Выполнение асинхронного вызова процедуры
PASSIVE_LEVEL
Обыденное выполнение кода потока
Общее правило обработки уровней запросов прерываний говорит, что прерывания с IRQL, наименьшим, чем у выполняемого в данный момент кода, маскируются. Во время выполнения кода потока (пользовательского либо системного) устанавливается меньший IRQL = 0 (PASSIVE_LEVEL). Работа драйвера почаще всего производится на уровне IRQL = 2 (DISPATCH_LEVEL). Уровни, лежащие над ним, именуются DIRQL (DeviceIRQL) и выставляются для обработчиков прерываний от наружных устройств (ISR– interruptserviceroutine). Даже во время выполнения ISR драйвера может произойти прерывание с огромным IRQL, к примеру, принадлежащее другому драйверу.
Чем выше текущий уровень IRQL исполняемого кода, тем меньше функций ему доступно. Так, к примеру, диспетчер потоков работает на уровне
DISPATCH_LEVEL, и, как следует, не будет вызываться, пока на микропроцессоре с уровнем огромным либо равным DISPATCH_LEVEL исполняется иной код. Таковым образом, на уровнях DISPATCH_LEVEL и выше отключается переключение потоков. Функции ожидания диспетчерских объектов (действия, мьютексы, семафоры) с хорошим от нуля временем, воззвание к файлам, подкачка отсутствующих в физической памяти страничек – всё это также становится труднодоступным. Для корректного сохранения запросов в файле фильтр в таковых вариантах должен использовать специальную методику.
1.7 Извещение о окончании запроса
нижестоящим драйвером
При отслеживании обмена данными драйвер-фильтр может получать извещения о том, что некий переданный запрос был завершён нижестоящим драйвером. Механизм извещения состоит в том, что вызовом специальной функции IoSetCompletionRoutine
фильтр обращается к стеку в пакете IRP. В позиции стека, последующей за текущей позицией, он устанавливает в особом поле адресок функции окончания (completionroutine). Потом при передаче пакета по цепочке позиция стека возрастает.
Когда нижестоящий драйвер посылает пакет запроса на окончание (вызовом IoCompleteRequest
), подсистема ввода / вывода начинает просматривать стек снутри этого пакета от конца к началу. Если в некий позиции стека определена функция окончания, управление передаётся ей. Отработав, функция возвращает итог, сигнализирующий о успехе, ошибке либо необходимости предстоящей обработки запроса.
При первых 2-ух вариантах подсистема ввода / вывода перебегает к последующей позиции стека и продолжает просмотр, пока не будет достигнуто его начало. Опосля этого запрос заканчивается обычным образом.
При 3-ем же варианте просмотр стека немедля прекращается и запрос не будет завершён. Эта возможность реализована для того, чтоб драйвер-фильтр мог выполнить какие-либо деяния над пакетом запроса опосля того, как тот будет обработан в нижестоящем драйвере. Опосля таковой «доборной обработки» пакет опять должен быть выслан на окончание.
1.8 Работа с файлами в режиме ядра
Так как протоколируемая информация обязана сохраняться в файле на диске, следует разглядеть главные функции уровня ядра, применяемые при работе с файлами.
Для открытия файла из драйвера режима ядра употребляется всепригодная функция ZwCreateFile
. Универсальность данной функции заключается в том, что с ее помощью делается и открытие имеющихся файлов, и создание новейших.
Специфичность системной функции ZwCreateFile
заключается в том, что она имеет протокольных характеристик даже больше, чем пользовательский вызов CreateFile
. Значимая часть входной инфы о открываемом объекте поступает снутри структуры OBJECT_ATTRIBURTES, которую следует за ранее сделать и заполнить надлежащими определенными данными. Для ведения учетной инфы открытого объекта употребляется структура данных IO_STATUS_BLOCK, которую следует предоставить при вызове (инициализировать ее не следует).
Представим главные характеристики функции ZwCreateFile
в последующей таблице:
Таблица 1.8.1. характеристики функции ZwCreateFile
Тип параметра
Описание параметра
OUT PHANDLE pHandle
Указатель на переменную, куда следует поместить дескриптор открытого объекта
IN ACCESS_MASK DesiredAccess
Черта доступа к объекту. Для фалов почаще всего употребляются значения
GENERIC_READ либо GENERIC_WRITE
IN POBJECT_ATTRIBUTES
pObjAttributes
Указатель на заполненную вызывающим кодом структуру данных, которая обрисовывает имя, положение и некие остальные свойства открываемого объекта
OUT PIO_STATUS_BLOCK pIOStatus
Указатель на буфер, в каком будет расположена информация о открытом объекте в формате структуры IO_STATUS_BLOCK
IN PLARGE_INTEGER AllocationSize
Исходный размер файла в б. Ненулевое к примеру, FILE_SHARE_READ – для чтения
IN ULONG CreateDispositionFlags
метод открытия файла, к примеру, FILE_OPEN_IF – если не существует, сделать
IN ULONG CreateOptions
Композиция флагов сотворения, к примеру, FILE_SYNCHONOUS_IO_NONALERT – все операции над файлом производятся как синхронные (DesiredAccess должен включать флаг SYNCHRONIZE)
IN PVOID EaBuffer
Для драйверов устройств следует указывать NULL
IN ULONG EaLength
Для драйверов устройств следует указывать 0
Для наполнения структуры атрибутов объекта употребляется функция
InitializeObjectAttributes
. Опишем ее характеристики в последующей таблице:
Таблица 1.8.2. Характеристики функции InitializeObjectAttributes
Тип параметра
Описание параметра
OUT POBJECT_ATTRIBUTES pObjAttributes
Указатель на переменную, куда следует поместить атрибуты объекта
IN PUNICODE_STRING ObjectName
имя объекта, HANDLE которого создается
IN ULONG Attributes
Флаги атрибутов объекта, при открытии файла как правило употребляются флаги OBJ_CASE_INSENSITIVE и OBJ_KERNEL_HANDLE
IN HANDLE RootDirectory
Дескриптор корневой директории для объекта, описатель атрибутов которого создается. Если ObjectName вполне обрисовывает путь к объекту, то значению RootDirectory присваивается NULL
IN PSECURITY_DESCRIPTOR SecurityDescriptor
Дескриптор сохранности. Если обозначено NULL, то применяется обычный дескриптор
Запись в файл производится системной функцией ZwWriteFile
:
Таблица 1.8.3. характеристики функции ZwWriteFile
Тип параметра
Описание параметра
IN HANDLE FileHandle
Дескриптор открытого либо измененного файлового объекта
IN HANDLE Event
Для драйверов устройств следует указывать NULL
IN PIO_APC_ROUTINE
Для драйверов устройств следует указывать NULL
IN PVOID ApcContext
Для драйверов устройств следует указывать NULL
OUT PIO_STATUS_BLOCK pioStatusBlock
В поле pIoStatusBlock->Information по окончании вызова находится число реально записанных б
IN PVOID Buffer
Буфер с данными для записи
IN ULONG Length
Размер записываемой порции данных
IN PLARGE_INTEGER pByteOffset
Указатель на переменную где содержится смещение в файле от его начала, по которому следует создавать запись
IN PULONG Key
Для драйверов устройств следует указывать NULL
Для закрытия дескриптора объекта следует использовать функцию ZwCloseKey
.
Необходимо подчеркнуть, что функции работы с файлами могут работать лишь на уровне IRQL, равном PASSIVE_LEVEL. Это приводит к необходимости внедрения специальной методики при протоколировании обмена данными с USB‑накопителем.
1.9 Работа с реестром в режиме ядра
Работа с реестром из драйвера уровня ядра нужна, потому что конкретно в системном реестре хранится информация о настройках протоколирования. Информация о настройках хранится в ключе реестра, связанном с устройством, к которому подключается драйвер-фильтр. Имя этого устройства соответствует шаблону HKEY_LOCAL_MACHINESystemCurrentControlSetEnumUSBXXXXXXDeviceParameters.
Доступ ключу устройства в реестре в драйвере предоставляется функцией IoOpenDeviceRegistryKey
. Перечислим ее характеристики:
Таблица 1.9.1. Характеристики функции IoOpenDeviceRegistry
Тип параметра
Описание параметра
IN PDEVICE_OBJECT DeviceObject
Указатель на объект физического устройства, ключ которого должен быть открыт
IN ULONG DevInstKeyType
Параметр определяющий, связан ли открываемый ключ конкретно с физ. устройством либо его программным обеспечением
IN ACCESS_MASK DesiredAccess
Этот параметр описывает права доступа к ключу
OUT PHANDLE DevInstRegKey
Указатель на переменную, куда следует поместить дескриптор открытого ключа
Открыв главный ключ, следует получить доступ к вложенному в него ключу с параметрами протоколирования. Для этого употребляется функция ZwOpenKey
. Перечислим ее характеристики:
Таблица 1.9.2. Характеристики функции ZwOpenKey
Тип параметра
Описание параметра
OUT PHANDLE KeyHandle
Указатель на переменную, куда следует поместить дескриптор открытого ключа
IN ACCESS_MASK DesiredAccess
Этот параметр описывает права доступа к ключу
IN POBJECT_ATTRIBUTES pObjectAttributes
Указатель на заполненную вызывающим кодом структуру данных, которая при использовании в данной функции обязана содержать имя открываемого ключа
Открыв ключ собственных характеристик драйверу нужно считать опции протоколирования. Для чтения значения характеристик ключа реестра употребляется функция ZwQueryValueKey
. Перечислим ее характеристики:
Таблица 1.9.3. Характеристики функции ZwQueryValueKey
Тип параметра
Описание параметра
IN HANDLE KeyHandle
Дескриптор ключа, которому принадлежит считываемый параметр
IN PUNICODE_STRING ValueName
Строчка юникод-символов, содержащая имя параметра ключа
IN KEY_VALUE_INFORMATION_CLASS
KeyValueInformationClass
Этот параметр воспринимает одно их 3-х значений зависимо от полноты инфы о параметре:
KeyValueBasicInformation
KeyValueFullInformation
KeyValuePartialInformation
OUT PVOID KeyInformation
Указатель на буфер, выделенный вызывающим кодом, в который обязана быть помещена запрашиваемая информация
IN ULONG Length
Длина предоставленного буфера
OUT PULONG ResultLength
Указатель на переменную, содержащую число реально записанных в KeyInformation б
Опосля того, как работа с ключом реестра закончена, его дескриптор следует высвободить вызовом функции ZwClose
.
1.10
MDL‑списки
MDL‑перечень – это структура, хранящая отображение блока виртуальной памяти на физическую память. MDL‑перечень употребляется в разрабатываемом драйвере для хранения инфы из URB‑пакетов, связанных с вводом / выводом USB‑устройства. Не считая того, обмен информацией с USB‑устройством в режиме прямого доступа к памяти ведется конкретно средством MDL‑списков.
Перед использовании MDL‑перечня в драйвере нужно провести ряд предварительных действий:
· выделить область в страничной памяти при помощи вызова функции
ExAllocatePool
;
· вызвать функцию MmCreateMdl
, создающую и инициализирующую MDL‑перечень;
· выполнить фиксацию страничек, обрисованных в MDL‑перечне, в физической памяти при помощи вызова функции MmProbeAndLockPages
.
Опосля окончания использования MDL‑перечня его следует высвободить:
· отменить фиксацию страничек страничной памяти в оперативки вызовом функции MmUnlockPages
;
· очистить MDL‑перечень, вызвав функцию IoFreeMdl
;
· высвободить выделенную под перечень страничную память вызовом
ExFreePool
.
2. Конструкторский раздел
2.1 Точки входа разрабатываемого драйвера
Разрабатываемый драйвер является драйвером нижнего уровня. В стеке драйверов USB‑накопителя он находится конкретно под драйвером устройства, если опосля его загрузки не произойдет установки какого-нибудь другого драйвера-фильтра нижнего уровня.
Разрабатываемый драйвер содержит в себе последующие точки входа:
· DriverEntry
;
· AddDevice
;
· DriverUnload
;
· Функции обработки IRP‑пакетов:
· обработка IRP‑пакетовскодами IRP_MJ_INTERNAL_DEVICE_CONTROL – функцияDispatchInternalDeviceControl
;
· обработка IRP пакетов с иными кодами – функция DispatchRoutine
.
Разглядим каждую из их наиболее тщательно.
2.1.1 Функция
DriverEntry
В данной функции происходит регистрация всех обычных точек входа драйвера и обработчиков IRP‑пакетов. В разрабатываемом драйвере пакеты IRPc кодами, не равными IRP_MJ_INTERNAL_DEVICE_CONTROL обрабатываются функцией DispatchRoutine
.
2.1.2 Функция
AddDevice
Управление данной функции передается диспетчером ввода / вывода опосля того, как завершает свою работу DriverEntry
. AddDevice
делает многофункциональный объект устройства при помощи вызова IoCreateDevice
и подключает его к стеку драйверов избранного устройства (вызовом IoAttachDeviceToDeviceStack
). Не считая того, в данной функции выполняются деяния по подготовке к протоколированию: считываются опции из системного реестра, выделяется буфер для сбора протоколируемой инфы, создается лог-файл.
2.1.3 Функция
DriverUnload
Функция DriverUnload
нужна для того, чтоб создать драйвер выгружаемым. В унаследованных драйверах на эту функцию возложен весь процесс выгрузки драйвера: удаление символьных ссылок, объектов устройств драйвера, отключение прерываний от объектов, освобождение выделенной памяти. В WDM‑драйверах все эти деяния возложены на функцию-обработчик пакетов с кодом IRP_MJ_PNP.
2.1.4 Функция
DispatchRoutine
На эту функцию возложены обязанности по обработке IRP‑пакетов с разными кодами, хотя в разрабатываемом драйвере существует необходимость в обработке лишь 2-ух типов запросов. Все запросы с кодом, хорошим от IRP_MJ_PNP передаются по стеку драйверов без конфигураций. Запросы же IRP_MJ_PNP диспетчеризуются по суб-кодам в функции PnP
_
Dispatch
. Необходимость диспетчеризации по суб-кодам запросов IRP_MJ_PNP вызвана тем, что драйвер не должен нарушать порядка работы операционной системы и должен подчиняться PnP‑менеджеру, другими словами в драйвере должны корректно обрабатываться действия старта и удаления устройства.
2.1.5 Функция
DispatchInternalDeviceControl
Запросы ввода / вывода к USB‑накопителю передаются в составе IRP‑пакетов с кодом IRP_MN_INTERNAL_DEVICE_CONTROL. Этот пакет содержит полную информацию о направлении и нраве передаваемых данных. Другими словами для протоколирования обмена информацией с USB‑носителем следует перехватывать пакеты конкретно этого типа.
Для того чтоб перехватывать информацию, передаваемую в обоих направлениях, следует установить функцию оборотного вызова диспетчера ввода / вывода. методика установки данной функции была описана в разделе 1.7. При наличии данной функции разрабатываемый драйвер-фильтр получит возможность перехвата данных, передаваемых от устройства к хосту.
Для сохранения протоколируемой инфы употребляется, как уже было сказано в разделе 1.10, MDL‑перечень. Этот MDL‑перечень создается в функции AddDevice
. Размер памяти, выделяемой под перечень, совпадает с наибольшим размером лог-файла, задаваемым в пользовательском приложении. Опосля сотворения перечень фиксируется в страничной памяти, что предутверждает его выгрузку на твердый диск во время работы драйвера. Опосля этих предварительных действий перечень употребляется в функции DispatchInternalDeviceControl
– он заполняется перехватываемой информацией.
Запись скопленного буфера в лог-файл происходит при удалении устройства.
Таковая методика выбрана из-за того, что функция DispatchInternalDeviceControl
работает на уровне запроса прерываний, равном DISPATCH_LEVEL, что очень затрудняет внедрение устройств синхронизации, которые могли бы дозволить перейти на уровень запроса прерываний, равный PASSIVE_LEVEL, где стают доступными функции работы с файлами. Если б это было достигнуто в разрабатываемом драйвере, то отпала бы необходимость выделения огромных размеров нестраничной памяти для хранения протокола.
Запись файла на диск в момент удаления устройства вероятна, потому что это событие инициализируется PnP‑менеджером, запросы которого постоянно происходят на уровне IRQL, равном PASSIVE_LEVEL.
2.2 Размещение кода драйвера в памяти
Некие функции драйвера, к примеру те, которые делают инициализацию, прибыльно выполнить и высвободить память, занимаемую ими. В языке C есть особая директива #
pragma
_
alloc
_
text
(<тип секции>, <имя размещаемой функции>), позволяющая управлять размещением кода. В качестве типа секции могут указываться значения «INIT» либо «PAGE».
Функции с размещением в секции «INIT» выгружаются, и память, занимаемая ими, освобождается сходу по окончании их работы. В разрабатываемом драйвере в секции «INIT» расположена точка входа DriverEntry
, так как она производится единожды при загрузке драйвера.
Точки входа AddDevice
и DriverUnload
размещаются в секции «PAGE», другими словами в страничной памяти, так как они гарантированно вызываются на уровне льгот, равном PASSIVE_LEVEL и, даже оказавшись выгруженными на диск, будут немедля загружены в физическую память менеджером страничной памяти (который способен работать лишь на уровне PASSIVE_LEVEL).
Другие же точки входа (DispatchRoutine
иDispatchInternalDeviceControl
) размещаются по дефлоту, в нестраничной памяти, так как их работа зависит от клиентского драйвера USB‑устройства, под которым в стеке драйверов размещается разрабатываемый драйвер-фильтр. Уровень льгот его запросов слабо предсказуем и быть может равен DISPATCH_LEVEL. На этом уровне подкачка страничек невозможна, что при воззвании к выгруженной функции приведет к краху системы.
2.3 Установка драйвера в системе
Для установки драйвера следует сделать его ключ в системном реестре.
Имяключадолжноиметьследующийвид:
HKEY_LOCAL_MACHINESystemCurrentControlSetServicesdriver_name.
Крайняя часть имени специфична для устанавливаемого драйвера. Создаваемый ключ должен содержать последующие характеристики:
· DisplayName – значение этого параметра обрисовывает текст, применяемый в служебных программках;
· ErrorControl – этот параметр предписывает операционной системе метод поведения в той ситуации, когда при загрузке драйвера произошла ошибка;
· ImagePath – обрисовывает полный путь к файлу с исполняемым кодом драйвера;
· Start – обрисовывает стадию загрузки операционной системы, когда следует загружать драйвер;
· Type – описывает тип драйвера.
Вероятные значения обозначенных характеристик можно выяснить из документации MSDN.
Таковым образом, 1-ая стадия установки драйвера в систему заключается
в том, что должен быть сотворен ключ драйвера в реестре, а сам драйвер
скопирован в каталог, описываемый строчкой ImagePath (как правило -%SystemRoot%System32Driversdriver_name.sys).
Дальше обязано быть выбрано устройство, на которое будет установлен фильтр. Избранному устройству в системном реестре соответствует ключ с именованием вида HKLMCurrentControlSetEnumUSBXXXYYY.
Крайняя часть ключа (XXXYYY) определяется именованием устройства. При установке драйвера фильтра нижнего уровня в разделе YYY создается строковый параметр LowerFilters, которому присваивается драйвер.
Не считая того, в ключе, связанном с устройством, при установке драйвера создается доп раздел MyFilterParams, который хранит два параметра:
· MaxLogSize – наибольший размер лог-файла;
· LogFileName – имя лог-файла.
3. Технологический раздел
3.1 Выбор языка и средств программирования
Разрабатываемый программный комплекс состоит из 2-ух частей:
· Драйвера-фильтра;
· Управляющего приложения для установки фильтра и ввода характеристик протоколирования.
Любая из программ, производит общение с операционной системой на разном уровне. Соответственно нужен различный подход к сиим задачкам и особый подбор средств разработки.
3.1.1 драйвер-фильтр
От разрабатываемого драйвера-фильтра требуется высочайшая скорость работы и надежность. При его работе осуществляется огромное количество манипуляций с памятью, операций с указателями, преобразований типов. Принципиально представлять структуру скомпилированного продукта, чтоб верно представить для себя логику его работы. Посреди языков программирования, удовлетворяющих сиим требованиям, известны языки С и ассемблер. Для написания драйвера предпочтение было отдано языку C. Таковой выбор был изготовлен по последующим причинам:
· Существует особый компилятор C, поставляемый в составе пакета DDK, предназначенный специально для компиляции драйверов. Он содержит огромное количество макроопределений и библиотек, позволяющих создать процесс написания драйвера наиболее легким. Microsoft советует его как основную среду для разработки драйверов для Windows;
· Программки на ассемблере работают резвее, чем программки, написанные на C. Но разница в скорости меж этими языками не весьма велика. Зато производительность труда при использовании C намного выше, чем при использовании ассемблера.
3.1.2 Управляющее приложение
Управляющее приложение было сотворено в среде разработки BorlandC++ Builder, так как эта среда программирования предоставляет широкие способности по созданию пользовательского интерфейса и ускоряет процесс разработки программных товаров. Данная среда программирования содержит огромное количество обычных частей оконного пользовательского интерфейса, внедрение которых позволило создать управляющее приложение обычным и понятным для юзера. Для рассматриваемого приложения скорость работы и размер исполняемого файла не являются критическими факторами, потому выбор среды BorlandC++ Builder можно считать полностью обоснованным.
3.2 Структуры данных драйвера-фильтра
Для сбора инфы о вводе / выводе устройства употребляется структура BUFFER, объявленная в драйвере последующим образом:
typedef struct _BUFFER
{
PVOID Buffer;
PMDL Mdl;
ULONG MaxSize;
ULONG CurrentSize;
} BUFFER, *PBUFFER;
Поясним значения полей структуры:
· Buffer
– указатель на буфер, хранящий информацию;
· Md
l – указатель на MDL‑перечень, хранящий отображение буфера на системные странички в памяти;
· MaxSize
– наибольший размер буфера в б;
· CurrentSize
– текущий размер буфера в б.
В программировании считается дурным тоном создание переменных, глобальных для всего кода. В драйверах рекомендуется располагать эти глобальные переменные в структуре расширения устройства. Создание данной структуры, конечный вид которой определяется программером, происходит при вызове IoCreateDevice
, другими словами при разработке объекта многофункционального устройства драйвера. Указатель на расширения устройства быть может получен по указателю на объект устройства.
В разрабатываемом драйвере в расширении устройства размещена последующая информация:
typedef struct _DEVICE_EXTENSION
{BUFFER UrbPackets;
HANDLE LogFileHandle;
BOOLEAN PreparedToLog;
PURB Urb;
ULONG UrbCount;
PDEVICE_OBJECT topDevObject;
…
} DEVICE_информация о вводе / выводе;
· PreparedToLog
– флаг, указывающий на то, что подготовка к протоколированию прошла удачно;
· Urb
– пакет, информация о котором переносится в буфер UrbPackets;
· UrbCount
– число URB‑пакетов, прошедших через фильтр;
· topDevObject
– объект устройства, находящийся в стеке под нашим устройством.
3.2 интерфейс управляющего приложения
Управляющее приложение создано для установки драйвера-фильтра в системе и передачи ему характеристик протоколирования через системный реестр.
интерфейс управляющего приложения состоит из головного окна, представленного на рисунке 3.2.1:
Рис. 3.2.2 интерфейс управляющего приложения
В левой части окна размещен перечень, в каком показываются имена устройств, присутствующих в системе.
Перед установкой драйвера-фильтра на некий USB‑накопитель, следует сделать ключ драйвера в системном реестре. Для этого следует расположить файл драйвера MyUSBFlt.sys в корневом каталоге управляющего приложения и надавить клавишу «Сделать ключ драйвера». По окончании операции будет выдано сообщение о ее итоге.
установка драйвера-фильтра допускается лишь на устройства типа «Запоминающее устройство USB». Для этого устройство следует выделить в перечне, а потом ввести наибольший размер лог-файла и путь к нему. Опосля этого следует надавить клавишу «Установить драйвер». Зависимо от результата установки будет выдано сообщение о успехе операции либо ее беде.
драйвер-фильтр начнет свою работу опосля того, как устройство, на которое он был установлен, будет перезапущено. Перезапуск можно выполнить методом выделения подходящего устройства в перечне и нажатия клавиши «Перезапустить устройство». Такого же результата можно достигнуть, перезапустив устройство типа «Хост-контроллер» либо «Корневой концентратор», к которому подключен рассматриваемый USB‑накопитель. Вероятен также перезапуск устройства методом отсоединения от порта концентратора и следующего подключения к нему.
Удаление драйвера-фильтра из системы обязано выполняться в оборотном порядке: поначалу удаляется драйвер с устройства, а потом ключ драйвера. Это соединено с тем, что в случае, если будет удален ключ драйвера, а само устройство не будет освобождено от фильтра, то работа устройства будет блокирована. Но опосля полного удаления фильтра из системы и перезапуска устройства, его работа будет происходить в обыкновенном режиме.
3.3 Тестирование драйвера-фильтра
драйвер был протестирован с внедрением обычной тестирующей утилиты DriverVerifier, поставляемой в составе пакета DDK. При помощи данной утилиты были проведены последующие испытания:
· Операции с пулами памяти;
· Правильность уровней IRQL, на которых производится код драйвера;
· Нехватка ресурсов;
· Нетипичные запросы к драйверу.
Все испытания прошли удачно. память в системе распределялась верно, ошибок с ней не появлялось. На нехватку ресурсов драйвер реагировал корректно. Нетипичные запросы к драйверу не обрабатывались им.
Для отладки драйвера использовалась программка DebugView. Эта утилита дозволяет производить перехват отладочных сообщений, выдаваемых драйвером.
Заключение
В данной работе рассмотрен вопросец, связанный с разработкой драйверов устройств в системе Windows, и реализован драйвер-фильтр USB‑накопителя.
Разработанный драйвер предоставляет последующие способности:
· возможность установки на хоть какой USB‑накопитель, присутствующий в системе;
· перехват инфы ввода / вывода USB‑накопителя;
· запись перехваченной инфы в файл на диске.
Драйвер-фильтр был протестирован при помощи тестовых утилит из состава пакета DDK и отвечает всем современным требованиям, накладываемым ОС Windows на свойства драйверов.
Тем не наименее, есть пути по усовершенствованию разработанного программного комплекса. к примеру, существует возможность по созданию связки «драйверуровняядра – управляющееприложениепользовательскогоуровня», которая при наличии развитых устройств синхронизации дозволила бы получать информацию о вводе / выводе устройства в интерактивном режиме. Но это довольно трудозатратная задачка, выходящая за рамки курсовой работы.
Перечень литературы и Веб-ресурсов
1. Агуров П.В. Интерфейсы USB. Практика использования и программирования.–СПб.: БХВ-Петербург, 2004. – 576 с.
2. Бойцов В.П. Программирование драйверов Windows. Изд. 2-е, перераб. и доп. – М.: ООО «Двучлен-Пресс», 2004. – 480 с.
3. Материалыпроекта «Windows Assembly Site» – www.wasm.ru.
4. Материалы веб-сайта www.usb.org.
5. MSDN Library, Copyright 1987–2005 Microsoft Corporation.
]]>