Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебники 6050.doc
Скачиваний:
14
Добавлен:
01.05.2022
Размер:
361.47 Кб
Скачать

1.2.2. Компиляция и сборка драйвера Example.Sys

Для компиляции и сборки драйвера утилитой Build пакета DDK потребуется создать два файла описания проекта — Makefile и Sources.

Файл Makefile. Этот файл управляет работой программы Build и в нашем случае имеет стандартный вид (его можно найти практически в любой директории примеров DDK), а именно:

!INCLUDE $(NTMAKEENV)\makefile.def

Файл Sources. Файл sources отражает индивидуальные настройки процесса компиляции и сборки. В нашем случае файл Sources чрезвычайно прост и имеет вид:

TARGETNAME=Example

TARGETTYPE=DRIVER

TARGETPATH=obj

SOURCES=init.cpp

Данный файл задает имя выходного файла Example, параметр TARGETNAME. Поскольку проект (TARGETTYPE) имеет тип DRIVER, то выходной файл будет иметь расширение .sys. Промежуточные файлы будут размещены во вложенной директории .\obj. Строка SOURCES задает единственный файл с исходным текстом — это файл init.cpp.

Для компиляции «чистовой» версии драйвера нужно запустить .exe файл:

Пуск – Все программы – Development Kits – Windows DDK 3790.1830 – Build Environments – Windows XP – Windows XP Free Build Environment.exe

Для компиляции отладочной версии (данная версия позволяет получать отладочные сообщения от драйвера в программе DebugView) драйвера нужно запустить:

Пуск – Все программы – Development Kits – Windows DDK 3790.1830 – Build Environments – Windows XP – Windows XP Checked Build Environment.exe

Когда программы запущена, нужно выполнить консольную команду перехода к директории, в которой находятся файлы с кодом драйвера и файлы описания проекта и вызвать команду build (например):

C:\WINDDK\3790.1830>cd C:\Example\

C:\Example>build

После выполнения этих действий начнется компиляция и сборка драйвера. В случае ошибок компиляции или сборки вывод будет содержать и их диагностику. Рабочее окно сборки драйвера под Windows XP DDK версии checked изображено на рисунке 1.

Рис. 1. Рабочее окно сборки драйвера под Windows XP DDK версии checked

1.2.3. Тестирование драйвера

Работа с драйвером Example.sys

Как уже было сказано, из всех возможных способов инсталляции и запуска драйвера Example.sys, ниже будет использован способ тестирования с применением тестирующего консольного приложения, которое само будет выполнять инсталляцию и удаление драйвера (прибегая к вызовам SCM Менеджера). Для поэтапного ознакомления с процессом взаимодействия драйвера и обращающегося к нему приложения рекомендуется запустить программу ExampleTest под отладчиком в пошаговом режиме.

Перед запуском тестирующей программы ExampleTest рекомендуется загрузить программу DebugView, чтобы в ее рабочем окне наблюдать сообщения, поступающие непосредственно из кода драйвера Example.sys (отладочной сборки).

Приложение, работающее с драйвером

Перед тем, как приступить к тестированию драйвера путем вызова его сервисов из приложения, следует это приложение создать, хотя бы в минимальном виде, как это предлагается ниже. И хотя драйвер можно успешно запускать программой Monitor, воспользуемся функциями SCM, поскольку это будет существенно полезнее для будущей практики. Для загрузки и выгрузки драйверов используется диспетчер управления службами 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(), необходимо указывать полное имя исполняемого файла службы (в нашем случае полный путь и имя Example.sys).

Листинг 8.

//////////////////////////////////////////////

// (Файл ExampleTest.cpp)

// Консольное приложение для тестирования драйвера Example.sys

///////////////////////////////////////////////////// Заголовочные файлы, которые необходимы в данном //приложении:

#include <windows.h>

#include <stdio.h>

#include <winioctl.h>

#include <tchar.h>

// Имя объекта драйвера и местоположение //загружаемого файла

#define DRIVERNAME _T("Example")

#define DRIVERBINARY _T("C:\\Example\\ExampleDriver\\Example.sys")

// Функция установки драйвера на основе SCM вызовов

BOOL InstallDriver( SC_HANDLE scm, LPCTSTR DriverName, LPCTSTR driverExec )

{

SC_HANDLE Service =

CreateService ( scm, // открытый дескриптор к SCManager

DriverName, // имя сервиса - Example

DriverName, // для вывода на экран

SERVICE_ALL_ACCESS, // желаемый доступ

SERVICE_KERNEL_DRIVER, // тип сервиса

SERVICE_DEMAND_START, // тип запуска

SERVICE_ERROR_NORMAL, // как обрабатывается ошибка

driverExec, // путь к бинарному файлу

// Остальные параметры не используются - укажем //NULL

NULL, // Не определяем группу загрузки

NULL, NULL, NULL, NULL);

if (Service == NULL) // неудача

{

DWORD err = GetLastError();

if (err == ERROR_SERVICE_EXISTS) {/* уже установлен */}

// более серьезная ощибка:

else printf ("ERR: CanТt create service. Err=%d\n",err);

// (^^ Этот код ошибки можно подставить в //ErrLook):

return FALSE;

}

CloseServiceHandle (Service);

return TRUE;

}

// Функция удаления драйвера на основе SCM вызовов

BOOL RemoveDriver(SC_HANDLE scm, LPCTSTR DriverName)

{

SC_HANDLE Service =

OpenService (scm, DriverName, SERVICE_ALL_ACCESS);

if (Service == NULL) return FALSE;

BOOL ret = DeleteService (Service);

if (!ret) { /* неудача при удалении драйвера */ }

CloseServiceHandle (Service);

return ret;

}

// Функция запуска драйвера на основе SCM вызовов

BOOL StartDriver(SC_HANDLE scm, LPCTSTR DriverName)

{

SC_HANDLE Service =

OpenService(scm, DriverName, SERVICE_ALL_ACCESS);

if (Service == NULL) return FALSE; /* open fail */

BOOL ret =

StartService( Service, // дескриптор

0, // число аргументов

); // указатель на аргументы

if (!ret) // неудача

{

DWORD err = GetLastError();

if (err == ERROR_SERVICE_ALREADY_RUNNING)

ret = TRUE; // OK, драйвер уже работает!

else { /* другие проблемы */}

}

CloseServiceHandle (Service);

return ret;

}

// Функция останова драйвера на основе SCM вызовов

BOOL StopDriver(SC_HANDLE scm, LPCTSTR DriverName)

{

SC_HANDLE Service =

OpenService (scm, DriverName, SERVICE_ALL_ACCESS );

if (Service == NULL)

// Невозможно выполнить останов драйвера

{

DWORD err = GetLastError();

return FALSE;

}

SERVICE_STATUS serviceStatus;

BOOL ret =

ControlService(Service, SERVICE_CONTROL_STOP, &serviceStatus);

if (!ret)

{

DWORD err = GetLastError();

// дополнительная диагностика

}

CloseServiceHandle (Service);

return ret;

}

#define SCM_SERVICE

/* ^^^^^^^^^^^^^^^^ вводим элемент условной компиляции, при помощи которого можно отключать использование SCM установки драйвера в тексте данного приложения. (Здесь Ц использование SCM включено.) Основная функция тестирующего приложения. Здесь минимум внимания уделен диагностике ошибочных ситуаций. В действительно рабочих приложениях следует уделить этому больше внимания*/

int __cdecl main(int argc, char* argv[])

{

#ifdef SCM_SERVICE

// Используем сервис SCM для запуска драйвера.

BOOL res; // Получаем доступ к SCM :

SC_HANDLE scm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

if(scm == NULL) return -1; // неудача

// Делаем попытку установки драйвера

res = InstallDriver(scm, DRIVERNAME, DRIVERBINARY );

if(!res)

// Неудача, но возможно, он уже инсталлирован

printf("Cannot install service");

res = StartDriver (scm, DRIVERNAME );

if(!res)

{

printf("Cannot start driver!");

res = RemoveDriver (scm, DRIVERNAME );

if(!res)

{

printf("Cannot remove driver!");

}

CloseServiceHandle(scm); // Отключаемся от SCM

return -1;

}

#endif

HANDLE hHandle = // Получаем доступ к драйверу

CreateFile( "\\\\.\\Example",

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL, NULL );

if(hHandle==INVALID_HANDLE_VALUE)

{

printf("ERR: can not access driver Example.sys !\n");

return (-1);

}

DWORD BytesReturned;

// Переменная для хранения числа переданных байт

// Последовательно выполняем обращения к драйверу

// с запросами на запись/чтение данных:

unsigned char xdata = 0x21;

if( !WriteFile( hHandle,

&xdata,

sizeof(xdata),

&BytesReturned,

NULL) )

{

printf( "Error with byte receive!" );

return(-1);

}

// Вывод диагностического сообщения в консольном //окне:

printf("Byte send: BytesTransferred=%d xdata=%d\r\n",

BytesReturned, xdata);

// Получаем 1 байт данных из драйвера.

// По окончании данного вызова переменная //xdata должна

// содержать значение 0x21:

if( !ReadFile( hHandle,

&xdata,

sizeof(xdata),

&BytesReturned,

NULL))

{

printf( "Error with byte receive!" );

return(-1);

}

// Вывод диагностического сообщения в //консольном окне:

printf("Byte receive: BytesReturned=%d xdata=%d\r\n",

BytesReturned, xdata);

// Закрываем дескриптор доступа к драйверу:

CloseHandle(hHandle);

#ifdef SCM_SERVICE

// Останавливаем и удаляем драйвер. //Отключаемся от SCM.

res = StopDriver (scm, DRIVERNAME );

if(!res)

{

printf("Cannot stop driver!");

CloseServiceHandle(scm);

return -1;

}

res = RemoveDriver (scm, DRIVERNAME );

if(!res)

{

printf("Cannot remove driver!");

CloseServiceHandle(scm);

return -1;

}

CloseServiceHandle(scm);

#endif

return 0;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]