配置好环境先写一个hello world来测试一下。
#include <ntddk.h>
NTSTATUS unload(PDRIVER_OBJECT driver)
{
DbgPrint("Driver unload success..");
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
driver->DriverUnload = unload;
DbgPrint("Hello World\n");
return STATUS_SUCCESS;
}
构成
驱动程序格式还是挺简单的,基本上有两个必要的模块组成。
- unload
- DriverEntry
DriverEntry
相当于main函数,驱动程序的载入函数,一般包含两个参数
PDRIVER_OBJECT driver // 刚被初始化的驱动对象指针
PUNICODE_STRING reg_path // 驱动在注册表中的键值
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
driver->DriverUnload = unload; // 注册卸载函数,位置无所谓。
DbgPrint("Hello World\n"); // 方便查看运行状态。
return STATUS_SUCCESS; // 和return 0没啥区别。
}
DRIVER_OBJECT 结构体
这是驱动载入和退出函数的第一个参数,包含了一个驱动的详细信息。在wdn.h中可以得到定义
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.
//
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_STRING DriverName; //驱动名称
//
// The following section is for registry support. This 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;
PDRIVER_UNLOAD DriverUnload; //驱动的卸载地址
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;
- Type:该字段标识该结构体的类型,始终设置DRIVER_OBJECT_TYPE
- Size:该字段表示该结构体的大小,以字节为单位
- DeviceObject:该字段是一个指针,指向驱动程序所创建的设备对象链表的头部。每个设备对象代表着一个设备或者驱动程序创建的一种虚拟设备
- DriverStart:该字段是一个指针,指向驱动程序代码的入口点,也就是驱动程序的DriverEntry函数。该函数会在驱动程序被加载时被调用。
- DriverSize:该字段表示驱动程序代码的大小,以字节为单位。
可以利用DriverSection来遍历当前系统下所有的驱动程序的具体信息。
UNICODE_STRING 结构体
在ntdef.h文件中可以看到定义
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
卸载函数
驱动程序需要自定义一个卸载程序,因为系统为了稳定,驱动不会被系统自动卸载,所以需要手动去定义一下。
假如在DriverEntry
中添加了某些系统回调,没有DriverUnload
,系统就不知道什么时候该移除这些回调,如果暴力移除驱动,此时系统回调会出问题,系统回调表中存在了一个被移除掉的驱动的回调,当调用时系统蓝屏 。
NTSTATUS unload(PDRIVER_OBJECT driver)
{
DbgPrint("Driver unload success..");
return STATUS_SUCCESS;
}
其实也没有什么特殊操作,就告诉系统有这么一回事就行了,这里留个字符串来显示一下状态。