ITEEDU

第1章 Iczelion的Win32汇编教程

第2章 Iczelion的ODBC教程

第3章 Iczelion的VxD教程

第4章 Iczelion的PE教程

第5章 罗云彬的Win32汇编教程

第6章 Win32ASM经验点滴

第7章 X86汇编语言编程

第8章 加密解密

第9章 病毒的分析和防治

VxD例程:消息框

在上一节教程里,我们讲了编写一个VxD程序的方法。现在我们要学以致用。 在这一节里,我们要编写一个静态VxD,这个静态VxD在一个虚拟机创建或销毁时就会弹出一个消息框。

捕获虚拟机创建和结束事件

当一个虚拟机创建时,VMM发送Create_VM控制消息给所有的VxD程序。当一个虚拟机退出时,它也发送VM_Terminate和VM_Terminate2消息给所有的VxD程序。
我们的工作很简单:在设备控制程序里处理Create_VM and VM_Terminate2消息。
当我们的VxD程序收到这两个控制消息时,它在屏幕上弹出一个消息框。 当VxD程序收到Create_VM或者 VM_Terminate2消息时,该虚拟机的句柄保存在ebx中。一个虚拟记的句柄可以看作它的唯一的ID。
每一个虚拟机都有它自己唯一的ID(虚拟机句柄)。你可以像使用进程ID一样使用虚拟机ID:调用函数时,把它当作参数传送。
更进一步的来看,一个虚拟机句柄实际上是一个指向虚拟机控制块(VMCB)的32位线性地址。
一个虚拟机控制块是一个包括了许多关于该虚拟机的重要属性的结构。它的定义如下:

        CB_S  STRUC
            CB_VM_STATUS  DD        ?
          CB_HIGH_LINEAR  DD        ?
       CB_CLIENT_POINTER  DD        ?
     CB_VMID  DD        ?
            CB_SIGNATURE  DD        ?
        CB_S  ENDS
  • CB_VM_Status 包含了反映虚拟机状态的一些标志位。
  • CB_High_Linear 是一个指向在系统共享区(约3GB)的虚拟机镜像的一个线性地址。这个概念需要解释一下。
    在Window95下,一个VxD不能直接访问到V86区域,代替地,VMM把每个虚拟机的V86区域都映射到系统共享区。
    当一个VxD程序要访问或修改虚拟机中的V86区时,它就在虚拟机的高线性区域进行操作。例如,如果显存的地址是0B8000H,而你的VxD程序要访问这个区域。
    它就要把CB_High_Linear中的值上0B8000H,然后访问那个区域。你在高线性镜像区域所作的修改都会被保存到虚拟机中去,因为这两个区域共享一个页面目录入口。
    使用高线性镜像在它多数情况下非常有效,因为你甚至可以修改一个不是当前虚拟机的虚拟机。
  • CB_Client_Pointer 包含了客户寄存器结构的地址。一个客户寄存器结构包含了在一个虚拟机中被中断的V86或保护模式程序的所有寄存器的值。
    如果你的VxD程序要读取/改动V86或PM程序的状态,它可以改动客户寄存器结构里的值,当VMM返回执行该程序时,这些改动会被保存到程序里去。
  • CB_VMID 虚拟机的身份验证数字。当VMM创建一个虚拟机时,就给该虚拟机分配一个数字。系统虚拟机的VMID是1。
  • CB_Signature 包含字串“VMcb”。这个元素是用来检测虚拟机句柄是否有效的。
  • 显示一个对话框

    一个VxD程序可以通过Virtual Shell Device服务来同用户通讯。在这个例子里我们要用到其中的一个:SHELL_Message.
    SHEll_Message是一个寄存器法的服务函数,通过寄存器来传送参数:
  • ebx 显示这个消息的虚拟机的句柄。
  • eax 消息框的标志位。你可以在shell.inc中查查它们的详细信息,它们都是以MB_开头的。
  • ecx 要显示的消息的32位线性地址。
  • edi 消息框的标题的32位线性地址。
  • esi 如果你要知道用户对你的消息框作的反应操作,就在这里填写返回函数的32位线性地址。如果你不想知道,就用NULL。
  • edx 用来传送你的返回函数所需要的参数(如果你在esi中填了这个函数的地址)。
  • 返回后,如果调用成功,返回标志被清零,否则,返回标志被置位。

    例子:

    .386P
         INCLUDE  VMM.INC
         INCLUDE  SHELL.INC DECLARE_VIRTUAL_DEVICE MESSAGE,1,0, MESSAGE_CONTROL, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
    
    Begin_control_dispatch MESSAGE 
    Control_Dispatch Create_VM, OnVMCreate 
    Control_Dispatch VM_Terminate2, OnVMClose 
    End_control_dispatch MESSAGE 
    
    VxD_PAGEABLE_DATA_SEG 
        MSGTITLE  DB        "VXD MESSAGEBOX",0
       VMCREATED  DB        "A VM IS CREATED",0
     VMDESTROYED  DB        "A VM IS DESTROYED",0
    VxD_PAGEABLE_DATA_ENDS 
    
    VxD_PAGEABLE_CODE_SEG 
    BeginProc OnVMCreate 
                  MOV       ECX, OFFSET32 VMCREATED
     COMMONCODE:
    VMMCall Get_sys_vm_handle 
                  MOV       EAX,MB_OK+MB_ICONEXCLAMATION
                  MOV       EDI, OFFSET32 MSGTITLE
                  XOR       ESI,ESI
                  XOR       EDX,EDX
    VxDCall SHELL_Message 
                  RET
    EndProc OnVMCreate 
    
    BeginProc OnVMClose 
                  MOV       ECX,OFFSET32 VMDESTROYED
                  JMP       COMMONCODE
    EndProc OnVMClose 
    VxD_PAGEABLE_CODE_ENDS 
    
                  END
    
    
    
           分析:
    
    Begin_control_dispatch MESSAGE 
    Control_Dispatch Create_VM, OnVMCreate 
    Control_Dispatch VM_Terminate2, OnVMClose 
    End_control_dispatch MESSAGE
    
    此VxD程序处理两个控制消息,Create_VM和VM_Terminate2当收到Create_VM 控制消息时,它调用OnVMCreate函数。当收到VM_Terminate2 消息时,它调用
    OnVMClose 函数。 
    VxD_PAGEABLE_DATA_SEG 
        MSGTITLE  DB        "VXD MESSAGEBOX",0
       VMCREATED  DB        "A VM IS CREATED",0
     VMDESTROYED  DB        "A VM IS DESTROYED",0
    VxD_PAGEABLE_DATA_ENDS
    
    我们把这些数据放在可调页段里面。 BeginProc OnVMCreate 
                  MOV       ECX, OFFSET32 VMCREATED
     COMMONCODE:
    VMMCall Get_sys_vm_handle 
                  MOV       EAX,MB_OK+MB_ICONEXCLAMATION
                  MOV       EDI, OFFSET32 MSGTITLE
                  XOR       ESI,ESI
                  XOR       EDX,EDX
    VxDCall SHELL_Message 
                  RET
    EndProc OnVMCreate
    我们用BeginProc和 EndProc宏来创建OnVMCreate。OnVMCreate函数把调用SHELL_Message服务所需要的参数放到寄存器里面去。
    因为我们要在系统虚拟机上显示消息框,所以不能使用ebx中的值(ebx包含了在创建的虚拟机的句柄,而我们要的是系统虚拟机的句柄)。
    于是,我们用另一个VMM服务,Get_Sys_VM_Handle来得到系统虚拟机的虚拟机句柄。我们分别把消息的地址和消息框标题的地址放在ecx和edi里面。
    我们不需要知道客户的反应,所以我们把esi和edx置零。当每个参数都在相应的寄存器内后,我们就调用 SHELL_Message 来显示消息框。
    BeginProc OnVMClose 
                  MOV       ECX,OFFSET32 VMDESTROYED
                  JMP       COMMONCODE
    EndProc OnVMClose
    OnVMCloseOnVMClose函数本身是很简单的。因为它要使用的代码和OnVMCreate相同,所以它在用另一个消息的地址初始化ecx后,就转到OnVMCreate中的代码去了。

    改变定义文件(.def)

    VxD MESSAGE
    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 
    
    MESSAGE_DDB @1
    汇编过程:
    ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 message.asm link -VxD -def:message.def message.obj 
    VxD 的安装:
  • 把message.VxD放到\system目录下。
  • 在system.ini文件里的[386enh]部分里加上如下的一行:
    device=message.VxD 
  • 重启你的计算机。
  • 测试这个VxD:

    打开一dos窗口,你会看到弹出的消息框,显示“A VM is created."。当你关闭一个dos窗口,又会弹出一个消息框显示“A VM is destroyed"。