Iczelion 的 Win32Asm VxD 汇编教程 (六)

原创 2002年02月14日 10:44:00

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将会创建/加再到内存中并且CreateFileVxD的句柄返回到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         lpOutBufferVxD程序在操作成功之后要将输出数据输出到的缓冲区。如果这个操作没有任何返回值,这个值可以为NULL

l         nOutBufferSizelpOutBuffer所指向的缓冲区的大小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的大小传给nInBufferSizeInBuffer是一个包括两个元素的数组:每个元素都是一个字符串的地址。

 

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_Openeas中返回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来计算消息框标题的长度lstrleneax中返回字符串的长度。我们把这个长度加1来包括结束标记NULL。下一步我们通过调用HeapAllocate来分配一块足够大可以容纳字符串和它的结束标记NULL内存。加上HEAPZEROINIT标记使HeapAllocate将这块内存清零HeapAllocateeax中返回这块内存的地址。我们然后从win32 app的地址空间把字符串拷贝到我们申请的内存中。我们对要做消息框文本的字符串做同样的操作。

 

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

 

我们把标题和文本的地址分别存在ediecx中。把想要的标记放在eax中,通过调用Get_Sys_VM_handle得到系统VMVM 句柄。然后调用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扩展非常理想。

 

Windows.设备驱动程序(VxD与WDM)开发实务.pdf

  • 2010年03月27日 20:49
  • 12.33MB
  • 下载

Win32Asm 教程(一)

前一章 目录 后一章 1.0-介绍汇编语言 汇编语言是创造出来代替原始的只能由处理器理解的二进制代码的。很久以前,尚没 有任何高级语言,程序都是用汇编写的。汇编代码直接描述处理器可以执行的...
  • gemgin
  • gemgin
  • 2013年06月13日 14:32
  • 403

win32汇编动态链接库的编写及使用

以前安装程序的时候,在安装目录下总会发现 好多的以.DLL结尾的文件,这些是什么玩意儿?有什么用?而且有时候运行程序的时候还会出现“无法定位程序输入点...与动态链接库....上”这种错误,现在想起来...
  • qq_22642239
  • qq_22642239
  • 2016年05月30日 21:53
  • 4369

图解RadASM使用初步

RadASM是一个主要用于Win32汇编的开发工具,也有对其他语言的支持; 此工具提供的方便相当多; 1 安装 2 自带例...
  • bcbobo21cn
  • bcbobo21cn
  • 2016年05月18日 11:31
  • 3703

Win32Asm 教程(二)

前一章 目录 后一章 1.0-介绍汇编语言 汇编语言是创造出来代替原始的只能由处理器理解的二进制代码的。很久以前,尚没 有任何高级语言,程序都是用汇编写的。汇编代码直接描述处理器可以执行的...
  • gemgin
  • gemgin
  • 2013年06月13日 14:32
  • 463

Win32Asm教程(基础篇)

来源: http://www.dav1d.org  原作者:taowen  发布者:Sunlion [E.S.T] http://evilsun.126.com  一篇很不错的教程,本来是放在我...
  • s98
  • s98
  • 2013年05月06日 19:02
  • 726

小波变换教程(六)

小波变换网文精粹:小波变换教程(六) 原文:ROBI POLIKAR. THE ENGINEER'S ULTIMATE GUIDE TO WAVELET ANALYSIS:The Wavelet...
  • alihouzi
  • alihouzi
  • 2015年04月22日 09:19
  • 1124

汇编语言--ARM汇编

ARM汇编指令总结目的总结目的是为了看懂ARM返汇编程序含义。如果是抱着来看这篇blog的盆友,希望可以帮到你们;如果有错误,请多指出。谢谢!#ARM指令的一般格式arm指令字长为固定的32位。一条典...
  • daiyibo123
  • daiyibo123
  • 2015年12月09日 19:30
  • 2895

asm基础——使用nasm和bochs学习汇编

使用nasm得到二进制并使用boch来调试。
  • jiangwei0512
  • jiangwei0512
  • 2016年01月27日 22:32
  • 1424

asm基础——使用nasm进行汇编(基础)

asm基础——使用nasm进行汇编(基础)
  • jiangwei0512
  • jiangwei0512
  • 2016年03月11日 23:32
  • 2713
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Iczelion 的 Win32Asm VxD 汇编教程 (六)
举报原因:
原因补充:

(最多只允许输入30个字)