📄 vxd-c4.htm
字号:
face=Arial,Helvetica><FONT size=-1><B><FONT
color=#ffff99>FILE_FLAG_DELETE_ON_CLOSE</FONT></B><FONT color=#ffffff> 这个标志用来说明该VxD在</FONT><B><FONT
color=#ffff99>CreateFile</FONT></B><FONT color=#ffffff>返回的句柄关闭时被卸载。</FONT></FONT></FONT> <BR><FONT face=Arial,Helvetica><FONT size=-1><FONT
color=#ffffff>如果你用CreateFile来加载一个动态VxD,那么这个动态VxD</FONT><B><FONT color=#ffff99>必须</FONT></B><FONT color=#ffffff>处理</FONT><B><FONT color=#ffff99>w32_DeviceIoControl </FONT></B><FONT
color=#ffffff>消息。当你的动态VxD第一次被CreateFile函数加载的时候,</FONT><B><FONT color=#ffff99>VWIN32 </FONT></B><FONT
color=#ffffff>向你的VxD发出这个消息。你的VxD响应这个消息,返回时eax中的值必须为零。当应用程序调用<B><FONT
color=#ffff99>DeviceIoControl</FONT></B> API来与一个动态VxD通讯时,</FONT><B><FONT color=#ffff99>w32_DeviceIoControl</FONT></B><FONT
color=#ffffff>消息也被发送。我们会在下一章讲到<B><FONT
color=#ffff99>DeviceIoControl</FONT></B><FONT color=#ffffff>接口。</FONT></FONT></FONT> <BR><FONT face=Arial,Helvetica><FONT
color=#ffffff><FONT size=-1>一个动态VxD在初始化时收到一个消息:</FONT></FONT></FONT>
<UL>
<LI><B><FONT face=Arial,Helvetica><FONT color=#ffff99><FONT
size=-1>Sys_Dynamic_Device_Init</FONT></FONT></FONT></B> </LI></UL><FONT
face=Arial,Helvetica><FONT color=#ffffff><FONT size=-1>在结束时也收到一个控制消息:</FONT></FONT></FONT>
<UL>
<LI><B><FONT face=Arial,Helvetica><FONT color=#ffff99><FONT
size=-1>Sys_Dynamic_Device_Exit</FONT></FONT></FONT></B> </LI></UL><FONT
face=Arial,Helvetica><FONT size=-1><FONT color=#ffffff>动态VxD不会收到</FONT><B><FONT color=#ffff99>Sys_Critical_Init</FONT></B><FONT
color=#ffffff>, </FONT><B><FONT color=#ffff99>Device_Init</FONT></B><FONT
color=#ffffff>和</FONT><B><FONT color=#ffff99>Init_Complete</FONT></B><FONT
color=#ffffff>控制消息,因为这些消息是在系统虚拟机初始化时发送的。除了这三个消息,动态VxD能收到所有的控制消息,只要它还在内存里。它可以做静态VxD可以做的所有事情。简单的说,动态VxD除了加载机制和接收到的初始化/结束消息跟静态VxD不同以外,它能做静态VxD所能做的一切。</FONT></FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ffff><FONT size=+0>其它系统控制消息</FONT></FONT></FONT></H3><FONT face=Arial,Helvetica><FONT
color=#ffffff><FONT size=-1>当VxD在内存里的时候,除了接收和初始化及结束相关的消息外,它还要收到许多别的控制消息。有些消息是关于虚拟机管理器的,有的是关于各种事件的。例如,关于虚拟机的消息如下:</FONT></FONT></FONT>
<UL>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>Create_VM</FONT></FONT></FONT>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>VM_Critical_Init</FONT></FONT></FONT>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>VM_Suspend</FONT></FONT></FONT>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>VM_Resume</FONT></FONT></FONT>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>Close_VM_Notify</FONT></FONT></FONT>
<LI><FONT face=Arial,Helvetica><FONT color=#ffffff><FONT
size=-1>Destroy_VM</FONT></FONT></FONT> </LI></UL><FONT
face=Arial,Helvetica><FONT color=#ffffff><FONT size=-1>选择地响应你所感兴趣的消息是你自己的责任。</FONT></FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ffff><FONT size=+0>
在VxD内创建函数</FONT></FONT></FONT></H3><FONT face=Arial,Helvetica><FONT
color=#ffffff><FONT size=-1>你要在一个段里面定义你的函数。你应该首先定义一个段,然后把你的函数放进去。例如,如果你要把你的函数放到一个可调页段中。你应该先定义一个可调页段,像这样:</FONT></FONT></FONT>
<BLOCKQUOTE><B><FONT face=Arial,Helvetica><FONT color=#ffcc33><FONT
size=-1>VxD_PAGEABLE_CODE_SEG</FONT></FONT></FONT></B>
<P><B><FONT face=Arial,Helvetica><FONT color=#66ff99><FONT size=-1>(你的函数写在这里)</FONT></FONT></FONT></B>
<P><B><FONT face=Arial,Helvetica><FONT color=#ffcc33><FONT
size=-1>VxD_PAGEABLE_CODE_ENDS</FONT></FONT></FONT></B></P></BLOCKQUOTE><FONT
face=Arial,Helvetica><FONT size=-1>你可以在一个段里面插入多个的函数。作为一个VxD编写者,你必须决定每一个函数应该放到哪个段里面去。如果你的函数必须时刻存在于内存中,如某些硬件中断处理程序,就把它们放到锁定页面段里面,否则,你应该把它们放到可调页段。</FONT></FONT> <BR><FONT face=Arial,Helvetica><FONT
size=-1>你要用<B><FONT
color=#ffff99>BeginProc</FONT></B>和<B><FONT color=#ffff99>EndProc</FONT></B>
宏来定义你的函数:</FONT></FONT>
<BLOCKQUOTE><FONT face=Arial,Helvetica><FONT size=-1><B><FONT
color=#ffcc33>BeginProc </FONT></B><I>函数名</I></FONT></FONT>
<P><FONT face=Arial,Helvetica><FONT size=-1><B><FONT color=#ffcc33>EndProc
</FONT></B><I>函数名</I></FONT></FONT></P></BLOCKQUOTE><FONT
face=Arial,Helvetica><FONT size=-1>使用<B><FONT color=#ffff99>BeginProc</FONT></B> 宏还可以加上一些参数,想了解这些细节,你可以看看Win95 DDK的文档。大多数时候,你只用填写函数的名字就够了。</FONT></FONT> <BR><FONT face=Arial,Helvetica><FONT size=-1>因为<B><FONT color=#ffff99>BeginProc-EndProc </FONT></B>宏比<B><FONT color=#ffff99>proc-endp</FONT></B> 指令的功能要强,所以你应该用<B><FONT
color=#ffff99>BeginProc-EndProc</FONT></B>宏来代替<B><FONT color=#ffff99>proc-endp</FONT></B>指令</FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ffff><FONT size=+0>VxD编程约定</FONT></FONT></FONT></H3>
<H3><FONT face=Arial,Helvetica><FONT color=#66ff99><FONT size=-1>寄存器的使用</FONT></FONT></FONT></H3><FONT face=Arial,Helvetica><FONT
color=#ffffff><FONT size=-1>你的VxD程序可以使用所有的寄存器,FS和GS。但是在改动段寄存器的时候一定要小心。尤其是,一定不要改动CS和SS的内容,除非你对将发生的事情有绝对的把握。你可以使用DS和ES,但一定要记住在返回时恢复它们初值。有两个特征位尤其重要:方向和中断特征位。不要长时间的屏蔽中断。还有如果你要改动方向特征位,不要忘了在返回之前恢复它的初值。
</FONT></FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ff99><FONT
size=-1>参数传递约定</FONT></FONT></FONT></H3><FONT size=-1> VxD服务函数有两种调用约定:寄存器法和堆栈法。调用寄存器法服务函数时,你通过各种寄存器来传递服务函数的参数。并且,在调用完成后检查寄存器的值来看操作是否成功。不要总是以为在调用服务函数后主要寄存器的值还和以前一样。当调用堆栈法服务函数时,你把要传递的参数压栈,在eax得到返回值。堆栈调用法的服务函数保存ebx,esi,edi和ebp的值。许多寄存器调用法服务函数都源于Windows3.x的时代。在大多数时候,你可以通过名字来区分这两种服务函数,如果一个函数的名字一下划线开头,如</FONT><B><FONT size=-1><FONT
color=#ffff99>_HeapAllocate</FONT></font></B><FONT size=-1><FONT color=#ffffff>,它就是一个堆栈法的服务函数(除了少数从</FONT><B><FONT
color=#ffff99>VWIN32.VxD</FONT></B><FONT color=#ffffff>导出的函数)。如果函数名不是一下划线开头,它就是一个寄存器法的服务函数。</FONT></FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ff99><FONT size=-1>
调用VxD服务函数</FONT></FONT></FONT></H3><FONT face=Arial,Helvetica><FONT size=-1><FONT
color=#ffffff>你可以通过</FONT><B><FONT
color=#ffff99>VMMCall</FONT></B><FONT color=#ffffff>和</FONT><B><FONT
color=#ffff99>VxDCall </FONT></B><FONT color=#ffffff>宏来调用VMM和VxD服务。这两个宏的语法是一样的。当你要调用VMM导出的VxD服务函数时,用</FONT><B><FONT
color=#ffff99>VMMCall</FONT></B><FONT color=#ffffff>。当你要用其它VxD程序导出的VxD服务函数时,用</FONT><B><FONT
color=#ffff99>VxDCall</FONT></B><FONT color=#ffffff>。</FONT></FONT></FONT>
<BLOCKQUOTE><FONT face=Arial,Helvetica><FONT size=-1><B><FONT
color=#ffff99>VMMCall</FONT></B><FONT color=#ffffff> </FONT><B><FONT
color=#66ff99>service</FONT></B><FONT
color=#ffffff>
; 调用寄存器法服务函数e</FONT></FONT></FONT> <BR><FONT
face=Arial,Helvetica><FONT size=-1><B><FONT
color=#ffff99>VMMCall </FONT><FONT color=#66ff99> _service, <argument
list></FONT></B><FONT color=#ffffff> ; 调用堆栈法服务函数</FONT></FONT></FONT></BLOCKQUOTE><FONT
face=Arial,Helvetica><FONT size=-1>正如我在前面所讲的,<B><FONT
color=#ffff99>VMMCall</FONT></B><FONT color=#ffffff>和</FONT><B><FONT
color=#ffff99>VxDCall</FONT></B><FONT color=#ffffff>分解出一个跟着一个双字的20h中断,这样用起来很方便。
当你调用堆栈法服务时,你必须用角括号把你的参数列括起来。</FONT></FONT></FONT>
<BLOCKQUOTE><B><FONT face=Arial,Helvetica><FONT size=-1><FONT
color=#ffff99>VMMCall </FONT><FONT color=#ffffff> _HeapAllocate,
</FONT><FONT color=#66ff99><<size mybuffer>,
HeapLockedIfDP></FONT></FONT></FONT></B></BLOCKQUOTE><FONT
face=Arial,Helvetica><FONT size=-1><B><FONT
color=#ffff99>_HeapAllocate</FONT></B><FONT color=#ffffff>是一个堆栈法服务函数。它有两个参数,我们必须用角括号把它们括起来。由于第一个参数是一个这个宏不能正确解释的表达式,所以我们又要用一个角括号把它括起来。</FONT></FONT></FONT>
<H3><FONT face=Arial,Helvetica><FONT color=#66ff99><FONT size=-1>Flat地址</FONT></FONT></FONT></H3><FONT face=Arial,Helvetica><FONT
size=-1><FONT color=#ffffff>在老的编译工具里,当你使用</FONT><B><FONT color=#ffff99>offset
</FONT></B><FONT color=#ffffff>操作符时,编译器和联接器会生成错误地址,所以VxD编写者用</FONT><B><FONT
color=#ffff99>offset flat:</FONT></B><FONT color=#ffffff>来代替</FONT><B><FONT color=#ffff99>offset</FONT></B><FONT color=#ffffff>。imm.inc包括了一个使这更简单的宏:</FONT><B><FONT color=#ffff99>OFFSET32
</FONT></B><FONT color=#ffffff>来代替</FONT><B><FONT color=#ffff99>offset
flat:</FONT></B><FONT color=#ffffff>。所以如果你要用地址操作时,用</FONT><B><FONT color=#ffff99>OFFSET32</FONT></B><FONT color=#ffffff>
来代替offset操作符。</FONT></FONT></FONT><FONT face=Arial,Helvetica><FONT
color=#ffffff><FONT size=-1></FONT></FONT></FONT>
<P><FONT face=Arial,Helvetica><FONT size=-1><B><FONT
color=#66ffff>注意:</FONT></B><FONT color=#ffffff> 当我写这篇教程的时候,我试了一下用</FONT><B><FONT color=#ffff99>offset</FONT></B><FONT color=#ffffff>
操作符。它可以生成正确的地址。所以我想MASM6.14修正了这个bug。但是为了安全起见,你还是应该用</FONT><B><FONT color=#ffff99>OFFSET32</FONT></B><FONT color=#ffffff>宏来代替</FONT><B><FONT color=#ffff99>offset</FONT></B><FONT
color=#ffffff>。</FONT></FONT></FONT> <BR>
<hr size="1">
<div align="center">
<script language="JavaScript1.1" src=http://ad.t2t2.com/textclick.asp?user=bigluo&style=4&bkcolor=no></script>
<br>
</div>
<!-- 10:1 文本广告交换 -->
<div align="center">
<script language="JavaScript1.1" src=http://coolsite21.com:90/c21.dll?Type=PT&id=1047&col=6&ReferID=1047&v=0></script>
<!-- 10:1 文本广告交换 --> </div>
<hr size="1">
<br>
<div align="center"> 由 Ryo 翻译,发表于 <a href="http://asm.yeah.net">http://asm.yeah.net</a>,英文版本来自
[<a href="http://win32asm.cjb.net/">Iczelion's Win32 Assembly Homepage</a>]
</div>
<CENTER></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -