Assembler Драйвер Wasm Через Загрузчик

На самые популярные файлы, мы сделали отдельную рубрику под названием «Загрузки». В статье 'Как написать простейший драйвер' есть строка 'через динамический загрузчик Свена.
Программы для загрузки файлов В данном разделе представлен софт, с которым закачка из Интернета станет намного удобнее. Установите торрент-клиент, интегрируемый в браузер плагин или отдельное приложение-загрузчик - и вы получите немало упрощающих работу возможностей. Восстановление закачивания после разрыва Интернет-соединения, расстановка приоритетов и управление скоростью - далеко не весь их перечень.
А чтобы скачать программу для загрузки файлов, хватит одного клика. Однако прежде рекомендуем прочитать обзоры и сравнить функционал похожих программ. Ведь даже аналогичные, на первый взгляд, продукты, предназначены для разных классов юзеров.
Jstrap@yandex.ru Источник: Краткое содержание. Цель работы.
Постановка задачи. API для WDM драйвера.
Пишем рыбу. Детализация. Компиляция и сборка.
Как правильно установить драйвер. Тестовая программа. Напоследок.
Постановка задачи. Признаюсь честно: мне нравится Ассемблер. Вернее, даже не сам Ассемблер, а стиль общения с компьютером через него.
В сети есть несколько примеров создания драйверов виртуальных устройств VxD на Ассемблере. Но нет ни одного аналогичного примера для драйвера WDM. Так исправим же эту досадную оплошность! Создание несложного драйвера с использованием только лишь Ассемблера - довольно трудоёмкое занятие.
Assembler Драйвер Wasm Через Загрузчика
По двум причинам:. Отсутствие ассемблерных заголовочных файлов для использования драйверного API. Методически трудная отладка драйверов в системе Windows. Первая причина может быть некритичной. Были бы руки да голова. Ведь известно, что значительная часть заголовков Win32 API была переведена энтузиастами на Ассемблер.
И работа эта немалая. Вторая причина более серьёзна и именно она является сдерживающей. Практически, самым доступным способом отладки является отладочный вывод из самого драйвера. При этом код осторожно дописывается небольшими кусочками.
Однако, теперь у вас будет хороший кусок работающего кода. Мы его сейчас напишем! Изменяя и дополняя его, вы сможете создать свой собственный драйвер, довольно быстро и легко. Сразу оговорюсь: я не собираюсь подробно объяснять принципы функционирования драйверной системы Windows и растолковывать специальные понятия.
Для этого существует специальная литература. Что нам потребуется? Вот что: 1) Текстовый редактор. Но лучше что-нибудь поудобнее, например, Патриот XP. 2) MS Windows DDK. DDK содержит почти всё, что требуется для создания драйверов. Но нам важны: справка DDK, Ассемблер MASM 6.1, компоновщик Link, также оттуда мы возьмём библиотеки и заголовочные файлы для C (что с ними делать - см.
3) Утилита для визуализации отладочного вывода. Я использую DbgView, который можно взять с сайта www.sysinternals.com 4) Delphi для компиляции тестовой программы. Но вам необязательно набирать текст с нуля. К счастью, я сделал это до вас:) Скачайте файл с исходниками проекта и распакуйте его в подкаталог NTDDK src AsmDrv.
Вот, кажется, всё. Можно начинать!
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, который находится в базовом каталоге проекта.
Итак, приступим. Вы можете проследить за последовательностью и содержанием действий, открыв файл main.asm для просмотра. Начнём, пожалуй, так:.586p; Процессор Intel Pentium, разрешены инструкции защищённого режима.model flat, stdcall; Здесь всё ясно. Плоская модель адресации и тип вызовов stdcall.
Option casemap:none; 'case-sensitive' Дальше нужно задействовать файл включений usewdm.inc и библиотеку wdm.lib, чтобы мы смогли использовать драйверный API:.include usewdm.inc.includelib wdm.lib Затем размещаем два сегмента - данных и кода:.data;.code;. 3.2. Процедура инициализации Каждый драйвер имеет процедуру инициализации.
Эта процедура вызывается системой сразу после загрузки драйвера в память. У нас такая процедура называется DriverEntry. Объявим её как Driver Entry proc near public, DriverObject:PDRIVEROBJECT, RegistryPath:PUNICODESTRING DriverObject - это указатель на служебную структуру, сопоставленную драйверу. Она используется системой для вызова процедур драйвера. Её-то и следует инициализировать - записать в эту структуру адреса соответствующих процедур нашего драйвера. Наш драйвер довольно прост.
Он будет отрабатывать только 4 стандартных запроса:. IRPMJCREATE - Вызов CreateFile в приложении пользователя для установления связи с драйвером;. IRPMJCLOSE - Вызов CloseHandle в приложении пользователя для разрыва связи с драйвером;. IRPMJDEVICECONTROL - Вызов DeviceIoControl в приложении пользователя для запроса выполнения какой-либо функции в драйвере.
Все эти три запроса мы адресуем некоей диспетчерской функции OnDispatch. Мы узнаем о ней позже. Четвёртый запрос - на выгрузку. Об этом пойдёт речь ниже.
А пока необходимо сделать ещё 2 важные вещи - создать логический объект устройства при помощи функции IoCreateDevice и символическую связь, имя которой пользовательские приложения будут использовать для связи с драйвером при помощи функции CreateFile. Символическая связь создаётся при помощи вызова IoCreateSymbolicLink:; Инициализируем юникодовые строки с именами устройства и линка invoke RtlInitUnicodeString, offset NtDeviceName, offset wsNtDeviceName invoke RtlInitUnicodeString, offset Win32DeviceName, offset wsWin32DeviceName;.; Создаём логический объект устройства invoke IoCreateDevice, DriverObject, 0, offset NtDeviceName,; Проверим, не было ли ошибки.
FILEDEVICEUNKNOWN,0,FALSE,offset DeviceObject; cmp eax,STATUSSUCCESS jnz @F; Создаём symbolic link; в eax останется код результата invoke IoCreateSymbolicLink, offset Win32DeviceName, offset NtDeviceName @@: ret Итак, только что мы завершили разбор процедуры инициализации. Процедура выгрузки. У нас она реализуется функцией OnUnload. Эта функция производит действия, обратные процедуре инициализации по отношению к связанным объектам: она удаляет символическую связь (вызов IoDeleteSymbolicLink), и затем логическое устройство, сопоставленное драйверу (IoDeleteDevice):; Удаляем символическую связь invoke IoDeleteSymbolicLink, offset Win32DeviceName; Удаляем логическое устройство invoke IoDeleteDevice, DeviceObject 3.4.
Главная диспетчерская процедура. Она называется OnDispatch и объявлена как OnDispatch proc near, pDeviceObject:PDEVICEOBJECT, pIrp:PIRP Здесь нам важен указатель на структуру с данными запроса pIrp.
Данная структура довольно сложна. Вы можете найти её объявление в файле usewdm.inc. Но нам понадобятся лишь некоторые данные. Сначала мы должны определить код запроса - он будет один из трёх: IRPMJCREATE, IRPMJCLOSE или IRPMJDEVICECONTROL.
Assembler Драйвер Wasm Через Загрузчику
Мы получаем этот код из структуры IOSTACKLOCATION, указатель на которую мы получаем из структуры IRP (в свою очередь, указатель на IRP был передан нам в пераметре pIrp): mov ebx,pIrp; Восстанавливаем указатель на структуру IOSTACKLOCATION mov eax,(IRP ptr ebx).Tail.Overlay.CurrentStackLocation mov pIrpStack,eax mov ebx,pIrpStack; al - Код сообщения mov al,(IOSTACKLOCATION ptr ebx).MajorFunction Дальше отрабатываем запросы по-разному. Для IRPMJCREATE и IRPMJCLOSE обработка фиктивная.
Мы просто возвращаем код успеха STATUSSUCCESS в регистре eax. Для IRPMJDEVICECONTROL мы должны получить данные о длине входного и выходного буферов приложения пользователя, восстановить указатель на промежуточный системный буфер и адрес переменной, в которую будет записана длина информационного пакета, передаваемого из драйвера приложению пользователя.
Мы размещаем эти данные в локальных переменных, чтобы потом вызвать вторичную функцию DeviceIoControlHandler, где и будет выполнена обработка. Детализация заключается в размещении пользовательского кода во вторичной процедуре обработчика IRPMJDEVICECONTROL. Мы будем отрабатывать 2 запроса:. IOCTLUSERREQUEST1 - отправка переданной строки в отладочный вывод, и. IOCTLUSERREQUEST2 - перевод литер переданной строки в нижний регистр.
Коды запросов объявлены в файле-включении ioctlcodes.inc В принципе, реализация этих вещей довольно проста и не требует комментариев. Компиляция и сборка. Для компиляции программы следует выполнить командный файл assemble.cmd. Его содержимое:.

Bin ml.exe -coff -Fl -c -Foasmdrv.obj main.asm В результате мы получим листинг main.lst и объектный модуль asmdrv.obj. Дальше мы должны собрать бинарник драйвера из объектного модуля. Для этой цели существует команда link.cmd:.
Bin link.exe @linkcmd.rsp в файле linkcmd.rsp размещены настройки линкера. Полный список выглядит так: -MACHINE:IX86 -STACK: -OPT:REF -OPT:ICF -INCREMENTAL:NO -FORCE:MULTIPLE -RELEASE -DEFAULTLIB:wdm.lib -DRIVER -ALIGN:0x20 -SUBSYSTEM:NATIVE -BASE:0x10000 -ENTRY:DriverEntry@8 -OUT:disk1 asmdrv.sys asmdrv.obj В результате сборки мы получаем файл AsmDrv.sys в подкаталоге Disk1. Как правильно установить драйвер. Чтобы установить драйвер в системе, нам потребуется специальный конфигурационный файл, хранящий некоторые дополнительные сведения о драйвере, важные для системы. Это так называемый inf-файл. Опять-таки, к счастью для вас, я уже написал этот файл - asmdrv.inf.
Вы можете открыть его для просмотра и изучить. Файл находится в подкаталоге Disk1 проекта.
Пробуем установиться. Открываем Панель управления, запускаем Мастер установки оборудования и указываем ему путь к файлу asmdrv.inf в режиме ручного выбора. Завершаем установку.
Windows 98 на этом месте может попросить перезагрузки. Не отказывайте ей:) Windows 2000/XP запускает драйвер сразу. Вы можете проконтролировать установку, убедившись в наличии устройства 'Простейший WDM драйвер на Ассемблере' в списке менеджера устройств. Поздравляю, если вы всё сделали правильно, наш драйвер - о, чудо! Тестовая программа. Проект тестовой программы расположен в подкаталоге TestApp.
Откройте его в Delphi и перекомпилируйте. В результате вы получите файл AsmDrvTest.exe, который нужно будет запустить. В принципе, это одна из самых простых программ в мире. Она занимается отправкой драйверу AsmDrv.sys запросов IOCTLUSERREQUEST1 и 2 по требованию пользователя, передавая драйверу строку символов. Работу этой программы рекомендуется изучить самостоятельно. Одновременно с тестовой программой используйте утилиту DbgView для просмотра отладочного вывода. Мы убедились ещё раз, что не боги горшки обжигают.
Следует ли писать драйверы WDM на ассемблере? - Зависит от желания и возможностей.
Однако вопрос оставлю открытым. MS-DOS драйвера разрабатывались только на языке ассемблера.
95 DDK также поддерживал разработку VXD-драйверов на ассемблере. Начиная с Win'98 Microsoft со своим Си-пи-пи и ООП'е развернулись к ассемблеру жо. Видимо новое поколение поцанов в фирме просто-напросто подзабыли как с ним работать. Теперь, чтоб разработать худо-бедно работающий драйвер необходимо с бубном попрыгать вместе с Си, Nume'гой и DDK 2000, например. Можно взять Jungo, но драйвер будет не полноценным и тонкие вещи на нем не наклепаешь. Поэтому увидеть макет WDM-драйвера на ассемблере приятно.
Реально использовать его проблематично, т.к. Для применения драйверного API необходимо собственноручно перелопатить кучу структур из wdm.h и прочих.h в файлы.inc, которые начиная с ddk98 Microsoft не утруждается поддерживать. Кроме всего прочего, придется еще и поработать с DDK'ашным Help'ом от Microsoft. Муки при изучении его полуметровых названий функций и структур настолько невыносимы, что приходиться ежесекундно вспоминать ласковыми словами славную компанию пацанов из Microsoft'а. К моему удивлению, ранее мною легко решенный вопрос выделения блока памяти для ПДП в VXD-драйвере с помощью VMMCall PageAllocate вызвал у меня затруднения в DDK 98.
Аналога в DDK 98 этой функции я не нашел, видимо у пацанов из Microsoft'а в очередной раз произошла ломка, которая сподвигла их на радикальные изменения подходов к системному программированию. Основным моментом в функции PageAllocate для ПДП является получение физического адреса буфера. Help 98 DDK отправил меня к использованию функции AllocateCommonBuffer, которая почему-то оказалась неразрывно связанной с ПДП, а следовательно и с кучей структур: DMAADAPTER, DEVICEOBJECT, DRIVEROBJECT и т.д. Убить время на перевод.h в.inc? Очевидно, реку не повернуть вспять и следует стать СИонистом, взять в руки бубен и начать хороводить.