Рис. 4.7.4. Программа, загружающая, использующая и выгружающая динамический драйвер.
Прокомментируем программу на Рис. 4.7.4. Главное здесь - разобрать работу
функции DeviceIoControl
. Вот параметры этой функции:
- 1-й параметр, дескриптор драйвера, полученный через функцию
CreateFile
. - 2-й параметр, номер необходимой Вам операции.
- 3-й параметр, адрес данных для драйвера.
- 4-й параметр, длина данных.
- 5-й параметр, буфер, куда драйвер поместит свои данные.
- 6-й параметр, длина буфера.
- 7-й параметр, адрес переменной, куда будет занесено количество байтов, помещенных в буфер драйвером.
- 8-й параметр, адрес
OVERLAPPED
-структуры.
Как видите, при вызове мы передаем указатель на строку MES1
.
Теперь, я думаю. Вы легко сможете разобраться в программе загрузки. Переходим
к самому драйверу. Драйвер выполняет весьма простую функцию. При вызове его
сервиса он выводит на экран сообщение. Причем текст сообщения передается
вызывающей программой. При вызове функции DeviceIoControl
с
дескриптором драйвера, на драйвер приходит сообщение
w32_deviceIoControl
. При этом регистр EBX
содержит
дескриптор виртуальной машины, ESI
указывает на структуру,
содержимое которой мы сейчас разберем. При этом надо иметь в виду, что при
загрузке драйвера на него тоже приходит это же сообщение, и мы его должны также
обработать. Разберем теперь структуру, на которую указывает регистр
ESI
.
DIOCParams STRUC Internal1 DD ? VMHandle DD ? Internal2 DD ? dwIoControlCode DD ? lpvInBuffer DD ? cbInBuffer DD ? lpvOutBuffer DD ? cbOutBuffer DD ? lpcbBytesReturned DD ? lpoOverlapped DD ? hDevice DD ? tagProcess DD ? DIOCParams ENDS
Опишем поле структуры:Internal1
- указатель на структуру
Client_Reg_Struc
, определяющую регистры вызывающего приложения (см.
Рис. 4.7.6. и пояснения к нему).VMHandle
- дескриптор
виртуальной машины.Internal2
- указатель на блок
DDB
.dwIoControlCode
- номер необходимой
операции.lpvInBuffer
- указатель на буфер, содержащий
информацию вызывающей программы.cbInBuffer
- количество байт,
пересылаемых в буфере.lpvOutBuffer
- указатель на буфер, в
который драйвер может поместить информацию для вызывающей
программы.cbOutBuffer
- количество байт в
буфере.lpcbBytesReturned
- количество возвращаемых
байт.lpoOverlapped
- указатель на
OverLapped-структуру.hDevice
- дескриптор драйвера,
возвращаемый функцией CreateFile
.tagProcess
-
признак процесса.
.386P include vmm.inc include vcond.inc include vwin32.inc include shell.inc DECLARE_VIRTUAL_DEVICE MSG,1,0, MSG_Control,\ UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER Begin_control_dispatch MSG ; будем обрабатывать сообщение w32_Device!oControl ; процедурой PROC1 Control_Dispatch w32_DeviceIoControl, PROC1 End_control_dispatch MSG ; сегмент данных VxD_PAGEABLE_DATA_SEG CAP1 DB "Окно сообщения",0 MES1 DB 50 DUP (0) VxD_PAGEABLE_DATA_ENDS ; сегмент кода VxD_PAGEABLE_CODE_SEG BeginProc PROC1 CMP DWORD PTR [ESI]+12,DIOC_Open JNE L1 XOR EAX,EAX JMP _EXIT L1: CMP DWORD PTR [ESI]+12,3 JNZ _EXIT ; длина строки MOV EDI,DWORD PTR [ESI]+16 VMMCall _lstrlen, <EDI> ; копировать в буфер INC EAX ; длина VMMCall _lstrcpyn,<OFFSET MES1,EDI,EAX> ; вызвать функцию SHELL_Message MOV ECX,OFFSET MES1 ; DWORD PTR [ESI]+14 MOV EDI,OFFSET CAP1 MOV EAX,MB_OK + MB_ICONEXCLAMATION VMMCall Get_Sys_VM_Handle ; адрес CaliBack функции, в данном случае NULL XOR ESI,ESI ; ссылка на данные для CallBack-функции XOR EDX,EDX VxDCall SHELL_Message XOR EAX,EAX _EXIT: RET EndProc PROC1 VxD_PAGEABLE_CODE_ENDS endРис. 4.7.5. Пример динамического драйвера Прокомментируем программу на Рис. 4.7.5.
- Как я уже говорил, при загрузке драйвера на него приходит сообщение
w32_DeviceIoControl
, при этом на структуру указывает регистрESI
. При этом полеdwIoControlCode
будет содержать числоDIOC_Open
, в действительности равное просто0
. ПолеdwIoControlCode
находится по смещениюESI+12
. Убедившись, что там содержится0
, мы возвращаем управление, обнулив предварительноEAX
(это необходимо).- При вызове драйвера из программы мы используем номер
3
. Убедившись, что в полеdwIoControlCode
содержится3
, мы таким образом должны сделать то, что ждет от нас программа.- Собственно задача драйвера - вывести сообщение со строкой, полученной от программы. Известен адрес строки и ее длина. Чтобы продемонстрировать некоторые функции VXD-сервиса, мы еще раз определяем длину строки и копируем ее в буфер, подготовленный в теле драйвера.
- Наконец вывод сообщения и возвращение управления с обнулением содержимого
EAX
.Сделаем теперь некоторые пояснения к структуре
Client_Reg_Struc
.Client_Reg_Struc STRUC Client_EDI DD ? Client_ESI DD ? Client_EBP DD ? Client_res0 DD ? Client_EBX DD ? Client_EDX DD ? Client_ECX DD ? Client_EAX DD ? Client_Error DD ? Client_EIP DD ? Client_CS DW ? Client_res1 DW ? Client_EFlags DD ? Client_ESP DD ? Client_SS DW ? Client_res2 DW ? Client_ES DW ? Client_res3 DW ? Client_DS DW ? Client_res4 DW ? Client_FS DW ? Client_res5 DW ? Client_GS DW ? Client_res6 DW ? Client_Alt_EIP DD ? Client_Alt_CS DW ? Client_res7 DW ? Client_Alt_EFlags DD ? Client_Alt_ESP DD ? Client_Alt_SS DW ? Client_res8 DW ? Client_Alt_ES DW ? Client_res9 DW ? Client_Alt_DS DW ? Client_res10 DW ? Client_Alt_FS DW ? Client_res11 DW ? Client_Alt_GS DW ? Client_res12 DW ? Client_Reg_Struc ENDSРис. 4.7.6. Структура, содержащая значения регистров вызывающего приложения.
Пояснение к Рис. 4.7.6. Структура содержит три типа полей:
Client_resX
- зарезервированные поля.Client_XXX
- регистры программы, запускаемой в виртуальной машине.Client_Alt_XXX
- регистры 32-битной программы, запускаемой в системной виртуальной машине.На этом мы заканчиваем рассмотрение виртуальных драйверов.
58 При написании главы были использованы материалы с сайта http://win32asm.cjb.net