分享
 
 
 

iczelion Vxd tut3

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Virtual Device Driver SkeletonNow that you know something about VMM and VxD, we can learn how to code a VxD. You need Windows 95/98 Device Driver Development Kit. It's essential that you have it. Windows 95 DDK is available only to MSDN subscribers. However, Windows 98 DDK is available free of charge from Microsoft. You can also use Windows 98 DDK to develop VxDs even if it is oriented toward WDM. You can download Windows 98 DDK from http://www.microsoft.com/hwdev/ddk/install98ddk.htm?

You can download the whole package, about 30 MBs or you can selectively download only the parts you're interested in. If you choose not to download the whole package, don't forget to download the Windows 95 DDK documentation included in other.exe

Windows 98 DDK contains MASM version 6.11d. You should upgrade it to the latest version. For the information about where to download the latest version upgrade, check my main page.

Windows 9x DDK contains several essential include files which are not included in MASM32 package.

You can download the example in this tutorial here.

LE File FormatVxD uses linear executable (LE) file format. This is the file format designed for OS/2 version 2.0. It can contain both 16- and 32-bit code which is one of the requirement of VxDs. Remember that VxDs date back from the days of Windows 3.x. During that time, Windows boots from DOS so VxDs may need to do some initialization in real mode before Windows switches the machine into protected mode. Real-mode 16-bit code must be in the same executable file as the 32-bit protected mode code. So LE file format is the logical choice. Windows NT drivers blissfully don't have to deal with real mode initialization so they don't have to use LE file format. Instead they use PE file format.

Code and data in an LE file are stored in segments with different runtime attributes. Below are the available segment classes.

LCODE Page-locked code and data. This segment is locked into memory. In other words, this segment will not be paged to disk, thus you should use this segment class judiciously so as not to waste precious system memory. Code and data that must be present in memory at all time should be in this segment. Especially the hardware interrupt handlers.

PCODE Pageable code. This segment is pageable by VMM. Code in this segment needs not be present in memory all the time. VMM will page this segment to disk if it needs physical memory.

PDATA Pageable data.

ICODE Initialization-only code. The code in this segment is used during initialization of the VxD only. After initialization, this segment will be discarded by VMM to reclaim physical memory.

DBOCODE debug-only code and data. The code and data in this segment is used when you run the VxD under a debugger. It contains the handler for Debug_Query control message, for example.

SCODE Static code and data. This segment will always be present in memory even when the VxD is unloaded. This segment is especially useful for dynamic VxD when it must be loaded/unloaded many times during a Window session and wants to remember the last configuration/state.

RCODE Real-mode initialization code and data. This segment contains the 16-bit code and data for real mode initialization.

16ICODE USE16 protected-mode initialization data. This segment is a 16-bit one which contains the code that the VxD will copy from protected mode to V86 mode. For example, if you want to paste some V86 code into a VM, the code you intend to paste must be in this segment. If you put the code in other segment, the assembler will generate wrong code, i.e. it will generate 32-bit code instead of the intended 16-bit one.

MCODE Locked message strings. This segment contains message strings which are compiled with the help of VMM message macros. This helps you create international versions of your driver. It doesn't mean your VxD must have ALL those segments. You can choose the segments you want to use in your VxD. For example, if your VxD doesn't have real-mode initialization, it doesn't have to have RCODE segment.

Most of the time, you would use LCODE, PCODE and PDATA. It's your judgement as a VxD writer to choose the appropriate segments for your code/data. In general, you should use PCODE and PDATA as much as possible because VMM can page the segments in and out of memory if necessary. You should use LCODE to store hardware interrupt handlers and services that will be called by hardware interrupt handlers.

You don't use those segment classes directly. You must declare segments based on those classes. Those segment declarations are stored in the module definition file (.def). The full-scale module definition file for a VxD is below:

VXD FIRSTVXD

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

FIRSTVXD_DDB @1The first statement is for declaration of the VxD name. The name of a VxD MUST be all uppercase. I experimented with the lowercase name, and the VxD refused to perform anything except loading itself into memory.

Next are the segment declarations. The declaration consists of three parts: the name of the segment, the segment class and the desired runtime property of the segment. You can see that there are many segments based on the same class, for example, _LPTEXT, _LTEXT, _LDATA are all based on LCODE segment class with exactly the same properties. These segments are declared to make coding easier to understand. For example, LCODE can contain both code and data. It'll be easier on the programmer if he can store the data in _LDATA segment and the code in _LTEXT segment. Eventually, both segments will be combined into only one segment in the final executable file.

A VxD exports one and only one symbol, its device descriptor block (DDB). The DDB is actually a structure which contains everything VMM needs to know about a VxD. You MUST export the DDB in the module definition file.

Most of the time, you can use the above .DEF file in new VxD projects. You would have to change only the name of the VxD in the first and the last lines of the .DEF file. The segment declarations are overkills for an asm VxD project. They are for use by a C VxD project but using them in an asm project is ok. You'll get a lot of warning messages but it will assemble. You can get rid of the annoying warning messages by deleting the segment declarations you don't use in your project.

vmm.inc contains many macros for declaring segments in your source file.

_LTEXT

VxD_LOCKED_CODE_SEG

_PTEXT

VxD_PAGEABLE_CODE_SEG

_DBOCODE

VxD_DEBUG_ONLY_CODE_SEG

_ITEXT

VxD_INIT_CODE_SEG

_LDATA

VxD_LOCKED_DATA_SEG

_IDATA

VxD_IDATA_SEG

_PDATA

VxD_PAGEABLE_DATA_SEG

_STEXT

VxD_STATIC_CODE_SEG

_SDATA

VxD_STATIC_DATA_SEG

_DBODATA

VxD_DEBUG_ONLY_DATA_SEG

_16ICODE

VxD_16BIT_INIT_SEG

_RCODE

VxD_REAL_INIT_SEG

Each macro has its ending counterpart. For example, if you want to declare an _LTEXT segment in your source file, you would do it like this:

VxD_LOCKED_CODE_SEG

<put your code here>

VxD_LOCKED_CODE_ENDS

VxD SkeletonNow that you know about segments in LE file, we can go on to the source file. One thing you can observe about VxD programming is the heavy use of macros. You will find macros everywhere in VxD programming. It takes some getting used to. Those macros are provided to hide some gory details from programmers and in some ways, make the source code more portable. If you are curious, you can read the definition of those macros in various include files such as vmm.inc.

Here is the VxD skeleton source code:

.386p

include vmm.inc

DECLARE_VIRTUAL_DEVICE FIRSTVXD,1,0, FIRSTVXD_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

Begin_control_dispatch FIRSTVXD

End_control_dispatch FIRSTVXD

end

At first glance, the source code doesn't look like an asm source code. That's because of the use of macros. Let's analyze this source code and you'll soon understand it.

.386pTell the assembler that we want to use 80386 instruction set including the privileged CPU instructions. You can also use .486p or .586p.

include vmm.incYou must include vmm.inc in every VxD source code because it contains the definitions of the macros you use in the source file. You can include other include files as needed.

DECLARE_VIRTUAL_DEVICE FIRSTVXD,1,0, FIRSTVXD_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDERAs stated previously, the VMM learns everything it needs to know about a VxD from the VxD's device descriptor block (DDB). A device descriptor block is a structure that contains vital information about the VxD such as the VxD's name, its device ID, the entrypoints of its VxD services (if exist) and so on. You can look up this structure in vmm.inc. It's declared as VxD_Desc_Block. You'll export this structure in .DEF file. There are 22 members in this structure, but you'll usually need to fill only some of them. So vmm.inc contains a macro that will initialize and fill the structure members for you. That macro is DECLARE_VIRTUAL_DEVICE. It has the following format:

Declare_Virtual_Device Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData

One thing you can observe is that, the labels in VxD source code is case-insensitive. You can use upper- or lowercase characters or combination of them. Let's examine each parameter of Declare_virtual_device.

Name The name of the VxD. Maximum length is 8 characters. It MUST be uppercase. The name should be unique among the VxDs in the system. The macro also uses the name to create the name of the DDB by appending _DDB to the device name. So if you use FIRSTVXD as the name of the VxD, Declare_Virtual_Device macro will declare the name of the DDB as FIRSTVXD_DDB. Remember that, you will also have to export the DDB in .DEF file too. You have to match the label in the source file with the one in the .DEF file.

MajorVer and MinorVer The major and minor versions of your VxD

CtrlProc The name of the device control procedure for your VxD. A device control procedure is a function that receives and processes control messages for a VxD. You can think of a device control procedure as the window procedure equivalence. Since we will use Begin_Control_Dispatch macro to create our device control procedure, we should use the standard name which is in the form of VxDName_Control. Begin_Control_Dispatch macro appends _Control to the name passed to it ( and we usually pass the name of the VxD to it) so we should specify the name of our VxD appended by _Control in CtrlProc parameter.

DeviceID The 16-bit unique identifier of your VxD. You need the ID if and only if your VxD must handle one of the situations below

Your VxD exports VxD services for other VxDs to use. Since int 20h interface uses the device ID to locate/identify the VxD, it's imperative that your VxD must have a unique identifier.

Your VxD broadcasts your existence to real-mode applications during initialization with int 2Fh function 1607h.

Some real-mode software (TSR) will use int 2Fh, function 1605h to load your VxD. If your VxD doesn't need a unique device ID, you can specify UNDEFINED_DEVICE_ID in this field. If you do need a unique ID, you have to ask Microsoft for one

InitOrder Initialization order, or in short, load order. VMM loads VxDs in the order specified. Each VxD will have a load order number. For example,

VMM_INIT_ORDER EQU 000000000H

DEBUG_INIT_ORDER EQU 000000000H

DEBUGCMD_INIT_ORDER EQU 000000000H

PERF_INIT_ORDER EQU 000900000H

APM_INIT_ORDER EQU 001000000H

You can see that VMM, DEBUG and DEBUGCMD are the first VxDs that are loaded, followed by PERF and APM. The VxD with lower value of initialization order is loaded first. If your VxD requires the services of other VxD during initialization, you should specify an initialization order value that is larger than that of the VxD you want to call so that by the time your VxD is loaded, that VxD is already there in memory, ready for you. If your VxD doesn't care about initialization order, specify UNDEFINED_INIT_ORDER in this parameter.

V86Proc and PMProc Your VxD can export API for use by V86 and protected-mode programs. V86Proc and PMProc specify the addresses of those API. Remember that, VxDs exist primarily for supervising VMs and a VM other than the system VM runs a DOS or protected-mode application. It stands to reason for VxDs to provide API support for DOS and protected-mode programs. If you don't export those API, you can omit these fields.

RefData Reference data used by Input Output Supervisor (IOS). The only occasion you would use this field is when you code a layer block driver for use with IOS. You can omit this field if your VxD is not a layer driver. Next we have Begin_Control_Dispatch macro.

Begin_control_dispatch FIRSTVXD

End_control_dispatch FIRSTVXDThis macro and its counterpart define the device control procedure which is the function that VMM calls when there are control messages for your VxD. You must specify the first half of the name of the device control procedure, in our example we use FIRSTVXD. The macro will append _Control to the name you supplied.This name must match the one you specify in CtrlProc parameter of Declare_virtual_device macro. The device control procedure is always in a locked segment (VxD_LOCKED_CODE_SEG). The above device control procedure does nothing. You have to specify what control messages your VxD is interested in handling and the functions that will handle them. You use Control_Dispatch macro for this purpose.

Control_Dispatch message, functionFor example, if your VxD processes only Device_Init message, your device control procedure would look like this:

Begin_Control_Dispatch FIRSTVXD

Control_Dispatch Device_Init, OnDeviceInit

End_Control_DispatchFIRSTVXDOnDeviceInit is the name of the function that will handle Device_Init message. You can name your function anything you like.

You end the VxD source code with end directive.

To recapitulate, at a minimum, a VxD must have a device control block and a device control procedure. You declare a device control block with Declare_Virtual_Device macro and a device control procedure with Begin_Control_Dispatch macro. You must export the device control block by specifying its name under EXPORTS directive in .DEF file.

Assembling the VxDThe assembling process is the same as the one used in assembling normal win32 applications. You invoke ml.exe on the asm source code and then link the object file with link.exe. The differences are in the command line switches used by ml.exe and link.exe

ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 firstvxd.asm

-coff Specify the COFF object format

-c Assemble only. Do not call the linker to link the object file, since we will call link.exe later with more parameters.

-Cx Preserve the case of public, extern labels.

-D<text> defines a text macro. For example, -DBLD_COFF defines a text macro BLD_COFF which will be used in conditional assembly. If you're interested, you can search for BLD_COFF in the include files and see for yourself what effect it has on the assembly process. So in the command line switches above, three text macros are defined: BLD_COFF, IS_32, and MASM6. If you're familiar with C, this process is identical to:

#define BLD_COFF

#define IS_32

#define MASM6link -vxd -def:firstvxd.def firstvxd.obj

-vxd specifies that we want to build a VxD from the object file

-def:<.DEF file> specifies the name of the module definition file of the VxD

I find it more convenient to use makefile but you can create a batch file to automate the assembling process if you don't like makefile approach. Here's my makefile.

NAME=firstvxd

$(NAME).vxd:$(NAME).obj

link -vxd -def:$(NAME).def $(NAME).obj

$(NAME).obj:$(NAME).asm

ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 $(NAME).asm

[Iczelion's Win32 Assembly Homepage]

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有