Пишем драйвер wdm на ассемблере

Пишем драйвер Windows на ассемблере

Автор: Автор неизвестен — Компьютеры
Жанр: Программирование

Признаюсь честно: мне нравится Ассемблер. Вернее, даже не сам Ассемблер, а стиль общения с компьютером через него.

В сети есть несколько примеров создания драйверов виртуальных устройств VxD на Ассемблере.

Но нет ни одного аналогичного примера для драйвера WDM.

Так исправим же эту досадную оплошность!

Создание несложного драйвера с использованием только лишь Ассемблера – довольно трудоёмкое занятие.

По двум причинам:

Пишем драйвер Windows на ассемблере скачать fb2, epub бесплатно

Конспект лекций соответствует требованиям Государственного образовательного стандарта высшего профессионального образования РФ и предназначен для освоения студентами вузов специальной дисциплины «Базы данных».

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

Добро пожаловать в мир SQL и в обширный, но постоянно растущий мир бизнеса, основанного на использовании технологий баз данных. Прочитав эту книгу, вы получите знания, которые вскоре станут просто необходимыми для выживания в современном мире реляционных баз данных и управления ими. К сожалению, поскольку сначала необходимо разобраться с основами SQL и определить некоторые понятия, которые вам понадобятся в дальнейшем, этот урок представлен почти сплошным текстом. Смиритесь с этим, ведь приведенный здесь «скучный материал» непременно окупится сторицей.

PascalABC.NET — это язык программирования Паскаль нового поколения, включающий классический Паскаль, большинство возможностей языка Delphi, а также ряд собственных расширений. Он реализован на платформе Microsoft.NET и содержит все современные языковые средства: классы, перегрузку операций, интерфейсы, обработку исключений, обобщенные классы и подпрограммы, сборку мусора, лямбда-выражения, средства параллельного программирования.

PascalABC.NET является мультипарадигменным языком: на нем можно программировать в структурном, объектно-ориентированном и функциональном стилях.

PascalABC.NET — это также простая и мощная интегрированная среда разработки, поддерживающая технологию IntelliSense, содержащая средства автоформатирования, встроенный отладчик и встроенный дизайнер форм.

Электронные вычислительные машины выполняют арифметические и логические операции, при этом используется два класса переменных: числа и логические переменные.

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

Логические переменные определяют состояние системы или принадлежность её к определённому классу состояний (коммутация каналов, управление работой ЭВМ по программе и т.п.).

Э л е м е н т ы ж а р г о н а «х э к е р о в»

B backslash [бэкслэш] — обратная косая черта (название символа) backspark [бэкспаак] — закрывающая кавычка (название символа) bang [бэнг] — восклицательный знак (название символа) barf [бааф] — выражать недовольство (действиями пользователя со стороны

системы) beetle [биитл]- «жучок» (координатный манипулятор для управления курсором) bells and whistles [белз энд вайлэс] — ненужные свойства программы, «укра

Эта книга научит вас, как разрабатывать программное обеспечение для платформы J2ME компании «Sun Microsystems». Эта книга придерживается стиля учебного пособия, это не справочное руководство.

Цель — дать вам твердую основу в понятиях и техниках, которая даст вам возможность решиться на самостоятельную разработку качественных приложений.

Яндекс Метрика – сервис, который позволяет анализировать конверсию и выручку сайта, эффективность рекламы, аудиторию сайта и поведение посетителей.

22 июня 2015 года интерфейс Яндекс Метрики кардинально изменился.

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

Книга-инструкция по НОВОЙ ЯндексМетрике понятным даже непрофессионалу языком рассказывает, как пользоваться Метрикой с выгодой для бизнеса.

Здесь рассматривается два варианта ISP программатора на основе Arduino: Mega-ISP, который может быть собран из любой версии Arduino и его клонов, и Bit-Bang программатор, для которого подойдут только те варианты Arduino, которые имеют дополнительно выведенные на специальный разъем контакты микросхемы FT232RL.

Qt предоставляет ряд алгоритмов на основе шаблона, которые реализуют самые полезные алгоритмы STL, начиная с версии 2. В этой статье, мы рассмотрим некоторые из алгоритмов, предлагаемых в Qt 4 .

Qt предоставляет собственные алгоритмы потому, что некоторые платформы (например, embedded Linux) не предоставляет реализацию STL. Алгоритмы используются внутри Qt и доступны его пользователям.

Возможно смешивание реализаций STL и Qt контейнеров и алгоритмов. Например, вы можете использовать алгоритм std::find() для QList

Unified system for program documentation. Indexing of programs and program documents

Разработка программ зачастую напоминает священный ритуал, построенный на произнесении ряда обязательных магических заклинаний. Особенно это касается Windows приложений. Windows-заклинания позволяют вывести графическое окно, обработать поступающие сообщения. Порядок их следования предопределен священными руководствами. Часто эти руководства заменяются шпаргалкой, кратко фиксирующей основной каркас:

// Каркасное приложение Windows 95

Подобная проблема возникает при создании инсталляторов и деинсталляторов. Наиболее простой и гибкий путь — использование DDE. При этом посылаются запросы к PROGMAN. Для этого необходимо поместить на форму компонент для посылки DDE запросов — объект типа TDdeClientConv. Для определенности назовем его DDEClient. Затем добавим метод для запросов к PROGMAN:

var macrocmd:array[0..88] of char;

Данное учебное пособие подготовлено на основе курса лекций по дисциплине «Нейроинформатика», читавшегося с 1994 года на факультете Информатики и вычислительной техники Красноярского государственного технического университета.

Несколько слов о структуре пособия. Далее во введении приведены учебный план по данному курсу, задания на лабораторные работы. Следующие главы содержат одну или несколько лекций. Материал, приведенный в главах, несколько шире того, что обычно дается на лекциях. В приложения вынесены описания программ, используемых в данном курсе (Clab и Нейроучебник), и проект стандарта нейрокомпьютера, включающий в себя два уровня — уровень запросов компонентов универсального нейрокомпьютера и уровень языков описания отдельных компонентов нейрокомпьютера.

Данное пособие является электронным и включает в себя программы, необходимые для выполнения лабораторных работ.

Пишем драйвер wdm на ассемблере

Признаюсь честно: мне нравится Ассемблер. Вернее, даже не сам Ассемблер, а стиль общения с компьютером через него.

В сети есть несколько примеров создания драйверов виртуальных устройств VxD на Ассемблере.

Но нет ни одного аналогичного примера для драйвера WDM.

Так исправим же эту досадную оплошность!

Создание несложного драйвера с использованием только лишь Ассемблера – довольно трудоёмкое занятие.

По двум причинам:

1) Отсутствие ассемблерных заголовочных файлов для использования драйверного API.

2) Методически трудная отладка драйверов в системе Windows.

Первая причина может быть некритичной. Были бы руки да голова. Ведь известно, что значительная часть заголовков Win32 API была переведена энтузиастами на Ассемблер. И работа эта немалая.

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

Все права на текст принадлежат автору: .
Это короткий фрагмент для ознакомления с книгой.

Пишем драйвер wdm на ассемблере

Размер шрифта:
14 | 16 | 18 | 20 | 22 | 24

Цвет текста:
Установить
Цвет фона:
Установить

Часть 1. Цель работы. Постановка задачи.

Часть 2. API для WDM драйвера.

Часть 3. Пишем рыбу.

3.1. Итак, приступим.

3.2. Процедура инициализации

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

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

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

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

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

3.3.8.2. Драйвер GDTDump

Программа, работающая с драйвером, написана — теперь осталось написать сам драйвер. Вообще-то на практике всё делается наоборот: сначала драйвер, потом программа; тем не менее такой порядок изложения материала будет более понятен начинающим.

Далее в листинге 3.21 приведён полный исходный код драйвера GDTDump.

Листинг 3.21. Драйвер GDTDump

format РЕ Native 4.0

include ‘win32w.inc’ include ‘DDKXntstatus.inc’ include ‘DDKXntdefs.inc 1 include ‘DDKXntddk.inc’ include ‘DDKXmacros.inc’ include ‘DDKXadvmacro.inc’

entry DriverEntry section ‘.code’ code readable writeable executable

IOCTL_DEFINE_EX IOCTL_DUMP_GDT, FILE_ANY_ACCESS, 1, METHOD_BUFFERED

UNICODE_STRING_define DeviceName, «DevicedevGDTDump» UNICODE_STRING_define SymbolicLinkName, «??GDTDump”

DeviceObject dd 0

proc DispatchControl pDeviceObject, plrp

push edi push esi push ecx push edx

mov [status], STATUS_DEVICE_CONFIGURATION_ERROR

mov edi, [plrp] virtual at edi .edi IRP end virtual

mov esi, [.edi.Tail.Overlay.CurrentStackLocation] virtual at esi .esi IO_STACK_LOCATION end virtual

cmp [.esi.Parameters.DeviceloControl.IoControlCode], IOCTL_DUMP_GDT jz .IOCTL_DUMP jmp .next .IOCTL_DUMP:

sgdt fword [GDTR]

mov cx, [GDTR.Limit]

inc ecx ; ecx = GDT size xor eax, eax

mov edx, [.esi.Parameters.DeviceloControl.InputBufferLength] cmp edx, 8 jnz .copydata

mov eax, [.edi.Associatedlrp.SystemBuffer] mov edx, [eax+4] ; edx = needed data size mov eax, [eax] ; eax = start offset in GDT

add edx, eax cmp edx, ecx jna @f

sub edx, eax ; edx = fact data size cmp edx, 7FFFFFFFh jna @f mov edx, 0

mov [status], STATUS_BUFFER_TOO_SMALL

cmp ecx, [.esi.Parameters.DeviceloControl.OutputBufferLength] ja .error

mov esi, [GDTR.Address]

mov edx, edi ; save EDI in EDX

Илон Маск рекомендует:  Тег script

mov edi, [.edi.Associatedlrp.SystemBuffer]

mov edi , edx ; restore EDI

mov [status], STATUS_SUCCESS jmp .exit

mov [.edi.IoStatus.Information], 0 jmp .exit

fastcall IofCompleteRequest, edi, IO_NO_INCREMENT mov eax, [status]

pop edx pop ecx pop esi pop edi ret

proc DispatchCreate pDeviceObject, plrp

mov eax, [plrp] virtual at eax .eax IRP end virtual

mov [.eax.IoStatus.Status], STATUS_SUCCESS and [.eax.IoStatus.Information], 0

mov edx, IO_NO_INCREMENT

mov eax, STATUS_SUCCESS ret

proc DispatchClose pDeviceObject, plrp

mov eax, [plrp] virtual at eax .eax IRP end virtual

mov [.eax.IoStatus.Status], STATUS_SUCCESS and [.eax.IoStatus.Information], 0

mov edx, IO_NO_INCREMENT

mov eax, STATUS_SUCCESS ret

proc DriverUnloadHandler pDriverObject

invoke IoDeleteSymbolicLink, SymbolicLinkName invoke IoDeleteDevice, [DeviceObject] ret endp proc DriverEntry pDriverObject, pusRegistryPath local status?DWORD

mov [status], STATUSJDEVICE_CONFIGURATION_ERROR

invoke IoCreateDevice, [pDriverObject], 0, DeviceName, FILE_DEVICE. UNKNOWN, 0, FALSE, DeviceObject

cmp eax, STATUS_SUCCESS jnz .END

invoke IoCreateSymbolicLink, SyrabolicLinkName, DeviceName

cmp eax, STATUS_SUCCESS

mov eax, [pDriverObject]

virtual at eax .eax DRIVER_OBJECT end virtual

mov [.eax.MajorFunction+IRP_MJ_CREATE*4], DispatchCreate

mov [.eax.MajorFunction+IRP_MJ_CLOSE*4], DispatchClose

mov [.eax.MajorFunction+IRP_MJ_DEVICE_CONTROL*4], DispatchControl

mov [.eax.DriverUnload], DriverUnloadHandler

mov [status], STATUS_SUCCESS jmp .END .simlinkfail:

invoke IoDeleteDevice, [DeviceObject]

mov eax, [status] ret

section ‘.relocs’ fixups readable writeable discardable section ‘.idata’ import readable writeable library ntoskrnl,’ntoskrnl.exe’ import ntoskrnl,

Начнём сначала — с функции DriverEntry. В начале её выполнения создаётся объект-устройство при ПОМОЩИ функции IoCreateDevi.ee. Функция IoCreateDevi.ce принимает семь параметров:

  • 1. Указатель на объект-драйвер, созданный системой (pdriver_object).
  • 2. Произвольный размер области дополнительной памяти устройства (device extension), которую можно выделить в каждом объекте устройство (dword).
  • 3. Имя устройства (punicode_string).
  • 4. Уникальный идентификатор типа устройства (dword).
  • 5. Дополнительная информация об устройстве (dword).
  • 6. Возможность монопольного доступа к устройству (bool).
  • 7. Указатель на переменную, в которую будет сохранён указатель на созданный объект-устройство.

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

Уникальный идентификатор типа устройства необходим для того, чтобы система «знала» тип созданного устройства. Мы не будем ничего придумывать и поставим file_device_unknown, т. е. «неизвестный тип».

Шестой параметр нужен для указания дополнительных характеристик устройства; в нашем случае в этом нет необходимости.

После создания объекта-устройства необходимо создать символьную ссылку на него, чтобы код третьего кольца смог получить к нему доступ. Осуществляет данное действие функция loCreateSymbolicLink. Функция принимает два параметра: имя символьной ссылки и имя устройства.

Следует заметить, что для объявления структур unicode_string был использован специальный макрос UNICODE_STRING_define — он максимально упрощает объявление строк в данном формате.

После создания символьной ссылки происходит заполнение массива Ма j orFunct ion (листинг 3.22).

Листинг 3.22. Заполнение массива MajorFunction

mov еах, [pDriverObject]

virtual at еах .eax DRIVER_OBJECT end virtual

mov [.eax.MajorFunction+IRP_MJ_CREATE*4], DispatchCreate

mov [.eax.MajorFunction+IRP_MJ_CL0SE*4], DispatchClose

mov [.eax.DriverUnload], DriverUnloadHandler

Сначала указатель на объект-драйвер заносится в регистр ЕЛХ. После чего с помощью директивы virtual мы говорим компилятору, что регистр ЕЛХ указывает на структуру driver_object. Структура driver_object содержит массив указателей MajorFunction, каждый элемент в котором содержит указатель на функцию- обработчик разных типов пакетов запроса ввода-вывода. Каждый элемент этого массива соответствует своему типу IRP. Если, например, драйверу необходимо обрабатывать запрос типа irp_mj_shutdown, уведомляющий о завершении работы системы, то он должен поместить в соответствующую позицию массива MajorFunction указатель на функцию, которой запросы этого типа и будут направляться. Если такая функциональность драйверу не нужна, как в нашем случае, то и заполнять этот элемент массива MajorFunction не требуется. Мы совсем не обязаны заполнять все элементы массива MajorFunction, коих в DDK определено целых 28 штук (irp_mj_ maximum.function + 1). Все зависит от задач, стоящих перед драйвером. В элементы массива MajorFunction, не заполненные драйвером, диспетчер ввода-вывода заносит указатель на внутреннюю функцию IopInvalidDeviceRequest. Эта функция уведомляет о попытке обращения к неподдерживаемой данным драйвером функции. В нашем случае происходит заполнение только тех элементов массива, которые обеспечивают успешный вызов функций CreateFile, DeviceloControl И CloseHandle кодом режима пользователя.

В ntddk.inc среди прочих определены константы, представляющие для нас интерес, а именно:

IRP_MJ_CREATE equ О

IRP_MJ_CLOSE equ 2

IRP_MJ_READ equ 3

IRP_MJ_WRITE equ 4

IRP_MJ_DEVICE_CONTROL equ OEh

IRP_MJ_CLEA№JP equ 12h

Это порядковые номера, определяющие положение указателя на процедуру диспетчеризации в массиве MajorFunction. Умножив соответствующую константу на размер указателя, равный 4 байтам, мы получим смещение в массиве MajorFunction, по которому должен быть расположен указатель на соответствующую процедуру- обработчик.

Теперь следует сказать несколько слов по поводу обработчиков запросов. Как и любые функции обратного вызова (т. е. те функции, которые вызываются самой системой), они должны отвечать соглашению передачи параметров stdcall. Все они принимают два параметра: первый параметр — указатель на объект-устройство, второй — указатель на структуру IRP, которая представляет запрос ввода-вывода.

Еще одно ключевое поле структуры driver_object — это поле DriverUnload. Туда мы должны поместить (если хотим иметь возможность динамически выгружать драйвер) указатель на процедуру, которую система будет вызывать при обращении кода режима пользователя к функции Controlservice с параметром service_ CONTROL.STOP.

Если всё прошло успешно, необходимо возвратить системе код успеха status. SUCCESS.

Следующий шаг — это обработчики запросов 1КР_мл_снеате и 1ЕР_мл_сь0оЕ. Эти запросы генерируются при вызове кодом третьего кольца функций СгеаЬеШе и С1о5еНапс11е (или мьСгеаСеЕИе и ысс1оБе в нулевом кольце). В обработчике запроса Iкр_ю_сееате драйвер должен подготавливать данные для дальнейшей работы с устройством; соответственно, в обработчике запроса 1 РР_мд_сьозе драйвер должен производить действия, противоположные действиям в обработчике 1 ЕР_мл_снеате. Обработчиками этих запросов являются функции оРзрассЬСгеаье и ОРзратсЬСХоБе; их код полностью идентичный (листинг 3.23).

Листинг 3.23. Функция обработки запроса IRP_MJ_CREATE

proc DispatchCreate pDeviceObject, plrp

mov eax, [plrp] virtual at eax .eax IRP end virtual

mov [.eax.IoStatus.Status], STATUS_SUCCESS and [.eax.IoStatus.Information], 0

mov edx, IO_NO_INCREMENT

mov eax, STATUS_SUCCESS ret

Оба обработчика почти ничего не делают. Они всего лишь возвращают код успеха и уведомляют диспетчер ввода-вывода об успехе.

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

Если драйвер обслуживает физическое устройство, то операция ввода-вывода может длиться ощутимое время. При синхронных операциях ввода-вывода, как в нашем случае, пока поток ждет завершения операции, система не предоставляет ему процессорное время. По окончании операции ожидавший поток вправе немедленно возобновить выполнение и обработать полученные данные. Именно через второй параметр функции IofCompleteRequest драйвер и сообщает системе, на какую величину повысить приоритет ожидавшего потока. В нашем примере повышения приоритета потока не требуется, и мы передаем константу io_no_increment равную нулю.

Функция IofCompleteRequest является (ахСсаП-фунюшей. В префиксе имени функции присутствует символ I. Существует, кстати сказать, и хГс1са11-вариант — 1оСотр1еСеКедиезс (обратите внимание на отсутствие символа i в префиксе). Но, в образовательных целях мы будем использовать быструю версию. Эта не единственная (а81са11-функция — есть и другие. У них также есть свои яГбсаП-аналоги, которые, как правило, просто вызывают свои (ая^аН-аналоги.

Функции, отвечающие соглашению (авФаИ, принимают первый аргумент в регистре ЕСХ, второй — в ЕОХ; остальные аргументы, при наличии таковых, помещаются в стек в обратном порядке (справа налево, как .яГскаП). Стек очищает вызванная функция.

В коде функций С1БраСсЬСгеаЕе И Пд.зраисЬС1озе ВЫЗОВ функции 1о?Сотр1еСеКе irp_mj_device_control (листинг 3.25).

Листинг 3.25. Функция-обработчик запроса IRP_MJ_DEVICE_CONTROL

proc DispatchControl pDeviceObject, plrp

emp [.esi.Parameters.DeviceloControl.IoControlCode], IOCTL_DUMP_GDT jz .IOCTL_DUMP jmp .next .IOCTL_DUMP: sgdt fword [GDTR] xor ecx, ecx mov cx, [GDTR.Limit] inc ecx ; ecx = GDT size

xor eax, eax mov edx, [.esi.Parameters.DeviceloControl.InputBufferLength] cmp edx, 8 jnz .copydata

mov eax, [.edi.Associatedlrp.SystemBuffer] mov edx, [eax+4] ; edx = needed data size mov eax, [eax] ; eax = start offset in GDT

add edx, eax cmp edx, ecx jna @f

sub edx, eax ; edx = fact data size cmp edx, 7FFFFFFFh jna @f mov edx, 0

mov [status], STATUS_BUFFER_TOO_SMALL

cmp ecx, [.esi.Parameters.DeviceloControl.OutputBufferLength] ja .error

mov esi, [GDTR.Address]

mov edx, edi ; save EDI in EDX

mov edi, [.edi.Associatedlrp.SystemBuffer]

mov edi, edx ; restore EDI pop [.edi.IoStatus.Information] mov [status], STATUS.SUCCESS push [status]

fastcall IofCompleteRequest, edi, IO_NO_INCREMENT mov eax, [status]

При получении управляющего кода ioctl_dump_gdt происходит прыжок на метку .ioctl_dump, за которым следуют обработка входных данных и передача необходимого участка GDT пользовательскому процессу.

Если размер входного буфера не равен 8, то пользовательскому процессу передаётся вся глобальная дескрипторная таблица. Если же во входном буфере переданы данные, то они интерпретируются следующим образом: первое DWORD- значение задаёт смещение, начиная с которого будут копироваться данные, а второе DWORD-значение — размер копируемых данных. После извлечения входных данных производится их проверка, и в итоге при подходе к метке . copydata в обоих случаях в регистре ЕЛХ присутствует смещение, начиная с которого будут копироваться данные, а в регистре ЕСХ указано количество байтов для копирования.

После выполнения всех операций и занесения в выходной буфер ответа на запрос необходимо занести в поле irp. IoStatus. information число байтов, реально скопированных в системный буфер, чтобы диспетчер ввода-вывода «знал», сколько байтов копировать в пользовательский выходной буфер. Также необходимо занести в поле irp.IoStatus.status результат обработчика запроса. Если результат равен status_success, то диспетчер ввода-вывода скопирует данные из системного буфера в пользовательский выходной буфер; в любом другом случае функция DeviceioControl возвратит ошибку выполнения.

Илон Маск рекомендует:  Очистка поля ввода от значения по умолчанию

После обработки запроса необходимо уведомить диспетчер ввода-вывода о том, что операция ввода-вывода завершена и можно отправлять её результаты инициатору запроса. Для этого надо вызвать функцию iofCompleteRequest; в нашем примере вызов функции произведен при помощи макроса, который приводился выше при рассмотрении функций DispatchCreate И DispatchClose.

Последняя функция, которую МЫ ещё не рассмотрели, — DriverUnloadHandler. Её задача минимальна: освободить все данные и структуры, которые были созданы в функции DriverEntry либо во время работы драйвера. В нашем случае происходит удаление объекта-устройства и символьной ссылки на него.

В пакете FASM (который находится на компакт-диске, прилагающемся к книге) в папке INCLUDE находятся все заголовочные файлы, используемые программой управления драйвером и самим драйвером (папка INCLUDEDDK).

Пишем драйвер Windows на ассемблере

Автор не указан

Часть 1. Цель работы. Постановка задачи.

Ad Content

Признаюсь честно: мне нравится Ассемблер. Вернее, даже не сам Ассемблер, а стиль общения с компьютером через него.

В сети есть несколько примеров создания драйверов виртуальных устройств VxD на Ассемблере.

Но нет ни одного аналогичного примера для драйвера WDM.

Так исправим же эту досадную оплошность!

Создание несложного драйвера с использованием только лишь Ассемблера – довольно трудоёмкое занятие.

По двум причинам:

1) Отсутствие ассемблерных заголовочных файлов для использования драйверного API.

2) Методически трудная отладка драйверов в системе Windows.

Первая причина может быть некритичной. Были бы руки да голова. Ведь известно, что значительная часть заголовков Win32 API была переведена энтузиастами на Ассемблер. И работа эта немалая.

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

Однако, теперь у вас будет хороший кусок работающего кода. Мы его сейчас напишем! Изменяя и дополняя его, вы сможете создать свой собственный драйвер, довольно быстро и легко.

Сразу оговорюсь: я не собираюсь подробно объяснять принципы функционирования драйверной системы Windows и растолковывать специальные понятия. Для этого существует специальная литература.

Что нам потребуется? Вот что:

1) Текстовый редактор.

Notepad. Но лучше что-нибудь поудобнее, например, Патриот XP.

2) MS Windows DDK.

DDK содержит почти всё, что требуется для создания драйверов. Но нам важны: справка DDK, Ассемблер masm 6.1, компоновщик Link, также оттуда мы возьмём библиотеки и заголовочные файлы для C (что с ними делать – см. далее).

3) Утилита для визуализации отладочного вывода. Я использую DbgView , который можно взять с сайта www.sysinternals.com

4) Delphi для компиляции тестовой программы.

Но вам необязательно набирать текст с нуля. К счастью, я сделал это до вас :)

Скачайте файл с исходниками проекта AsmDrv и распакуйте его в подкаталог \NTDDK\src\AsmDrv.

masm64 написание драйверов

masm32 поддерживает написание драйверов. Имеет ли эту возможность masm64?

Знаете кого-то, кто может ответить? Поделитесь ссылкой на этот вопрос по почте, через Твиттер или Facebook.

Посмотрите другие вопросы с метками ассемблер или задайте свой вопрос.

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2020 Stack Exchange Inc; пользовательское содержимое попадает под действие лицензии cc by-sa 4.0 с указанием ссылки на источник. rev 2020.11.12.35408

Пишем драйвер Windows на ассемблере

HonoratoBonafe

Пишем драйвер WDM на Ассемблере.

(Комментарии к исходникам AsmDrv)

Часть 1. Цель работы. Постановка задачи.

Признаюсь честно: мне нравится Ассемблер. Вернее, даже не сам Ассемблер, а стиль общения с компьютером через него.

В сети есть несколько примеров создания драйверов виртуальных устройств VxD на Ассемблере.

Но нет ни одного аналогичного примера для драйвера WDM.

Так исправим же эту досадную оплошность!

Создание несложного драйвера с использованием только лишь Ассемблера – довольно трудоёмкое занятие.

По двум причинам:

1) Отсутствие ассемблерных заголовочных файлов для использования драйверного API.

2) Методически трудная отладка драйверов в системе Windows.

Первая причина может быть некритичной. Были бы руки да голова. Ведь известно, что значительная часть заголовков Win32 API была переведена энтузиастами на Ассемблер. И работа эта немалая.

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

Однако, теперь у вас будет хороший кусок работающего кода. Мы его сейчас напишем! Изменяя и дополняя его, вы сможете создать свой собственный драйвер, довольно быстро и легко.

Сразу оговорюсь: я не собираюсь подробно объяснять принципы функционирования драйверной системы Windows и растолковывать специальные понятия. Для этого существует специальная литература.

Что нам потребуется? Вот что:

1) Текстовый редактор.

Notepad. Но лучше что-нибудь поудобнее, например, Патриот XP.

2) MS Windows DDK.

DDK содержит почти всё, что требуется для создания драйверов. Но нам важны: справка DDK, Ассемблер masm 6.1, компоновщик Link, также оттуда мы возьмём библиотеки и заголовочные файлы для C (что с ними делать – см. далее).

3) Утилита для визуализации отладочного вывода. Я использую DbgView , который можно взять с сайта www.sysinternals.com

4) Delphi для компиляции тестовой программы.

Но вам необязательно набирать текст с нуля. К счастью, я сделал это до вас :)

Скачайте файл с исходниками проекта AsmDrv и распакуйте его в подкаталог \NTDDK\src\AsmDrv.

Вот, кажется, всё. Можно начинать!

Часть 2. API для WDM драйвера.

Большинство функций драйверного API, которые нас интересуют, предоставляются модулем ntoskrnl.exe.

Для их использования надо сделать следующее:

1) Объявить типы данных и определить константы.

Большинство определений для C находятся в файлах ntdef.h и wdm.h.

2) Объявить прототипы функций, которые мы намерены использовать.

Эти определения для C также находятся в wdm.h

3) Выполнить сборку драйвера с подключением библиотеки wdm.lib

Все три файла (wdm.h, ntdef.h и wdm.lib) входят в состав Windows DDK.

Я перевёл часть заголовков на Ассемблер и поместил их в файл usewdm.inc, который находится в базовом каталоге проекта.

Часть 3. Пишем рыбу.

3.1. Итак, приступим.

Вы можете проследить за последовательностью и содержанием действий, открыв файл main.asm для просмотра.

Начнём, пожалуй, так:

.586p ; Процессор Intel Pentium, разрешены инструкции защищённого режима

.model flat, stdcall ; Здесь всё ясно. Плоская модель адресации и тип вызовов stdcall.

option casemap:none ; «case-sensitive»

Дальше нужно задействовать файл включений usewdm.inc и библиотеку wdm.lib, чтобы мы смогли использовать драйверный API:

Затем размещаем два сегмента – данных и кода:

3.2. Процедура инициализации

Каждый драйвер имеет процедуру инициализации . Эта процедура вызывается системой сразу после загрузки драйвера в память.

У нас такая процедура называется DriverEntry. Объявим её как

Driver Entry proc near public, DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING

DriverObject – это указатель на служебную структуру, сопоставленную драйверу. Она используется системой для вызова процедур драйвера. Её-то и следует инициализировать – записать в эту структуру адреса соответствующих процедур нашего драйвера.

Наш драйвер довольно прост. Он будет отрабатывать только 4 стандартных запроса:

IRP_MJ_CREATE – Вызов CreateFile() в приложении пользователя для установления связи с драйвером;

IRP_MJ_CLOSE – Вызов CloseHandle() в приложении пользователя для разрыва связи с драйвером;

IRP_MJ_DEVICE_CONTROL – Вызов DeviceIoControl() в приложении пользователя для запроса выполнения какой-либо функции в драйвере.

Все эти три запроса мы адресуем некоей диспетчерской функции OnDispatch. Мы узнаем о ней позже.

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

А пока необходимо сделать ещё 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 ; Проверим, не было ли ошибки.

; Создаём symbolic link

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

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

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):

Илон Маск рекомендует:  Что такое код swf_shapelinesolid

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

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:

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

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

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

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

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

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

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

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

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

Windows 98 на этом месте может попросить перезагрузки. Не отказывайте ей :)

Windows 2000/XP запускает драйвер сразу.

Вы можете проконтролировать установку, убедившись в наличии устройства «Простейший WDM драйвер на Ассемблере» в списке менеджера устройств.

Поздравляю, если вы всё сделали правильно, наш драйвер – о, чудо! – работает.

Часть 7. Тестовая программа.

Проект тестовой программы расположен в подкаталоге TestApp.

Откройте его в Delphi и перекомпилируйте.

В результате вы получите файл AsmDrvTest.exe, который нужно будет запустить.

В принципе, это одна из самых простых программ в мире. Она занимается отправкой драйверу AsmDrv.sys запросов IOCTL_USER_REQUEST_1 и _2по требованию пользователя, передавая драйверу строку символов.

Работу этой программы рекомендуется изучить самостоятельно.

Одновременно с тестовой программой используйте утилиту DbgView для просмотра отладочного вывода.

Часть 8. Напоследок.

Мы убедились ещё раз, что не боги горшки обжигают.

Следует ли писать драйверы WDM на ассемблере? –

Зависит от желания и возможностей.

Однако вопрос оставлю открытым.

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

BReader.ru

» Пишем драйвер Windows на ассемблере —

Большинство книг в нашей библиотеке хранится в формате FB2 (FictionBook). Этот формат отличается от других малым весом и возможностью форматирования текста. Также FB2 может содержать изображения и обложку, что делает его самым распространенным форматом книг. Но этот формат имеет один недостаток — книги в FB2 нельзя открыть обычным блокнотом, нужна специальная программа.

Чем читать? (программы для чтения):
» Скачать HaaliReader — программа для чтения FB2 для Windows.
» Скачать ICE Book Reader Professional — программа под Windows для чтения электронных книг.

Пишем драйвер wdm на ассемблере

В далекие студенческие годы, «карпея» над лекциями по радиолокации и чередуя это действо с попытками сдать курсовую по радиопередающим устройствам, я очень серьезно загорелся тематикой управления внешними радиоэлектронным устройствами с помощью компьютера. Первые опыты с LPT портом под ОС Windows Millennium повергли меня в настоящий восторг, и с тех пор это направление стало не только моим хобби, но и работой. В 2005 году на чистом энтузиазме я начал вести проект в сети Интернет под названием www.pcports.ru в котором в виде статей я пытался рассказать и объяснить что же это такое “сопряжение компьютеров с внешними устройствами” и как «это» можно попробовать на практике.

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

Программирование LPT порта

Е сли Вы решили заниматься изготовлением и программированием устройств сопряжения с компьютером, то Вам следует начать именно с этого порта — LPT. Его использование относительно простое и даже не имея специальных знаний можно в короткие строки сделать собственное устройство подключаемое к порту LPT, управлять им из программы.

Справочник программиста на персональном компьютере фирмы IBM. Ввод/вывод
Страница 16. Создание драйвера устройства

Раздел 2. Создание драйвера устройства.

Драйвер устройства это специальная программа, которая управ-
ляет обменом с периферийным устройством, таким как принтер или
дисковый накопитель. Поскольку параметры этих периферийных уст-
ройств меняются от производителя к производителю, то разным поль-
зователям программы может потребоваться дюжина различных драйве-
ров, чтобы он мог работать на имеющемся у него оборудовании.
Имеется 4 способа включения драйверов устройств в программу:

1. Можно поместить код для всех драйверов прямо в программу.
Например, чтобы поддерживать различные принтеры, можно создать
таблицу управляющих последовательностей и искать в ней нужный код
каждый раз когда он потребуется. Этот подход тратит много памяти
и может быть достаточно медленным.

2. Создать ряд драйверов устройств и потребовать, чтобы прог-
рамма загружала необходимый в качестве оверлея (т.е. помещать его
в область программы, специально оставленную для этой цели
[1.3.5]).

3. Создать драйвер устройства как отдельную программу, которая
указывается в командном файле, выполняемом при загрузке системы.
Программа запускается и устанавливает драйвер устройства как
программу обработки прерывания. После этого программа завершает-
ся, но остается резидентной в памяти, как объяснено в [1.3.4].
Впоследствии наша программа использует этот драйвер через вектор
прерывания.

4. Создать полноценный драйвер устройства, который будет заг-
ружаться при старте с помощью файла CONFIG.SYS. MS DOS поддержи-
вает такой тип драйверов устройств и однажды загруженный он может
использовать все возможности команд DOS, включая проверку ошибок.
Специальная команда IOCTL (Контроль ввода/вывода) позволяет прог-
рамме узнать статус драйвера и послать ему управляющую строку,
помимо обычного потока данных.

Первые три стратегии легко реализуются с помощью информации,
приведенной в остальных частях данной книги. Но устанавливаемые
драйверы устройств очень сложны. Зато когда он есть, то он очень
мощен. В этом случае система будет работать с устройством нас-
только же тесно, как с клавиатурой или дисковым накопителем.
Устройству может быть присвоено имя, например, SERIALPR для пос-
ледовательного принтера, и затем это устройство может быть откры-
то для доступа из любого языка. В Бейсике оператор OPEN «SE-
RIALPR» FOR OUTPUT AS #2 подготовит последовательный принтер для
вывода. В языке ассемблера Вы сможете получить доступ к принтеру
как с помощью метода управляющего блока файла, так и с помощью
метода дескриптора файла, включая очень мощную функцию IOCTL. При
этом пользователь имеет возможность доступа к устройству на уров-
не операционной системы и может просто ввести команду COPY A:MY-
FILE SERIALPR:, чтобы скопировать содержимое файла на принтер.
Устанавливаемые драйверы устройств могут быть написаны только
на языке ассемблера. Они могут обслуживать два типа устройств:
символьные и блочные. Эти имена описывают единицы, которыми уст-

ройство обрабатывает данные. Обычно драйверы блочных устройств
обслуживают дисковые накопители, а драйверы символьных — все
остальное, начиная от последовательных принтеров и кончая робота-
ми. Блочные устройства обмениваются блоками данных, поэтому они
занимаются накоплением данных. Символьные устройства обмениваются
данными побайтно, поэтому они лучше подходят для управляющих
устройств, а также для устройств, которые не могут обеспечить
высокую скорость обмена данными. Драйверы блочных устройств очень
сложны и здесь нет достаточно места, чтобы объяснить их структу-
ру. Очень редко кому требуется написать такой драйвер. Техничес-
кое руководство по MS DOS предоставляет всю необходимую информа-
цию и содержит полный пример драйвера виртуального диска в опера-
тивной памяти. Вы можете просмотреть эту информацию после того
как изучите обсуждение драйверов символьных устройств, приведен-
ное здесь.
Устанавливаемые драйверы устройств беспощадны к программистс-
ким ошибкам. Поскольку драйверы автоматически загружаются систе-
мой при загрузке, то невозможно использовать отладчики для выяв-
ления причин неполадок. Поэтому будьте предельно внимательны при
их написании.
Программа драйвера устройства разбивается на три части, каждая
из которых обсуждается отдельно в следующих разделах. Это (1)
заголовок драйвера, который именует устройство и содержит инфор-
мацию об остальных частях драйвера, (2) стратегия драйвера, кото-
рая хранит информацию об области данных, создаваемой MS DOS,
которая называетя заголовком запроса, и (3) обработчик прерывания
устройства, который и содержит код, управляющий устройством.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL