Password
    
 К титульной странице  |  Форум  |  О проекте  |  Словарь  |  Товары  |  Сделать стартовой  |  В Закладки   
Авторизация
Забыли пароль?
Регистрация 
 
Программирование
Безопасность
Демосцена
Игры
WEB-мастерская
Программное обеспечение
Аппаратное обеспечение



Последние материалы
  The Chronicles of Riddick: Escape from Butcher bay

  Что такое хорошо и что такое плохо, или FAQ по LCD-мониторам

  Организация удаленного доступа

  Инсталляция программного обеспечения используя GPO

  Smarty в веб-разработке

  BioShock или кафе разбитых надежд...



Последние новости
  Латвия подписала АСТА

  Примечательная промо-акция игры STAR WARS: The Old Republic на Times Square в Нью Йорке

  На сайте выложены первые выпуски легендарной телепередачи о компьютерных играх "От винта!"

  На сайте опубликован энциклопедический словарь по информатике Э.Якубайтиса

  Конференция Разработчиков Видеоигр, 1979

  Более шустрый и динамичный Mail.lv



Charitable advertising
Њл ­г¦¤ Ґ¬бп ў ў иҐ© Ї®¬®йЁ!



Ziedot.lv

Penn State Child Life Program



Программирование --> C/C++
Драйвер с нуля
  
Автор: Артём
Источник:www.cybersecurity.ru
Опубликовано: [2005-07-18 00:43]
В один прекрасный день меня попросили написать Драйвер. На тот день мои познания в C/C++ ограничивались программой «Hellow Word» и поэтому, на вопрос: «Напишешь?» я самоуверенно ответил: «Конечно».

На следующий день я узнал, что на свете существуют MSDN и DDK. Вскоре я понял, что не все Windows одинаковые, оказалось, что мой драйвер должен работать «под Win2000/NT». У меня ушло больше месяца на то, чтобы скомпилировать и запустить свой первый Драйвер. По правде сказать, это был не совсем мой Драйвер, а точнее--это был genport из NTDDK. Но радовался я так, как будто минимум написал свою ОС. Недавно мне пришлось опять вернуться к Драйверу. И вот вчера я, наконец-то, сдал работающий драйвер и решил написать эту небольшую статью, для того чтобы как-то систематизировать то, что я узнал и, чтобы когда мне снова придется взяться за драйвер, было от чего отталкиваться.

Люди знающие что такое IOCTL, DEVICE_EXTENSION, MajorFunction и DriverEntry не найдут здесь ничего нового. Эта статья для тех, кто возможно никогда не слышал слово ДДК, и кто до сего дня никогда не заглядывал в исходники драйверов. И еще, я буду довольно-таки подробно описывать многие, даже очевидные вещи, поэтому напомню о том, что данная статья рассчитана на людей с очень малым опытом программирования, какой был у меня, когда я занялся написанием драйверов.

Ссылки:
Первое с чем сталкивается программист, решивший заняться драйверами это почти полное отсутствие русскоязычной литературы по данной теме. За год поисков мне удалось найти всего три книги на русском, в которых хотя бы немного говориться о драйверах:

-----------------------
1. Свен Шрайбер «Недокументированные возможности Windows 2000». Издательство «Питер» 2002 год. Здесь очень хорошо описан механизм динамической загрузки драйвера.
------------------
2. П. И. Рудаков, К. Г. Финогенов «Язык ассемблера: уроки программирования»
Диалог МИФИ 2001 год. Очень полезная книга для того, что бы понять, как писать драйвера без всякий Wizard-ов.
-----------------------------
3. Светлана Сорокина, Андрей Тихонов, Андрей Щербаков «Программирование драйверов и систем безопасности». Издательство «БХВ-Петербург» 2002 год. Здесь хорошо описывается многоуровневая модель драйверов.

Предупреждение:
Я, ни в коей мере не претендую как на полноту освещения темы написания драйверов, так и на 100% правильность и достоверность того, что здесь написано (но все приведенные здесь исходники проверены и являются работоспособными). Буду благодарен всем, приславшим мне или высказавшим в форуме свои замечания.

Итак, я обращаюсь к человеку решившему написать Драйвер уровня ядра под Win2000/NT. Надеюсь, эти заметки помогут сэкономить кучу времени и сил.

Прежде всего, я бы не рекомендовал (исходя из собственного опыта) пользоваться различными библиотеками (типа NuMega и всякими другими визардами). В основном из-за того, что даже для написания простейшего драйвера необходимо хотя бы поверхностное представление о том, как он функционирует. И самый простой способ получить представление об этом-написать драйвер самому. Мне, например, не хватило терпения разобраться с NuMega, и даже «оболочки» функций динамической загрузки/выгрузки драйвера, предложенные Свен Шрайбером в своей книге, я предпочел переписать.

Итак, начнем.
Для начала надо установить на компьютер Visul C++ 6.0, MSDN и NTDDK установку проводить желательно именно в этом порядке. Лично я пользуюсь редактором UltraEdit для работы с текстами драйверов, но в принципе исходный код драйвера можно набирать в любом текстовом редакторе, хоть в NotePad.
Создадим папку, в которой мы будем работать с драйвером (пусть это будет C:myDriver).
В этой папке создадим 5 файлов:

  • myDrv.c
  • myDrv.h
  • myDrv.rc
  • MAKEFILE
  • SOURCES

Начнем с последнего файла:
В SOURCES скопируйте следующее:
TARGETNAME=myDrv
TARGETPATH=obj
TARGETTYPE=DRIVER

SOURCES=myDrv.c MyDrv.rc
В MAKEFILE скопируйте следующее:
!INCLUDE $(NTMAKEENV)makefile.def

В myDrv.rc скопируйте следующее: #include
#include
#define VER_FILETYPE VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
#define VER_FILEDESCRIPTION_STR "Generic Port I/O"
#define VER_INTERNALNAME_STR "myDrv.sys"
#include "common.ver"

А вот так должен выглядеть myDrv.h:

#define FIRST_IOCTL_INDEX 0x800
#define FILE_DEVICE_myDRV 0x00008000


#define TEST_SMTH CTL_CODE(FILE_DEVICE_myDRV,
FIRST_IOCTL_INDEX + 101,
METHOD_BUFFERED,
FILE_ANY_ACCESS)

Теперь обратимся к тексту самого драйвера myDrv.c:
#include "ntddk.h"
#include "myDrv.h"
#include "parallel.h"

#define NT_DEVICE_NAME L"\Device\myDrv"
#define DOS_DEVICE_NAME L"\DosDevices\myDrv"

//структура расширения устройства
typedef struct _DEVICE_EXTENSION
{
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
HANDLE Handle;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

//прототипы функций
NTSTATUS
DriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS
DriverOpen(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

NTSTATUS
DriverClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);

///////////////////////////////////////////////////////реализация функций

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT deviceObject;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_EXTENSION extension;
NTSTATUS ntStatus;

RtlInitUnicodeString(&deviceNameUnicodeString, NT_DEVICE_NAME);

ntStatus = IoCreateDevice(DriverObject,
sizeof (DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);

if (!NT_SUCCESS(ntStatus)) return ntStatus;

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverOpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverClose;

extension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
extension->DeviceObject = deviceObject;
extension->DriverObject = DriverObject;

// Create counted string version of our Win32 device name.
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);

// Create a link from our device name to a name in the Win32 namespace.
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}

return STATUS_SUCCESS;
}


//-------------------------------------------------------------------------------------------------------------------
VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_EXTENSION extension;
PIRP pNewIrp = NULL;
ULONG m_size;
NTSTATUS ntStatus;
extension = DriverObject->DeviceObject->DeviceExtension;

// Create counted string version of our Win32 device name.
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);


// Delete the link from our device name to a name in the Win32 namespace.
IoDeleteSymbolicLink(&deviceLinkUnicodeString);


// Finally delete our device object
IoDeleteDevice(DriverObject->DeviceObject);
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverOpen(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverClose(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

//-------------------------------------------------------------------------------------------------------------------
NTSTATUS
DriverDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION extension;
PULONG ioBuffer;
ULONG ioControlCode;
ULONG port = 0;

Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
extension = DeviceObject->DeviceExtension;
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode)
{
case TEST_SMTH:
ioBuffer[0] =(ULONG)DriverEntry;//В буфер обмена адрес функции DriverEntry
Irp->IoStatus.Information = 4;
break;

default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}

ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}

Немного поясню содержимое файла myDrv.c. Итак, по порядку:
#define NT_DEVICE_NAME L"\Device\myDrv"
#define DOS_DEVICE_NAME L"\DosDevices\myDrv"- Эти строки служат для задания символических имен текстовыми строками с именами объекта устройства, который будет создан нашим драйвером.
Далее приведены прототипы используемых функций. Этим функциям можно дать произвольные имена, НО их сигнатура (состав параметров с типом возвращаемого значения) жестко заданы системой.
[2]:Программная часть драйвера начинается с обязательной функции с именем DriverEntry(), которая автоматически вызывается системой на этапе загрузки драйвера. Эта функция должна содержать все действия по его инициализации. В качестве первого параметра наша функция получает указатель на объект драйвера типа PDRIVER_OBJECT.

Небольшое лирическое отступление:
При загрузке драйвера системы создает объект драйвера (driver object), олицетворяющий образ драйвера в памяти. С другой стороны, объект драйвера представляет собой структуру, содержащую необходимые для функционирования драйвера данные и адреса функций. В процессе инициализации драйвера (в DriverEntry()) создаются один или несколько объектов устройств (device object), олицетворяющие те устройства с которыми будет работать драйвер. Этот самый device object, необходим для правильного функционирования драйвера и создается (как и в нашем случае) даже тогда, когда драйвер не имеет отношение к какому-либо реальному устройству.

Далее, в первых строках DriverEntry мы определяем используемые в ней данные, в т.ч. указатель на device object и две символьные строки UNICODE_STRING с именами устройств. Системные программы взаимодействуют с объектом устройства, созданным драйвером, посредством указателя на него. Однако для прикладных программ объект устройства представляется одним из файловых объектов и обращение к нему осуществляется по имени (в приложении мы будем использовать функцию CreateFile() ).
Надо иметь в виду, что объект устройства должен иметь два имени, одно-в пространстве имен NT, другое-в пространстве имен Win32. Эти имена должны представлять собой структуры UNICODE_STRING. Имена объектов устройств составляются по определенным правилам. NT-имя предваряется префиксом Device, а Win32-имя -префиксом ?? ( или DosDevice). При указании имен в Си-программе знак обратной косой черты удваивается. Для того чтобы указанное в программе драйвера имя можно было использовать в приложении для открытия устройства, следует создать символическую связь между обоими заданными именами устройств. Для этого используем функцию IoCreateSymbolicLink(). Следующая обязательная операция-создание объекта устройства-осуществляется вызовом функции IoCreateDevice().
Первый параметр этой функции это указатель на объект драйвера, поступающий в DriverEntry(). Второй параметр определяет размер расширения устройства-структуры, которая служит для передачи данных между функциями драйвера (состав этой структуры произволен, и полностью определяется разработчиком). Третий параметр-созданное ранее NT-имя устройства. Далее идут: тип устройства (FILE_DEVICE_UNKNOWN), специальные характеристики (0), FALSE означает, что у нас однопоточное устройство. Наконец, последний параметр является выходным-через него функция возвращает указатель на созданный объект устройства.
Далее необходимо занести в объект драйвера адреса основных функций, включенных программистом в текст драйвера. Массив MajorFunction является одним из элементов структурной переменной. В этот массив мы и заносим адреса основных функций (т.е. функций которые вызываются системой автоматически в ответ на определенные действия приложения или устройства). Завершается функция оператором return с указанием кода успешного завершения.
Функция DriverUnload() вызывается при выгрузке драйвера. Здесь мы должны выполнить действия по удалению объекта устройства, созданного в DriverEntry().
Функции DriverOpen и DriverClose в нашем случае ничего не делают и возвращают просто STATUSS_SUCCESS. Кстати, все эти функции тоже могут иметь произвольные имена, но передаваемые им параметры строго фиксированы.

[2]:Вот мы и добрались до «самой содержательной» с точки зрения прикладного программирования функции DriverDeviceControl(). Эта функция вызывается каждый раз, когда драйверу приходит IRP-пакет с каким либо IOCTL_… кодом. Грубо говоря, IRP-пакет-это структура, передавая указатель на которую, приложение может «общаться» с драйвером (как впрочем, и драйвер может «общаться» с другим драйвером). Более подробное описание того, что такое IRP-пакет можно найти здесь http://www.lcard.ru/~gorinov/texts/irp99.html .
IRP-пакет содержит так называемый системный буфер, служащий для обмена информацией (переменная SystemBuffer). Таким образом, нам надо получить доступ к IRP-пакету, а через него к SystemBuffer. Для этого объявляем переменную irpStack типа указателя на стековую область ввода-вывода PIO_STACK_LOCATION, и, кроме того, переменная ioBuffer, в которую будет помещен адрес системного буфера обмена. В нашем случае тип этой переменной-PULONG, в действительности тип передаваемых данных может быть каким угодно. С помощью функции IoGetCurrentIrpStackLocation() в переменную irpStack помещается адрес стековой области ввода-вывода, а в переменную ioBuffer заноситься адрес системного буфера из структуры IRP. Системный буфер входит в объединение (union) с именем AssociatedIrp, поэтому мы используем конструкцию Irp->AssociatedIrp.SystemBuffer.
Конструкция switch-case анализирует содержимое ячейки IoControlCode и в зависимости от значения кода выполняет те или иные действия. В нашей программе только один код действия TEST_SMTH. Засылка в буфер обмена адреса функции DriverEntry() осуществляется через указатель на этот буфер. В переменную Irp->IoStatus.Information заносим количество (4) пересылаемых байт. Для завершения IRP-пакета вызываем IoCompleteRequest().
Итак, драйвер мы написали. Теперь надо его скомпилировать. Т.к. процесс компиляции идет из командной строки, то для этой цели гораздо удобнее пользоваться bat-файлом. Создадим небольшой bat-файл с именем, допустим, Crt.bat и со следующим содержанием:

%SystemRoot%system32cmd.exe /c "cd C:NTDDKbin&&setenv.bat C:NTDDK&&cd c:myDriver &&build -ceZ"
pause

Замечание:
NTDDK у меня установлено в корень С:, если у Вас по другому- то вместо C:NTDDKbin и C:NTDDK пропишите полные пути к соответствующим папкам.

Итак, теперь запустим наш Crt.bat. После окончания компиляции в папке C:myDriverobjfrei386 находим готовый драйвер myDrv.sys. Наш драйвер пока умеет только, лишь загружаться/выгружаться и по специальному запросу-посылает приложению адрес одной из своих процедур.

Теперь займемся написанием приложения работающего с нашим драйвером. Еще раз напоминаю, что мы работаем под Win2000. Эта ОС позволяем реализовать динамическую загрузку/выгрузку драйвера.

Примечание:
Точнее динамическую загрузку/выгрузку служб (service), но т.к. в Win2000 в качестве службы можно рассматривать и драйвер, я буду использовать оба эти термина, подразумевая, в данной статье, наш драйвер.

Для загрузки и выгрузки драйверов используется диспетчер управления службами SC Manager (Service Control Manager). Прежде чем вы сможете работать с интерфейсом SC, вы должны получить дескриптор диспетчера служб. Для этого необходимо обратиться к функции OpenSCManager(). Дескриптор диспетчера служб необходимо использовать при обращении к функциям CreateServise() и OpenService(). Дескрипторы, возвращаемые этими функциями необходимо использовать при обращении к вызовам, имеющим отношение к конкретной службе. К подобным вызовам относятся функции ControlService(), DeleteService() и StartService(). Для освобождения дескрипторов обоих типов используется вызов CloseServiceHandle().
Загрузка и запуск службы подразумевает выполнение следующих действий:

  1. Обращение к функции OpenSCManager() для получения дескриптора диспетчера
  2. Обращение к CreateServise() для того, чтобы добавить службу в систему.
    Если такой сервис уже существует, то CreateServise() выдаст ошибку с кодом 1073 (код ошибки можно прочитать GetLastError()) данная ошибка означает, что сервис уже существует и надо вместо CreateServise() использовать OpenService().
  3. Обращение к StartService() для того, чтобы перевести службу в состояние функционирования.
  4. Если служба запустилась успешно, то можно вызвать CreateFile(), для получения дескриптора, который мы будем использовать уже непосредственно при обращении к драйверу.
  5. И по окончании работы не забудьте дважды обратиться к CloseServiceHandle() для того чтобы освободить дескрипторы диспетчера и службы.

Если на каком-то шаге этой последовательности возникла ошибка, нужно выполнить действия обратные тем, которые вы успели выполнить до ошибки.
Надо помнить о том, что при обращении к функциям подобным CreateServise() необходимо указывать полное имя исполняемого файла службы (в нашем случае полный путь и имя myDrv.sys).

Посмотрим на исходный текст простого консольного приложения, написанного на Visual C++ 6.0:

#include
#include "LoadDRV.h"
#include
#include


void main()
{
LPTSTR m_name = new char[20];
strcpy(m_name, "myDrv.sys");

if (drvLoad(m_name)) TestSmth();

drvUnLoad(m_name);
delete m_name;
}

//-----------------------------------------------------------------------------
//создаем и посылаем драйверу IRP-запрос
int TestSmth(void)//0x800 + 101
{
int test = 0;
DWORD ReturetLength = 0;

DeviceIoControl(hDevice, IOCTL_TEST_SMTH, NULL, 0,
&test, 4, &ReturetLength, NULL);

printf("TestSmth= %in",test);
return test;
}


///**************Функции динамической загрузки************************
bool drvLoad(char* name)
{
printf (name);
hSCManager=NULL;
hService=NULL;
bool status;

status=FALSE;


if(OpenManager())
{
if(drvCreateService(name))
{
if(drvStartService(name))
{
status=TRUE;
printf("n Driver is now load...n");
}
}
}

hDevice = CreateFile ("//./myDrv", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);

return status;
}

//---------------------------------------------------------------------

bool OpenManager()
{
bool status;
status=FALSE;

if(hSCManager!=NULL)
{
CloseServiceHandle (hSCManager);
hSCManager=NULL;
}

hSCManager=OpenSCManager (NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hSCManager == NULL)
{
error(_OpenSCManager);
} else status=TRUE;

return status;
}

//---------------------------------------------------------------------
bool drvCreateService(PCHAR pDrvName)
{
LPTSTR lpBuffer;
lpBuffer = new char[256];
bool status = FALSE;
LPTSTR awPath; // путь к драйверу с именем pDrvName

// формируем путь к pDrvName, драйвер должен лежать рядом с exe-шником

GetCurrentDirectory(256, lpBuffer);
strcat(lpBuffer,"\");
strcat(lpBuffer,pDrvName);
awPath = lpBuffer;

hService = CreateService(hSCManager,pDrvName,pDrvName,SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,awPath,NULL,NULL,NULL,NULL,NULL);

if(!hService)
{
error(_CreateService);
status = drvOpenService(pDrvName);//Пытаемся открыть службу
}
else status=TRUE;

delete lpBuffer;
return status;
}

//--------------------------------------------------------------------
bool drvOpenService(PCHAR name)
{

bool status;
status=FALSE;
if(hService!=NULL) CloseService();

hService=OpenService(hSCManager,name,SERVICE_ALL_ACCESS);
if (!hService) error(_OpenService);
else status=TRUE;
return status;
}

//---------------------------------------------------------------------
bool drvStartService(PCHAR name)
{
bool status;
status=FALSE;
if(!StartService(hService,0,NULL))
{
error(_StartService);
printf("Deleting service...");
drvDeleteService(name)
}
else status=TRUE;
return status;
}

//---------------------------------------------------------------------
bool drvDeleteService(PCHAR name)
{
bool status;
status=FALSE;
CloseService();
if(!DeleteService(hService)) error(_DeleteService);
else status=TRUE;
return status;
}

//-------------------------------------------------------------------
void CloseService()
{
CloseServiceHandle (hService);
hService=NULL;
}

//-------------------------------------------------------------------
int drvUnLoad(PCHAR name)
{
int status;
status=FALSE;

if (hDevice!=INVALID_HANDLE_VALUE)
{
if(!CloseHandle(hDevice)) error(_CloseHandle);
hDevice=INVALID_HANDLE_VALUE;
}

if (hService)
{
status = ControlService(hService,SERVICE_CONTROL_STOP,&ServiceStatus);
if(!status) error(_SERVICE_CONTROL_STOP);

status = DeleteService(hService);
if(!status) error(_DeleteService);

status = CloseServiceHandle(hService);
if(!status) error(_CloseServiceHandle);
}

if(!CloseServiceHandle(hSCManager)) error(_CloseServiceHandle);
if (status) printf("Driver Unload... SUCCESSn");
return status;
}

//---------------------------------------------------------------------
void error(error_index erIndex)
{

DWORD err;
err=GetLastError();
switch(erIndex)
{
case _OpenSCManager:
printf("OpenSCManager failed with Error=%in",err);
break;

case _GetFullPathName:
printf("GetFullPathName failed with Error=%in",err);
break;

case _CreateService:
switch (err)
{
case 1073:
printf("The specified service already exists.n");
printf("opening this service...");
break;
default:
printf("CreateService failed with Error=%in",err);
}
break;

case _OpenService:
printf("OpenService failed with Error=%in",err);
break;

case _StartService:
printf("StartService failed with Error=%in",err);
break;

case _DeleteService:
printf("DeleteService failed with Error=%in",err);
break;

case _SERVICE_CONTROL_STOP:
printf("SERVICE_CONTROL_STOP failed with Error=%in",err);
break;
case _CreateFile:
printf("CreateFile failed with Error=%in",err);
break;
case _CloseHandle:
printf("CloseHandle failed with Error=%in",err);
break;
case _CloseServiceHandle:
printf("CloseServiceHandle failed with Error=%in",err);
break;

}
}

И содержимое h-файла этого приложения:

#define FIRST_IOCTL_INDEX 0x800
#define FILE_DEVICE_myDrv 0x00008000

#define TEST_SMTH CTL_CODE(FILE_DEVICE_myDrv,
0x800 + 101,
METHOD_BUFFERED,
FILE_ANY_ACCESS)

Это приложение загружает драйвер, файл которого лежит в одной папке, что и exe-шник данного приложения.

Посмотрим на исходный текст:
В main(), мы создаем переменную с именем драйвера (myDrv.sys), и передаем это имя в функцию динамической загрузки драйвера drvLoad(), которая выполняет все необходимые действия по работе с менеджером служб, и в конце вызывает CreateFile(),которая возвращает дескриптор, нужный для работы с драйвером как файловым объектом.
Этот дескриптор, в частности, используется при вызове функции DeviceIoControl.
Если драйвер загружен успешно, то вызываем функцию TestSmth(), внутри которой мы создаем, и посылаем драйверу IRP-пакет (с помощью вызова DeviceIoControl()). Приняв этот пакет, наш драйвер возвращает адрес своей процедуры DriverEntry.
После этого выгружаем драйвер. Всё.

Заключение
Итак, мы написали простейший (дальше некуда) драйвер и приложение, работающее с ним. В этой статья я активно цитировал материалы из книги П. И. Рудаков, К. Г. Финогенов, по возможности делая ссылки на нее в виде: [2]. Через некоторое время, напишу о том, как на базе этого драйвера написать драйвер-фильтр для LPT-порта.

Артем
Источник: http://shelek.com





Перейти к рубрике --> C & C++

Наши друзья
Juridiskie pakalpojumi  
IT Works
  Codenet - всё для программиста
   
• Hi-tech NEWS • InCube e-mag
  Программисты, Вам сюда!
КомментарииВсего:0


Только зарегистрированные пользователи могут оставлять здесь комментарии. Зарегистрироваться можно здесь. Если вы уже зарегистировались ранее, то можете войти в систему здесь.


© Mihail Chernov (MiHack) Обмен ссылками