Создание антивирусного программного обеспечения с применением языка программирования низкого уровня: Методические указания по выполнению лабораторных работ по курсу «Информационная безопасность», страница 5

Каждая строка внутри таблицы обработки сообщений соответствует одному сообщению. Такая строка должна начинаться макросом «Control_Dispatch», за которым следует имя (номер) обрабатываемого сообщения и имя процедуры, которая его обрабатывает.

Так, в приведенном выше примере драйвер обрабатывает 3 сообщения:

– W32_DeviceIoControl;

– SYS_DYNAMIC_DEVICE_INIT;

– SYS_DYNAMIC_DEVICE_EXIT.

Первое сообщение обеспечивает интерфейс драйвера с Windows-программой, работающей на 3-м кольце защиты (см. о связи между драйвером и программой далее). Также следует отметить, что любой динамически загружаемый драйвер должен обрабатывать это сообщение, т.к. через него происходит динамическая инициализация драйвера при его открытии приложением.

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

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

Однако, весь список сообщений, посылаемых драйверу не ограничивается этими тремя. Для получения полной информации, откройте файл «other.chm» из Windows 98 DDK, перейдите на страничку «поиск» и введите строку «control_dispatch» для поиска. После чего выберите одноименный раздел из списка. А для более полного списка, обратитесь к файлу «vmm.inc».

Но для начального знакомства с написанием драйвера этих трех сообщений вполне достаточно.

Как было сказано выше, каждому сообщению соответствует своя процедура обработки. Любая процедура (не обязательно, что она обрабатывает сообщение) при написании драйвера должна быть определена следующим образом:

VxD_LOCKED_CODE_SEG

...

BeginProc OnSysInit

... тело процедуры

ret

EndProc   OnSysExit

Т.е. для определения процедуры используются макросы «BeginProc» и «EndProc», за которыми следует имя определяемой процедуры.

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

Какой же можно сделать вывод? С использованием макроопределений из DDK исходный код драйвера минимален и выглядит весьма изящно. Не требуется никаких сложных структур и так называемого startup кода (т.е. кода, необходимого для правильного функционирования программы, независимо от ее назначения).

Интерфейс драйвера и Windows-приложения

Теперь рассмотрим, как происходит динамическая загрузка драйвера из Windows-приложения.

Для загрузки драйвера применяется хорошо известная функция Windows API (находящаяся в kernel32.dll) CreateFile. Странно? Да, наверное, но ребята из Microsoft решили так. При этом первый параметр указывает имя открываемого драйвера с префиксом «\\.\», т.е. для открытия файла AV.vxd, находящегося в текущем каталоге, необходимо в качестве первого параметра указать строку «\\.\AV.vxd» (следует иметь ввиду, что при программирования на языке С++ для задания бэкслэша (backslash) следует использовать два символа «\\»). В качестве второго, 3-го, 4-го и 5-го параметра указываются нули, 6-й параметр имеет значение «FILE_FLAG_DELETE_ON_CLOSE» и 7-й – значение ноль. При этом функция возвращает хэндл (handle) на открытый драйвер. Этот хэндл следует запомнить. Пример:

HANDLE h = CreateFile ('\\.\av.vxd', 0, 0, 0, 0, \

FILE_FLAG_DELETE_ON_CLOSE, 0);

После завершения работы с драйвером, его хэндл закрывается обычным образом (с помощью функции CloseHandle (h)). Если при этом больше никто не пользовался услугами этого драйвера, то его код выгружается из памяти компьютера.

Когда Вы пытаетесь таким способом открыть драйвер, система поступает следующим образом. Она загружает драйвер в память и проверяет, поддерживает ли он динамическую загрузку. Это происходит посредством посылки драйверу сообщения «W32_DeviceIoControl».