程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編DeviceIoControl接口詳解

匯編DeviceIoControl接口詳解

編輯:匯編語言

在這一節中我們將要關於學習動態VXD,特別是如何創建,加載和使用。

VxD接口

VxD總共提供了4種接口。

l VxD services VxD服務

l V86 Interface V86接口

l Protected-mode (PM) Interface 保護模式接口

l Win32 DeviceIoControl Interface Win32設備輸入輸出控制接口

我們已經知道了VxD服務,V86和保護模式接口是由V86和保護模式程序調用的。因為V86和保護模式程序是16位的,我們不能在Win32應用程序中使用那兩種接口。在Windows 95中,微軟給Win32應用程序加了另外一個接口所以Win32應用程序可以調用VxD的服務:DeviceIoControl接口(設備輸入輸出控制接口)

DeviceIoControl接口

簡單的說,DeviceIoControl接口是一種為Win32程序准備的調用VxD內部函數的方法。不要混淆DeviceIoControl接口調用函數和用VxD服務調用函數,這兩種方法是不一樣的。比如說,DeviceIoControl function1 也許和Vxd service1是不一樣的。你應給把DeviceIoControl函數作為一種只為Win32應用程序提供的單獨的函數。

在Win32程序方面:

首先用CreateFile來打開/加載一個VxD。如果調用成功的話,VxD將會創建/加再到內存中並且CreateFile把VxD的句柄返回到eax中。

接著你調用DeviceIoControlAPI函數來選擇要運行的函數。DeviceIoControl函數遵循下面的語法:

DeviceIoControl PROTO hDevice:DWORD,\

dwIoControlCode:DWORD,\

lpInBuffer:DWORD,\

nInBufferSize:DWORD,\

lpOutBuffer:DWORD,\

nOutBufferSize:DWORD,\

lpBytesReturned:DWORD,\

lpOverlapped:DWORD

l hDevice 是從CreateFile返回的VxD句柄。
   l dwIoControlCode是用來制定VxD將要進行的操作。你應該在你要選用那種操作之前得到可能的dwIoControlCode值得列表。

l lpInBuffer是包含了VxD完成dwIoControlCode所制定操作的數據的緩沖區地址。如果這個操作不需要數據,你可以傳為NULL。

l nInBufferSize是由lpInBuffer所指向的緩沖區的地址的大小(byte)。

l lpOutBuffer是VxD程序在操作成功之後要將輸出數據輸出到的緩沖區。如果這個操作沒有任何返回值,這個值可以為NULL。

l nOutBufferSize是lpOutBuffer所指向的緩沖區的大小(byte)。

l lpBytesReturned是一個dword型變量的地址。這個變量用來接收VxD在lpOutBuffer中寫入數據的大小。

l 如果你想要把操作設成異步的,lpOverlapped是一個OVERLAPPED結構的指針。如果你要一直等直到操作完成,這個值為NULL。

在VxD方面:

VxD程序必須處理w32_deviceIoControl消息。當VxD收到w32_deviceIoControl消息,它的寄存器是如下值:

l ebx 是VM的句柄。

l esi 是指向DIOCParams結構的指針。DIOCParams包含了從win32程序傳送的信息。

DIOCParams是按照如下定義的:

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

l Internal1 是指向Win32應用應用程序用戶寄存器結構的指針。

l VMHandle 虛擬機句柄

l Internal2 是指向設備描述塊(DDB)的句柄。
   l dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped是傳送到DeviceIoControl API的參數。

l hDevice是 ring-3級設備句柄。

l tagProces 是過程的標簽。

在DIOCParams結構中有所有從Win32應用程序傳送到你的VxD的信息。

你的VxD至少要處理DIOC_Open(傳送到dwIoControlCode),那是當Win32程序調用CreateFile打開你的VxD時VWIN32發送給你的VxD的。如果你的VxD准備好了,它必須在eax中返回0而且CreateFile也會成功。如果你的VxD沒有准備好,它必須在eas中返回一個非零值而且CreateFile也會失敗。除了DIOC_Open,當Win32程序關閉這個設備句柄時,你的VxD將會從VWIN32收到DIOC_Closehandle。

能由CreateFile加載的最小的動態VxD框架:

.386p
include vmm.inc
include vwin32.inc
DECLARE_VIRTUAL_DEVICE DYNAVXD,1,0, DYNAVXD_Control,\
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_control_dispatch DYNAVXD
Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
End_control_dispatch DYNAVXD
VxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax
.endif
ret
EndProc OnDeviceIoControl
VxD_PAGEABLE_CODE_ENDS
end
;--------------------------------------------------------------------------------------------------------------------------------
; Module Definition File
;---------------------------------------------------------------------------------------------------------------------------------
VXD DYNAVXD DYNAMIC
SEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LMGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_LMSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PMSGTABLE CLASS 'MCODE' NONDISCARDABLE IOPL
_PMSGDATA CLASS 'MCODE' NONDISCARDABLE IOPL
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'
EXPORTS
DYNAVXD_DDB @1

完整例子:

下面是一段加載動態VxD並且通過DeviceIoControl API 來調用VxD內部函數的Win32應用程序的源代碼。

; VxDLoader.asm
.386
.model flat,stdcall
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
AppName db "DeviceIoControl",0
VxDName db "\\.\shellmsg.vxd",0
Success db "The VxD is successfully loaded!",0
Failure db "The VxD is not loaded!",0
Unload db "The VxD is now unloaded!",0
MsgTitle db "DeviceIoControl Example",0
MsgText db "I'm called from a VxD!",0
InBuffer dd offset MsgTitle
dd offset MsgText
.data?
hVxD dd ?
.code
start:
invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
.if eax!=INVALID_HANDLE_VALUE
mov hVxD,eax
invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATION
invoke DeviceIoControl,hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
invoke CloseHandle,hVxD
invoke MessageBox,NULL,addr Unload,addr AppName,MB_OK+MB_ICONINFORMATION
.else
invoke MessageBox,NULL,addr Failure,NULL,MB_OK+MB_ICONERROR
.endif
invoke ExitProcess,NULL
end start

下面這段源代碼是由 vxdloader.asm 調用的動態VxD。
; ShellMsg.asm
.386p
include vmm.inc
include vwin32.inc
include shell.inc
DECLARE_VIRTUAL_DEVICE SHELLMSG,1,0, SHELLMSG_Control,\
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_control_dispatch SHELLMSG
Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
End_control_dispatch SHELLMSG
VxD_PAGEABLE_DATA_SEG
pTitle dd ?
pMessage dd ?
VxD_PAGEABLE_DATA_ENDS
VxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax
.elseif [esi].dwIoControlCode==1
mov edi,[esi].lpvInBuffer
;-----------------------------------
; copy the message title to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pTitle,eax
pop eax
VMMCall _lstrcpyn,<pTitle,[edi],eax>
;-----------------------------------
; copy the message text to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi+4]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pMessage,eax
pop eax
VMMCall _lstrcpyn,<pMessage,[edi+4],eax>
mov edi,pTitle
mov ecx,pMessage
mov eax,MB_OK
VMMCall Get_Sys_VM_Handle
VxDCall SHELL_sysmodal_Message
VMMCall _HeapFree,pTitle,0
VMMCall _HeapFree,pMessage,0
xor eax,eax
.endif
ret
EndProc OnDeviceIoControl
VxD_PAGEABLE_CODE_ENDS
end
  分析:

我們從VxDLoader.asm開始。

Invoke CreateFile,addrVxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
.if eax!=INVALID_HANDLE_VALUE
mov hVxD,eax
....
.else
invoke MessageBox,NULL,addr Failure,NULL,MB_OK+MB_ICONERROR
.endif

我們調用CreateFile來加載動態VxD。注意FILE_FLAG_DELETE_ON_CLOSE標記。當從CreateFile返回的VxD句柄被關閉的時候,這個標志通知Windows卸載VxD。如果CreateFile成功,我們把VxD句柄保存起來。

invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATION
invoke DeviceIoControl,hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
invoke CloseHandle,hVxD
invoke MessageBox,NULL,addr Unload,addr AppName,MB_OK+MB_ICONINFORMATION

當VxD加載/卸載的時候,這個程序會顯示一個消息框。它令dwIoControlCode=1然後調用DeviceIoControl。將InBuffer的地址傳給lpInBuffer,將InBuffer的大小傳給nInBufferSize。InBuffer是一個包括兩個元素的數組:每個元素都是一個字符串的地址。

MsgTitle db "DeviceIoControl Example",0
MsgText db "I'm called from a VxD!",0
InBuffer dd offset MsgTitle
dd offset MsgText

現在我們看一下這段VxD。

它只處理w32_deviceIoControl消息。當w32_deviceIoControl消息發送的時候,調用OnDeviceIoControl函數。

BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax

OnDeviceIoControl 處理DIOC_Open,再eas中返回0。

.elseif [esi].dwIoControlCode==1
mov edi,[esi].lpvInBuffer

它也處理control code 等於1。它做的第一件事是取出在lpyInBuffer中的數據。這個數據是傳送到DeviceIoControl API 的lpInBuffer中的兩個dword值。它把指向dword數組的地址放到edi中。第一個dword是作為消息框標題的字符串地址。第二個dword是作為消息框文本的字符串地址。

;-----------------------------------
; copy the message title to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pTitle,eax
pop eax
VMMCall _lstrcpyn,<pTitle,[edi],eax>

它調用VMM服務lstrlen來計算消息框標題的長度。lstrlen在eax中返回字符串的長度。我們把這個長度加1來包括結束標記NULL。下一步我們通過調用HeapAllocate來分配一塊足夠大可以容納字符串和它的結束標記NULL內存。加上HEAPZEROINIT標記使HeapAllocate將這塊內存清零。HeapAllocate在eax中返回這塊內存的地址。我們然後從win32 app的地址空間把字符串拷貝到我們申請的內存中。我們對要做消息框文本的字符串做同樣的操作。

mov edi,pTitle
mov ecx,pMessage
mov eax,MB_OK
VMMCall Get_Sys_VM_Handle
VxDCall SHELL_sysmodal_Message

我們把標題和文本的地址分別存在edi和ecx中。把想要的標記放在eax中,通過調用Get_Sys_VM_handle得到系統VM的VM 句柄。然後調用SHELL_sysbodal_Message 。SHELL_sysModal_Message是系統SHELL_Message的模式版本。它凍結系統直到用戶對消息框做出反應。

VMMCall _HeapFree,pTitle,0
VMMCall _HeapFree,pMessage,0

當SHELL_sysmodal_Message返回時,我們用_HeapFree釋放內存。

總結:

DeviceIoControl接口使你的win32應用程序使用動態VxD作為一個ring-0 DLL擴展非常理想。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved