1、WDM.h
/************************************************************************ * 文件名称:HelloWDM.h * 作 者:张帆 * 完成日期:2007-11-1 *************************************************************************/ #ifdef __cplusplus extern "C" { #endif #include <wdm.h> #ifdef __cplusplus } #endif typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT fdo; PDEVICE_OBJECT NextStackDevice; UNICODE_STRING ustrDeviceName; // 设备名 UNICODE_STRING ustrSymLinkName; // 符号链接名 } DEVICE_EXTENSION, *PDEVICE_EXTENSION; #define PAGEDCODE code_seg("PAGE") #define LOCKEDCODE code_seg() #define INITCODE code_seg("INIT") #define PAGEDDATA data_seg("PAGE") #define LOCKEDDATA data_seg() #define INITDATA data_seg("INIT") #define arraysize(p) (sizeof(p)/sizeof((p)[0])) NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject); NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp); NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp); void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject); extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
/************************************************************************ * 文件名称:HelloWDM.cpp * 作 者:张帆 * 完成日期:2007-11-1 *************************************************************************/ #include "HelloWDM.h" /************************************************************************ * 函数名称:DriverEntry * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 pRegistryPath:驱动程序在注册表的中的路径 * 返回 值:返回初始化驱动状态 *************************************************************************/ #pragma INITCODE extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { KdPrint(("Enter DriverEntry\n")); pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice; pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = pDriverObject->MajorFunction[IRP_MJ_CREATE] = pDriverObject->MajorFunction[IRP_MJ_READ] = pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMDispatchRoutine; pDriverObject->DriverUnload = HelloWDMUnload; KdPrint(("Leave DriverEntry\n")); return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloWDMAddDevice * 功能描述:添加新设备 * 参数列表: DriverObject:从I/O管理器中传进来的驱动对象 PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象 * 返回 值:返回添加新设备状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { PAGED_CODE(); KdPrint(("Enter HelloWDMAddDevice\n")); NTSTATUS status; PDEVICE_OBJECT fdo; UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice"); status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); if( !NT_SUCCESS(status)) return status; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; pdx->fdo = fdo; pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\HelloWDM"); pdx->ustrDeviceName = devName; pdx->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName); if( !NT_SUCCESS(status)) { IoDeleteSymbolicLink(&pdx->ustrSymLinkName); status = IoCreateSymbolicLink(&symLinkName,&devName); if( !NT_SUCCESS(status)) { return status; } } fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; //驱动创建的设备有三种工作方式,缓冲区方式、直接方式和其他方式。 fdo->Flags &= ~DO_DEVICE_INITIALIZING; KdPrint(("Leave HelloWDMAddDevice\n")); return STATUS_SUCCESS; } /************************************************************************ * 函数名称:DefaultPnpHandler * 功能描述:对PNP IRP进行缺省处理 * 参数列表: pdx:设备对象的扩展 Irp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx, PIRP Irp) { PAGED_CODE(); KdPrint(("Enter DefaultPnpHandler\n")); IoSkipCurrentIrpStackLocation(Irp); KdPrint(("Leave DefaultPnpHandler\n")); return IoCallDriver(pdx->NextStackDevice, Irp); } /************************************************************************ * 函数名称:HandleRemoveDevice * 功能描述:对IRP_MN_REMOVE_DEVICE IRP进行处理 * 参数列表: fdo:功能设备对象 Irp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp) { PAGED_CODE(); KdPrint(("Enter HandleRemoveDevice\n")); Irp->IoStatus.Status = STATUS_SUCCESS; NTSTATUS status = DefaultPnpHandler(pdx, Irp); IoDeleteSymbolicLink(&(UNICODE_STRING)pdx->ustrSymLinkName); //调用IoDetachDevice()把fdo从设备栈中脱开: if (pdx->NextStackDevice) IoDetachDevice(pdx->NextStackDevice); //删除fdo: IoDeleteDevice(pdx->fdo); KdPrint(("Leave HandleRemoveDevice\n")); return status; } /************************************************************************ * 函数名称:HelloWDMPnp * 功能描述:对即插即用IRP进行处理 * 参数列表: fdo:功能设备对象 Irp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloWDMPnp(IN PDEVICE_OBJECT fdo, IN PIRP Irp) { PAGED_CODE(); KdPrint(("Enter HelloWDMPnp\n")); NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) = { DefaultPnpHandler, // IRP_MN_START_DEVICE DefaultPnpHandler, // IRP_MN_QUERY_REMOVE_DEVICE HandleRemoveDevice, // IRP_MN_REMOVE_DEVICE DefaultPnpHandler, // IRP_MN_CANCEL_REMOVE_DEVICE DefaultPnpHandler, // IRP_MN_STOP_DEVICE DefaultPnpHandler, // IRP_MN_QUERY_STOP_DEVICE DefaultPnpHandler, // IRP_MN_CANCEL_STOP_DEVICE DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_RELATIONS DefaultPnpHandler, // IRP_MN_QUERY_INTERFACE DefaultPnpHandler, // IRP_MN_QUERY_CAPABILITIES DefaultPnpHandler, // IRP_MN_QUERY_RESOURCES DefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_TEXT DefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS DefaultPnpHandler, // DefaultPnpHandler, // IRP_MN_READ_CONFIG DefaultPnpHandler, // IRP_MN_WRITE_CONFIG DefaultPnpHandler, // IRP_MN_EJECT DefaultPnpHandler, // IRP_MN_SET_LOCK DefaultPnpHandler, // IRP_MN_QUERY_ID DefaultPnpHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE DefaultPnpHandler, // IRP_MN_QUERY_BUS_INFORMATION DefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION DefaultPnpHandler, // IRP_MN_SURPRISE_REMOVAL }; ULONG fcn = stack->MinorFunction; if (fcn >= arraysize(fcntab)) { // unknown function status = DefaultPnpHandler(pdx, Irp); // some function we don't know about return status; } // unknown function #if DBG static char* fcnname[] = { "IRP_MN_START_DEVICE", "IRP_MN_QUERY_REMOVE_DEVICE", "IRP_MN_REMOVE_DEVICE", "IRP_MN_CANCEL_REMOVE_DEVICE", "IRP_MN_STOP_DEVICE", "IRP_MN_QUERY_STOP_DEVICE", "IRP_MN_CANCEL_STOP_DEVICE", "IRP_MN_QUERY_DEVICE_RELATIONS", "IRP_MN_QUERY_INTERFACE", "IRP_MN_QUERY_CAPABILITIES", "IRP_MN_QUERY_RESOURCES", "IRP_MN_QUERY_RESOURCE_REQUIREMENTS", "IRP_MN_QUERY_DEVICE_TEXT", "IRP_MN_FILTER_RESOURCE_REQUIREMENTS", "", "IRP_MN_READ_CONFIG", "IRP_MN_WRITE_CONFIG", "IRP_MN_EJECT", "IRP_MN_SET_LOCK", "IRP_MN_QUERY_ID", "IRP_MN_QUERY_PNP_DEVICE_STATE", "IRP_MN_QUERY_BUS_INFORMATION", "IRP_MN_DEVICE_USAGE_NOTIFICATION", "IRP_MN_SURPRISE_REMOVAL", }; KdPrint(("PNP Request (%s)\n", fcnname[fcn])); #endif // DBG status = (*fcntab[fcn])(pdx, Irp); KdPrint(("Leave HelloWDMPnp\n")); return status; } /************************************************************************ * 函数名称:HelloWDMDispatchRoutine * 功能描述:对缺省IRP进行处理 * 参数列表: fdo:功能设备对象 Irp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloWDMDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp) { PAGED_CODE(); KdPrint(("Enter HelloWDMDispatchRoutine\n")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); //打印IRP的major function code和minor function code。 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; KdPrint(("DispatchRoutine, Major function code: %x, Minor function code: %x, control code: %x\n", stack->MajorFunction, stack->MinorFunction, code)); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; // no bytes xfered IoCompleteRequest( Irp, IO_NO_INCREMENT ); KdPrint(("Leave HelloWDMDispatchRoutine\n")); return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloWDMUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: DriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE void HelloWDMUnload(IN PDRIVER_OBJECT DriverObject) { PAGED_CODE(); KdPrint(("Enter HelloWDMUnload\n")); KdPrint(("Leave HelloWDMUnload\n")); }
4、用户态应用程序
#include "CC_Debug.h" #include <stdio.h> #include <windows.h> #define DEVICE_NAME L"\\\\.\\HelloWDM" int main() { HANDLE hDevice = CreateFile(DEVICE_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); printf("hDevice = %x",hDevice); if (hDevice != INVALID_HANDLE_VALUE) { for(int i = 0; i < 10; i++) { DWORD RetBytes = 0; BOOL b = DeviceIoControl(hDevice, 0xAB, NULL, 0, NULL, 0, &RetBytes, NULL); printf("Test number %d, DeviceIoControl result: %d, byte: %d\n", i + 1, b, RetBytes); Sleep(1000); } CloseHandle(hDevice); } else printf("CreateFile failed, err: %x\n", GetLastError()); return 0; }
5、这里有必要讲一下驱动的几个名字概念:
1. 首先是设备名称,就是IoCreateDevice里面用到的那个名字。这个名字只能被内核模式的程序(如其他驱动)所识别。用户模式的程序是不知道这个名字的。
2. 符号链接,驱动程序里面可以为某个设备设置符号链接,以\??\开头(或者\DosDevices\),这样用户模式的程序就可以通过这个符号链接来访问这个设备。
3. 用户模式程序里面的设备名称,以\\.\开头
比如这个例子里面内核模式的设备名称是"\Device\MyWDMDevice",符号链接是"\DosDevices\HelloWDM",然后用户模式程序通过"\\.\HelloWDM"访问这个设备。
当CreateFile成功打开这个设备后,就可以操作这个设备了。测试例子里面简单往这个设备调用了10次DeviceIoControl函数(也就是发送一个IRP_MJ_DEVICE_CONTROL类型的IRP)。
4、Major function code 是e(16进制),看一下WDM.H
确实0x0e对应的是IRP_MJ_DEVICE_CONTROL。
然后测试例子里面发送了一个0xAB的控制码给驱动,那么驱动里面通过stack->Parameters.DeviceIoControl.IoControlCode得到的控制码也是0xab,看上面的debugview信息。
http://blog.csdn.net/zj510/article/details/8208732