转载自:http://mzf2008.blog.163.com/blog/static/3559978620101195653754/
驱动对象(DRIVER_OBJECT)
typedef struct _DRIVER_OBJECT {
//结构的类型和大小
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject; //指向驱动的第一个设备对象
ULONG Flags;
//这个驱动设备在内核空间中的开始地址和大小
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension; //驱动扩展
UNICODE_STRING DriverName;//驱动程序名字,例如:\\Driver\\【驱动程序名称】
//指向注册表中的硬件配置信息,一般为 \Registry\Machine\Hardware\DESCRIPTION\SYSTEM
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch; //文件驱动中用到的派遣函数
PDRIVER_INITIALIZE DriverInit; //驱动程序的DriverEntery例程入口点
PDRIVER_STARTIO DriverStartIo; //驱动程序的DriverStartIo
PDRIVER_UNLOAD DriverUnload; //驱动程序的DriverUnload
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; //驱动程序的派遣例程入口点
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
![NT式驱动的基本结构 - Fly - 从C开始](http://img153.ph.126.net/RDD3jCMGVm4w6omVyiH2cQ==/1644376813945185707.jpg)
设备对象(DEVICE_OBJECT)
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {CSHORT Type;
USHORT Size;
struct _DRIVER_OBJECT *DriverObject; // 这个设备所属的驱动对象
struct _DEVICE_OBJECT *NextDevice; // 指向该驱动程序的下一个设备对象
struct _DEVICE_OBJECT *AttachedDevice; // 如果有更高一层驱动附加到这个驱动,这个指向更高一层驱动的设备对象
struct _IRP *CurrentIrp; // 指向当前 IRP
PIO_TIMER Timer;
ULONG Flags; // See above: DO_... 设备的缓冲方式
ULONG Characteristics; // See ntioapi: FILE_... 由 IoCreateDevice 函数设置
PVPB Vpb;
PVOID DeviceExtension; // 指向设备扩展
DEVICE_TYPE DeviceType;
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; // ntndis
![NT式驱动的基本结构 - Fly - 从C开始](http://img464.ph.126.net/xfi3gOleeN16KACOQpOQ5Q==/191121509187671567.png)
设备扩展
设备对象记录“通用”设备信息,而另外一些“特殊”的信息记录在设备扩展里。各个设备扩展由程序员自己定义,每个设备的扩展也不尽相同。设备扩展是由程序员指定内容和大小,由I/O管理器创建的,并保存在非分页内存中。
在设备扩展中会记录下列这些内容:
1. 设备对象的反向指针
2. 设备状态或驱动环境信息
3. 中断对象指针
4. 控制器对象指针
由于设备扩展是驱动程序专用的,它的结构必须在驱动程序的头文件中定义。
NT式驱动的基本结构
1. 驱动入口函数(DriverEntry)
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDrover_Object,
IN PUNICODE_STRING pRegistryPath);
DriverEntry主要是对驱动程序进行初始化工作,它由系统进程即System进程在驱动加载的时候,启动新的线程,调用执行体组件中的对象管理器,创建一个驱动对象。
pDrover_Object:指向这个驱动对象。
pRegistryPath:指向设备服务键的键名字符串的指针。该字符串的内容一般为\REGISTRY\MACHINE\SYSTEM\ControlSet\Services\[服务名]。
在驱动程序中,字符串用UNICODE字符集来表示,每个字符用16位即两个字节表示。其中,UNICODE用UNICODE_STRING结构体表示。
typedef struct _UNICODE_STRING {
USHORT Length; //字符串的长度,如果字符串有N个字符,那么Length将会是N的2倍。
USHORT MaximumLength; //指定这个结构最大能记录的字节数
PWSTR Buffer; //记录字符串的指针,每个字符占两个字节
} UNICODE_STRING *PUNICODE_STRING;
在驱动程序中,可以用KdPrint打印UNICODE信息。其语法是:
KdPrint((“%S”, pRegistryPath->Buffer)); //s大写
或
KdPrint((“%ws”, pRegistryPath->Buffer)); //ws小写
注意:
1.在DriverEntry函数中,一般设置设置卸载例程和IRP派遣函数,另外还有一部分代码用来创建驱动的设备对象。
2.DriverEntry返回值是NTSTATUS的数据。其中宏NT_SUCCESS,被用来检测状态的正确性。
3.DriverEntry中的参数修饰符“IN”,“OUT”,“INOUT”在DDK中被定义为空串,他们的功能类似于程序的注释。
2.创建设备对象
NTSTATUS
IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize, //指定设备扩展的大小
IN PUNICODE_STRING DeviceName OPTIONAL,//设备对象的名字
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,//设置设备对象的特征
IN BOOLEAN Exclusive,//设置设备对象是否在内核模式下使用,一般为TRUE
OUT PDEVICE_OBJECT *DeviceObject //指向新创建的设备对象。
);
参数DeviceName 用UNICODE字符串来指定设备对象的名字,该字符串必须为”\Device\[设备名]”的形式。
当然,也可以不指定设备名字,这样I/O管理器会自动分配一个数字作为设备的设备名,例如:\Device\00000001;
如果指定了设备名,但是也只能被内核模式下的其他驱动所识别,用户模式下的应用程序是无法识别的。我们可以通过符号链接来让用户模式下的程序识别这个设备。
创建符号链接的函数是IoCreateSymbolicLink,声明如下:
NTSTATUS
IoCreateSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
IN PUNICODE_STRING DeviceName
);
在内核模式下,符号链接就是以”\??\”开头的(或者“\DosDevice\”开头的)。如C盘就是“\??\C:”。而在用户模式下则是以“\\.\”开头的,如C盘就是“\\.\C:”
3.DriverUnload例程
此例程在驱动被卸载时调用,在NT式驱动中,DriverUnload一般负责删除在DriverEntry中创建的设备对象,并且将设备对象所关联的符号链接删除。另外,DriverUnload还负责对一些资源进行回收。
删除设备对象:
VOID
IoDeleteDevice(
IN PDEVICE_OBJECT DeviceObject
);
删除符号链接
NTSTATUS
IoDeleteSymbolicLink(
IN PUNICODE_STRING SymbolicLinkName
);