NT式驱动程序的基本结构:
驱动对象:每个驱动程序会有唯一的驱动对象与之对应,这个驱动对象时在驱动加载的时候,被内核中的对象管理程序所创建的,由内核中的IO管理器进行加载。
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
//
// The following links all of the devices created by a single driver
// together on a list, and the Flags word provides an extensible flag
// location for driver objects.
//
/*DeviceObject是设备对象的链表,设备对象由程序员创建的,驱动卸载的时候遍历每一个设备对象,将其删除。*/
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
//
// The following section describes where the driver is loaded. The count
// field is used to count the number of times the driver has had its
// registered reinitialization routine invoked.
//
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
//
// The driver name field is used by the error log thread
// determine the name of the driver that an I/O request is/was bound.
//
/*驱动程序的名称,UNICODE字符串,格式为\Driver\[驱动名称]*/
UNICODE_STRING DriverName;
//
// The following section is for registry support. Thise is a pointer
// to the path to the hardware information in the registry
//
/*设备的硬件数据库键名,*/
PUNICODE_STRING HardwareDatabase;
//
// The following section contains the optional pointer to an array of
// alternate entry points to a driver for "fast I/O" support. Fast I/O
// is performed by invoking the driver routine directly with separate
// parameters, rather than using the standard IRP call mechanism. Note
// that these functions may only be used for synchronous I/O, and when
// the file is cached.
//
PFAST_IO_DISPATCH FastIoDispatch;/*文件驱动中用到的派遣函数*/
//
// The following section describes the entry points to this particular
// driver. Note that the major function dispatch table must be the last
// field in the object so that it remains extensible.
//
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;/*记录StartIO例程的函数地址,用于串行化操作*/
PDRIVER_UNLOAD DriverUnload;/*驱动卸载时所用的回调函数地址*/
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];/*记录着一个函数指针数组,每一个指针指向一个函数,每个函数就是处理IRP的派遣函数。*/
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
设备对象:每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构体表示,每个设备对象都会有一个指针指向下一个设备对象,形成一个设备链,第一个设备由DRIVER_OBJECT结构体中指明。
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;/*指向驱动程序中的驱动对象,同一个驱动程序对象中的设备指向统一的驱动对象*/
struct _DEVICE_OBJECT *NextDevice;/*指向下一个设备对象,下一个对象是指同一个驱动程序创建的若干设备对象*/
struct _DEVICE_OBJECT *AttachedDevice;/*指向下一个设备对象,这里指的是,若有更高一层的驱动附件到这个驱动的时候,AttachedDevice指向的是那个更高一层的驱动的设备对象*/
struct _IRP *CurrentIrp;/*使用StartIO例程的时候,指向的是当前IRP结构*/
PIO_TIMER Timer;
ULONG Flags; // See above: DO_...
/*
#define DO_BUFFERED_IO 0x00000004 // 读写操作使用缓冲方式(系统复制缓冲区)访问用户模式数据
#define DO_EXCLUSIVE 0x00000008 //一次只允许一个线程打开设备句柄
#define DO_DIRECT_IO 0x00000010 //读写操作使用直接方式(内存描述符表)访问用户模式数据
#define DO_DEVICE_INITIALIZING 0x00000080 //设备正在初始化
#define DO_POWER_PAGABLE 0x00002000 //必须在PASSIVE_LEVEL级别上处理IRP_MJ_PNP请求
#define DO_POWER_INRUSH 0x00004000 //设备上电期间需要大量电流
*/
ULONG Characteristics; // See ntioapi: FILE_...
__volatile PVPB Vpb;
PVOID DeviceExtension;/*设备扩展对象,记录的是设备自己特殊定义的结构体,尽量避免使用全局变量*/
DEVICE_TYPE DeviceType;/*指明设备类型,当制作虚拟设备时,应选择FILE_DEVICE_UNKNOWN*/
CCHAR StackSize;/*在多层驱动的情况下,驱动与驱动之间会形成类似堆栈的结构,IRP会依次从最高层传递到最底层。该值记录堆栈的层数*/
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;/*设备在大容量传输的时候,需要内存对齐,以保证传输速度*/
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
//
// The following field is for exclusive use by the filesystem to keep
// track of the number of Fsp threads currently using the device
//
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT;
typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;
UNICODE结构体:宽字符集,每个字符占16位
//
// Unicode strings are counted 16-bit character strings. If they are
// NULL terminated, Length does not include trailing NULL.
//
typedef struct _UNICODE_STRING {
USHORT Length;//记录字符串长度,若有N个字符,则此数值为N*2
USHORT MaximumLength;//记录容纳字符串的最大长度,
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
__field_bcount_part(MaximumLength, Length) PWCH Buffer; //记录字符串的指针
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
NTSTATUS:32位无符号长整型,0~0X7FFFFFFF被认为是正确的状态,0X80000000~0XFFFFFFFF被认为是错误的状态。使用宏NT_SUCCESS来检测状态是否正确。
//创建设备
NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,/*驱动对象的指针*/
IN ULONG DeviceExtensionSize,/*指定设备扩展的大小,IO管理器根据此数值在内存中创建设备扩展,并和驱动对象关联(驱动对象能找到是哪个设备对象的扩展对象吧)*/
IN PUNICODE_STRING DeviceName OPTIONAL,/*设备对象的名字*/
IN DEVICE_TYPE DeviceType,/**/
IN ULONG DeviceCharacteristics,/*设备对象的特制,一般为FILE_DEVICE_SECURE_OPEN*/
IN BOOLEAN Exclusive,/*设置设备对象是否在内核模式下使用,一般设置为TRUE*/
OUT PDEVICE_OBJECT *DeviceObject/*IO管理器负责创建这个设备对象,此参数表示返回的创建设备对象的指针*/
);
//创建设备连接名
NTSTATUS IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,//设备连接名
IN PUNICODE_STRING DeviceName //设备名
);
驱动对象:每个驱动程序会有唯一的驱动对象与之对应,这个驱动对象时在驱动加载的时候,被内核中的对象管理程序所创建的,由内核中的IO管理器进行加载。
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
//
// The following links all of the devices created by a single driver
// together on a list, and the Flags word provides an extensible flag
// location for driver objects.
//
/*DeviceObject是设备对象的链表,设备对象由程序员创建的,驱动卸载的时候遍历每一个设备对象,将其删除。*/
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
//
// The following section describes where the driver is loaded. The count
// field is used to count the number of times the driver has had its
// registered reinitialization routine invoked.
//
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
//
// The driver name field is used by the error log thread
// determine the name of the driver that an I/O request is/was bound.
//
/*驱动程序的名称,UNICODE字符串,格式为\Driver\[驱动名称]*/
UNICODE_STRING DriverName;
//
// The following section is for registry support. Thise is a pointer
// to the path to the hardware information in the registry
//
/*设备的硬件数据库键名,*/
PUNICODE_STRING HardwareDatabase;
//
// The following section contains the optional pointer to an array of
// alternate entry points to a driver for "fast I/O" support. Fast I/O
// is performed by invoking the driver routine directly with separate
// parameters, rather than using the standard IRP call mechanism. Note
// that these functions may only be used for synchronous I/O, and when
// the file is cached.
//
PFAST_IO_DISPATCH FastIoDispatch;/*文件驱动中用到的派遣函数*/
//
// The following section describes the entry points to this particular
// driver. Note that the major function dispatch table must be the last
// field in the object so that it remains extensible.
//
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;/*记录StartIO例程的函数地址,用于串行化操作*/
PDRIVER_UNLOAD DriverUnload;/*驱动卸载时所用的回调函数地址*/
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];/*记录着一个函数指针数组,每一个指针指向一个函数,每个函数就是处理IRP的派遣函数。*/
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
设备对象:每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构体表示,每个设备对象都会有一个指针指向下一个设备对象,形成一个设备链,第一个设备由DRIVER_OBJECT结构体中指明。
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;/*指向驱动程序中的驱动对象,同一个驱动程序对象中的设备指向统一的驱动对象*/
struct _DEVICE_OBJECT *NextDevice;/*指向下一个设备对象,下一个对象是指同一个驱动程序创建的若干设备对象*/
struct _DEVICE_OBJECT *AttachedDevice;/*指向下一个设备对象,这里指的是,若有更高一层的驱动附件到这个驱动的时候,AttachedDevice指向的是那个更高一层的驱动的设备对象*/
struct _IRP *CurrentIrp;/*使用StartIO例程的时候,指向的是当前IRP结构*/
PIO_TIMER Timer;
ULONG Flags; // See above: DO_...
/*
#define DO_BUFFERED_IO 0x00000004 // 读写操作使用缓冲方式(系统复制缓冲区)访问用户模式数据
#define DO_EXCLUSIVE 0x00000008 //一次只允许一个线程打开设备句柄
#define DO_DIRECT_IO 0x00000010 //读写操作使用直接方式(内存描述符表)访问用户模式数据
#define DO_DEVICE_INITIALIZING 0x00000080 //设备正在初始化
#define DO_POWER_PAGABLE 0x00002000 //必须在PASSIVE_LEVEL级别上处理IRP_MJ_PNP请求
#define DO_POWER_INRUSH 0x00004000 //设备上电期间需要大量电流
*/
ULONG Characteristics; // See ntioapi: FILE_...
__volatile PVPB Vpb;
PVOID DeviceExtension;/*设备扩展对象,记录的是设备自己特殊定义的结构体,尽量避免使用全局变量*/
DEVICE_TYPE DeviceType;/*指明设备类型,当制作虚拟设备时,应选择FILE_DEVICE_UNKNOWN*/
CCHAR StackSize;/*在多层驱动的情况下,驱动与驱动之间会形成类似堆栈的结构,IRP会依次从最高层传递到最底层。该值记录堆栈的层数*/
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;/*设备在大容量传输的时候,需要内存对齐,以保证传输速度*/
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
//
// The following field is for exclusive use by the filesystem to keep
// track of the number of Fsp threads currently using the device
//
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT;
typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;
UNICODE结构体:宽字符集,每个字符占16位
//
// Unicode strings are counted 16-bit character strings. If they are
// NULL terminated, Length does not include trailing NULL.
//
typedef struct _UNICODE_STRING {
USHORT Length;//记录字符串长度,若有N个字符,则此数值为N*2
USHORT MaximumLength;//记录容纳字符串的最大长度,
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
__field_bcount_part(MaximumLength, Length) PWCH Buffer; //记录字符串的指针
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
NTSTATUS:32位无符号长整型,0~0X7FFFFFFF被认为是正确的状态,0X80000000~0XFFFFFFFF被认为是错误的状态。使用宏NT_SUCCESS来检测状态是否正确。
//创建设备
NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,/*驱动对象的指针*/
IN ULONG DeviceExtensionSize,/*指定设备扩展的大小,IO管理器根据此数值在内存中创建设备扩展,并和驱动对象关联(驱动对象能找到是哪个设备对象的扩展对象吧)*/
IN PUNICODE_STRING DeviceName OPTIONAL,/*设备对象的名字*/
IN DEVICE_TYPE DeviceType,/**/
IN ULONG DeviceCharacteristics,/*设备对象的特制,一般为FILE_DEVICE_SECURE_OPEN*/
IN BOOLEAN Exclusive,/*设置设备对象是否在内核模式下使用,一般设置为TRUE*/
OUT PDEVICE_OBJECT *DeviceObject/*IO管理器负责创建这个设备对象,此参数表示返回的创建设备对象的指针*/
);
//创建设备连接名
NTSTATUS IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,//设备连接名
IN PUNICODE_STRING DeviceName //设备名
);