This article is aimed at the user that already does little Virtual Device Driver (VxD) progamming using Microsoft's Macro Assembler (MASM).
I. About the readers and article's files overview
II. MASM vs NASM : Syntax overview
III. A skeleton VxD
IV. More VxD examples
V. FAQs
VI. About the writer
I. About the readers and article's files overview
This article is aimed at the user that already does little Virtual Device
Driver (VxD) progamming using Microsoft's Macro Assembler (MASM). It will only
cover how to use the Net Wide Assembler (NASM) to write Virtual Device Drivers
and not how to learn VxD programming using NASM.
It is also suggested that the user be familiar with NASM or read NASM DOC.
As for the files in this article:
NASMVXD.TXT - This article.
VXDN.INC - Contains VxD related definitions and macros for NASM.
WINDDK.INC - This is used by VXDN.INC and should'nt be directly included
by you. It contains VxD related EQU's and it also has VxD
services covering VMM,Shell,Debug,...
II. Overview about MASM & NASM
It is time to mention that NASM was never intended to produce VxD files and you
won't be able to produce any without the include files from this package and
without Microsoft's Incremental Linker (LINK.EXE).
Okay, now the syntax differences between MASM & NASM.
Processor Mode:
To enable the use of 386+ protected mode instructions you used to put a '.386p'
in MASM, no need for that in NASM, however you have to explicitly set the
default bitness to 32 via the 'BITS 32' directive (and to 16 in the real mode
initialization segment).
MASM: .386p
NASM: BITS 32
Segments specification:
MASM has lot of segments declaration macros unlike NASM in which you have to
name the segment as you stated it in the .DEF file.
The 5 basic segment definition macros are:
MASM: NASM: Description
----- ----- -----------
VxD_CODE_SEG/ENDS segment LTEXT Protected mode code seg.
VxDDATA_SEG/ENDS segment LDATA Protected mode data seg.
VxDICODE_SEG/ENDS segment ITEXT Protected mode initialization
code segment. (usually optional)
VxDIDATA_SEG/ENDS segment IDATA Protected mode initialization
data segment. (usually optional)
VxDREAL_INIT_SEG/ENDS segment _RTEXT Real mode initialization
segment. (optional too)
Notice that NASM does not need a segment closing macro unlike MASM.
To start a new segment just declare it like 'segment _LTEXT' and everything
after that line will go to that segment.
Please do not use the intrinsic form of the segment macro (e.g.
[segment _LTEXT]) as certain VxD macros rely on saving/restoring the current
segment and they would fail should you use the intrinsic form.
Check the FAQ for a brief segment overview or NASMDOC.TXT for full overview.
Virtual Device Desciptor Block (DDB) Declaration:
- MASM
-
Declare_Virtual_Device Name, MajorVer, MinorVer, CtrlProc, DeviceNum,
InitOrder, V86Proc, PMProc, RefData
- NASM
-
Due to the fact that NASM does not support string concatenation in macros
yet (there exist patched versions which do), the declaration is a bit
- different
Declare_Virtual_Device Name, 'Name', MajorVer, MinorVer, CtrlProc,
DeviceNum, InitOrder, V86Proc, PMProc, RefData
Params 5 to 9 are optional, since most of the time they are generic (not
used).
The extra parameter is 'Name' which will become the DDB_Name field in the
DDB (this is the name by which the VxD will be known to the VMM), Name
itself determines the name for the Control Procedure and the Service Table
(if used).
The DDB must be declared inside the _LDATA segment.
- Example
segment LDATA
DeclareVirtual_Device SAMPVXD1, 'SAMPVXD1', 1, 0, SAMPVXD1_Control
Control Procedure Definition:
- MASM
-
Begin_Control_Dispatch NAME
Control_Dispatch Message,Proc
End_Control_Dispatch
- NASM
-
This will be a little new for you since you have to do it by hand and not
by similar macros:
segment _LTEXT
- VXDNAME Control
- cmp eax,VM_INIT
je OnVmInit
cmp eax,W32_DEVICEIOCONTROL
je OnDIOC
cmp eax,<system message>
je <Desired Event handler proc>
clc ; At any time during initialization, a virtual device can set the
; carry flag and return to the VMM to prevent the virtual device
; from loading. This means that the carry flag must be cleared to
; allow loading.
retn
- OnVmInit
- ; Do some code
ret
OnDIOC: ; OnDeviceIoControl
; ESI points to a DIOCParams struct
cmp word [esi+DIOCParams.dwIoControlCode],MY_DIOC_CODE
je domycode
retn ; Don't forget to put a return as you're used to put a
; "EndProc procname"
Any Other procedure Definition
Using NASM's normal procedure definition you can define a new proc as
usual: "procname :".
As for calling conventions you have to access the stack yourself or use some
other NASM macros.
Using VxdCall and VMMCall
In NASM you can call: VMMCall Service,param1,{param2},[ [{]param3[}] ],....
III. A skeleton VxD
A skeleton VxD will be a very basic VxD enough to be loaded correctly and do
nothing more than taking up memory. =)
In NVXDSKEL.DEF you can specify if it will be a DYNAMIC or a STATIC VxD like:
VXD MYVXD DYNAMIC ; dynamic vxd
VXD MYVXD ; static vxd
NVXDSKEL.DEF
VXD NVXDSKEL DYNAMIC
SEGMENTS
_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
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_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
_RCODE CLASS 'RCODE'
EXPORTS
NVXDSKEL_DDB @1
NVXDSKEL.ASM
bits 32
%include "vxdn.inc"
segment _LDATA
Declare_Virtual_Device NVXDSKEL,'NVXDSKEL',1,0,NVXDSKEL_Control
segment _LTEXT
- NVXDSKEL Control
-
clc
retn
Assembling and linking:
- To assemble you must have NASM v0.98+
NASM NVXDSKEL.ASM -f win32
LINK NVXDSKEL.OBJ /VXD /DEF:NVXDSKEL.DEF
That's it!
IV. More VxD examples
This example will show the use of VMMCall and VxDCall
VXDSAMP1.DEF
VXD VXDSAMP1 DYNAMIC
SEGMENTS
_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
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_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
_RCODE CLASS 'RCODE'
EXPORTS
VXDSAMP1_DDB @1
VXDSAMP1.ASM
bits 32
%include "vxdn.inc"
segment _LDATA
Declare_Virtual_Device VXDSAMP1,'VXDSAMP1',1,0,VXDSAMP1_Control
segment _LTEXT
- VXDSAMP1 Control
-
cmp eax,W32_DEVICEIOCONTROL
je OnDIOC
clc
retn
- OnDIOC
-
cmp dword [esi+DIOCParams.dwIoControlCode],1
je .1
xor eax,eax
jmp .ret
.1:
VMMCall Get_Sys_VM_Handle
xor esi,esi ; no callback
xor edx,edx ; no ref data for callback
mov eax,0
mov ecx,Msg
mov edi,Title
VxDCall SHELL_Message
.ret:
retn
segment _LDATA
Msg db 'Hello world!',0
Title db 'Title!',0
<EOF>
And another example that calls Int21/Ah=02,dl=7 to beep.
VXDSAMP2.ASM
bits 32
%include "vxdn.inc"
segment _LDATA
Declare_Virtual_Device VXDSAMP2,'VXDSAMP2',1,0,VXDSAMP2_Control
segment _LTEXT
- VXDSAMP2 Control
cmp eax,W32_DEVICEIOCONTROL
je OnDIOC
clc
retn
- OnDIOC
-
cmp dword [esi+DIOCParams.dwIoControlCode],1
je .1
xor eax,eax
jmp .ret
.1:
VxDCall Begin_Nest_V86_Exec
mov word [ebp+CRS.EAX],0x0200
mov word [ebp+CRS.EDX],0x0007
mov eax,0x21
VxDCall Exec_Int
VxDCall End_Nest_Exec
.ret:
retn
<EOF>
Use .DEF like previous example but change name to the new VxD name.
To test the last two examples, just open the VxD with CreateFileA() and then
issue a DeviceIoControl() with code 1.
V. FAQs
Q) Where can i get NASM and LINK from?
A) As for NASM you can get it from:
{http://www.web-sites.co.uk/nasm/}
As for LINK.EXE you can get it from the DDK or just download the MASM Pack
from {http://win32asm.cjb.net}
Q) How can i add new services and use them with NASM?
A) You can start by defining:
MyDevice_DeviceID equ 0x1234 ; must be word
and then define a service table like:
Begin_Service_Table MyDevice
VMM_Service MyService0 ; 0x0000 ord
VMM_Service MyService1 ; 0x0001 ord
VMM_Service MyServiceN ; ord N
End_Service_Table MyDevice
VI. About the writers
Me as therain, would like to credit:
fOSSiL
&
The Owl - For creating VXDN.INC and
for showing how to write VxDs in NASM in the first place
by demonstrating it in IceDump (visit: {http://icedump.tsx.org}).
And for reviewing/editing this document.
Iczelion - For his awesome win32asm resource site and for his
good VxD tutorials. (visit: {http://win32asm.cjb.net})
UKC Team - For their support.
[The VXDN.INC and WINDDK.INC files can be obtained from
{http://asmjournal.freeservers.com/files/nasmvxd.zip}
where they have been archived along with the text of the article.]
|