Создание VxD на Visual C++ без ассемблерных модулей - Общая схема драйвера VxD

ОГЛАВЛЕНИЕ

 

Общая схема драйвера VxD

Минимальный виртуальный драйвер должен содержать секцию резидентного кода, в которой расположены блок описателя устройства, диспетчер системных сообщений и обработчики сервисных функций.Обработчик системных сообщений анализирует код сообщения, переданный в EAX, выделяет интересующие его сообщения, обрабатывает их и возвращает сброшенный флаг CF в случае успеха, и установленный — в случае неудачи. Для всех необрабатываемых сообщений должен возвращаться сброшенный флаг CF.Обработчики сервисных функций вызываются по таблице, так что каждой функции соответствует собственный обработчик. Способ передачи параметров и возврата результатов определяется разработчиком.При необходимости драйвер может содержать обработчики запросов V86 и PM API. Для доступа к данным виртуальных машин DOS, указатели на которые могут передаваться в регистрах при запросе, достаточно преобразовать их в линейные 32-разрядные адреса, ибо первый мегабайт адресного пространства текущей виртуальной машины непосредственно «виден» из VxD. Для доступа к данным приложений Win16 потребуется выполнить отображение адресов посредством функции VMM _SelectorMapFlat.

Программирование VxD

Средства разработки, включаемые файлы и библиотекиМинимально необходимый набор включаемых файлов и библиотек содержится в Windows 95 DDK (подкаталоги Inc32 и Lib). Обычно требуется включение хотя бы файлов BASEDEF.H и VMM.H.Файлы VXDWRAPS.H, CONFIGMG.H и некоторые другие оформлены в стиле обычного языка C, поэтому при включении их в файлы типа CPP директивы #include необходимо помещать внутрь квалификатора extern "C":

extern "C" {
#include <vxdwraps.h>
}

 

Файлы из DDK можно включать и в тексты модулей обычных приложений, определив перед этим символическое имя Not_VxD. При этом определяются только полезные константы и типы, а определение специфических для VxD конструкций отключается.

Структуры, обычно используемые в VxD

VxD_Desc_Block - блок описателя устройстваОписывает структуру DDB. Заполняется статически, чтобы к моменту загрузки драйвера все поля имели нужные значения.

ULONG DDB_Next;
USHORT DDB_SDK_Version;
USHORT DDB_Req_Device_Number;
UCHAR DDB_Dev_Major_Version;
UCHAR DDB_Dev_Minor_Version;
USHORT DDB_Flags;
UCHAR DDB_Name [8];
ULONG DDB_Init_Order;
ULONG DDB_Control_Proc;
ULONG DDB_V86_API_Proc;
ULONG DDB_PM_API_Proc;
ULONG DDB_V86_API_CSIP;
ULONG DDB_PM_API_CSIP;
ULONG DDB_Reference_Data;
ULONG DDB_Service_Table_Ptr;
ULONG DDB_Service_Table_Size;
ULONG DDB_Win32_Service_Table;
ULONG DDB_Prev;
ULONG DDB_Size;
ULONG DDB_Reserved1;
ULONG DDB_Reserved2;
ULONG DDB_Reserved3;

  • DDB_Next — поле для адреса следующего DDB в списке VMM. Инициализируется нулем.
  • DDB_SDK_Version — версия DDK, с которой построен драйвер. Инициализируется константой DDK_VERSION.
  • DDB_Req_Device_Number — идентификатор устройства. При отсутствии назначенного идентификатора задается нулевое значение.
  • DDB_Dev_Major_Version — старшая часть номера версии драйвера.
  • DDB_Dev_Minor_Version — младшая часть номера версии драйвера.
  • DDB_Flags — для служебных флагов VMM. Инициализируется нулем.
  • DDB_Name — имя устройства, дополненное пробелами до восьми символов.
  • DDB_Init_Order — позиция драйвера в списке загрузки. Если порядок загрузки не важен, используется константа UNDEFINED_INIT_ORDER (нуль).
  • DDB_Control_Proc — адрес функции диспетчера системных сообщений.
  • DDB_V86_API_Proc — адрес функции диспетчера V86 API.
  • DDB_PM_API_Proc — адрес функции диспетчера PM API.
  • DDB_V86_API_CSIP — служебное поле, инициализируется нулем.
  • DDB_PM_API_CSIP — служебное поле, инициализируется нулем.
  • DDB_Reference_Data — служебное поле, инициализируется нулем.
  • DDB_Service_Table_Ptr — указатель таблицы адресов процедур—обработчиков сервисных функций.
  • DDB_Service_Table_Size — количество сервисных функций, реализованных в драйвере.
  • DDB_Win32_Service_Table — служебный указатель таблицы функций Win32, инициализируется нулем.
  • DDB_Prev — поле для адреса предыдущего DDB в списке VMM, инициализируется константой 'Prev'.
  • DDB_Size — размер структуры описателя.
  • DDB_Reserved1 — служебное поле. Инициализируется константой 'Rsv1'.
  • DDB_Reserved2 — служебное поле. Инициализируется константой 'Rsv2'.
  • DDB_Reserved3 — служебное поле. Инициализируется константой 'Rsv3'.

Client_Reg_Struc - структура пакета регистров клиента

Описывает состояние регистров процессора в вызвавшей виртуальной машине/приложении (клиенте).

ULONG Client_EDI;
ULONG Client_ESI;
ULONG Client_EBP;
ULONG Client_res0;
ULONG Client_EBX;
ULONG Client_EDX;
ULONG Client_ECX;
ULONG Client_EAX;
ULONG Client_Error;
ULONG Client_EIP;
USHORT Client_CS;
USHORT Client_res1;
ULONG Client_EFlags;
ULONG Client_ESP;
USHORT Client_SS;
USHORT Client_res2;
USHORT Client_ES;
USHORT Client_res3;
USHORT Client_DS;
USHORT Client_res4;
USHORT Client_FS;
USHORT Client_res5;
USHORT Client_GS;
USHORT Client_res6;
ULONG Client_Alt_EIP;
USHORT Client_Alt_CS;
USHORT Client_res7;
ULONG Client_Alt_EFlags;
ULONG Client_Alt_ESP;
USHORT Client_Alt_SS;
USHORT Client_res8;
USHORT Client_Alt_ES;
USHORT Client_res9;
USHORT Client_Alt_DS;
USHORT Client_res10;
USHORT Client_Alt_FS;
USHORT Client_res11;
USHORT Client_Alt_GS;
USHORT Client_res12;

Поля с именами Client_xxx содержат значения соответствующих регистров на момент обращения виртуальной машины или приложения к системной функции. В поле Client_Error может быть занесен код ошибки.Для структуры введен синоним типа (typedef) с именем CRS. В файле VMM.H определены также вспомогательные структуры Client_Word_Reg_Struc и Client_Byte_Reg_Struc и объединение всех трех структур CLIENT_STRUCT.

DIOCParams - параметры запроса DeviceIoControl

DWORD Internal1;
DWORD VMHandle;
DWORD Internal2;
DWORD dwIoControlCode;
DWORD lpvInBuffer;
DWORD cbInBuffer;
DWORD lpvOutBuffer;
DWORD cbOutBuffer;
DWORD lpcbBytesReturned;
DWORD lpoOverlapped;
DWORD hDevice;
DWORD tagProcess;

  • VMHandle — идентификатор виртуальной машины, сделавшей запрос.
  • dwIoControlCode — код функции. Константы для определенных в системе кодов функций имеют префикс DIOC_, остальные функции определяются разработчиком.
GETVERSION (0) Открывание и опрос интерфейса. Если драйвер не поддерживает Win32 API, он должен вернуть в EAX ненулевое значение. В противном случае в EAX возвращается нуль, а если задан буфер результата, то в него заносится номер версии драйвера.
CLOSEHANDLE (-1) Закрывание интерфейса. Драйвер должен прервать обработку всех асинхронных запросов по этому устройству и освободить относящиеся к нему ресурсы.
  • lpvInBuffer — указатель исходного буфера.
  • cbInBuffer — размер исходного буфера в байтах.
  • lpvOutBuffer — указатель буфера результата.
  • cbOutBuffer — размер буфера результата в байтах.
  • lpcbBytesReturned — поле для объема в байтах данных, занесенных драйвером в буфер результата.
  • lpoOverlapped — указатель структуры типа OVERLAPPED (описатель адреса внутри файла и/или данных для асинхронной операции).
  • hDevice — идентификатор устройства.
  • tagProcess — идентификатор запроса. Вместе с полем hDevice образует уникальный внутри системы идентификатор запроса, по которому запрос может быть найден и аварийно прерван при получении запроса CLOSEHANDLE.