贴一下上篇文章创建新设备的代码
#pragma code_seg("INIT" ) void CreateDevice(PDRIVER_OBJECT driver) { ULONG j; NTSTATUS statuss; UNICODE_STRING StDeviceName = {0}; UNICODE_STRING StSysLinkName= {0}; PDEVICE_EXT pExt=NULL; PDEVICE_OBJECT pDeviceObj = NULL; RtlInitUnicodeString(&StDeviceName, L"\\Device\\SmkDevice" ); //设别名称 内核模式下可访问的 RtlInitUnicodeString(&StSysLinkName, L"\\??\\LinkSmkDevice" ); //符号链接名称 ring3下访问的 其中\\??需改成\\. statuss = IoCreateDevice( driver, sizeof(DEVICE_EXT), &StDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj ); //DEVICE_EXT扩展属性 记录用户自定义数据 if (!NT_SUCCESS(statuss)) { KdPrint(("create obj faile")); return; } pDeviceObj->Flags|=DO_BUFFERED_IO;//这边以缓冲区方式进行读取 statuss=IoCreateSymbolicLink(&StSysLinkName,&StDeviceName); if (!NT_SUCCESS(statuss)) { IoDeleteDevice( pDeviceObj ); KdPrint(("create Symbolic faile")); return; } pExt=(PDEVICE_EXT)pDeviceObj->DeviceExtension; pExt->pDeviceObj=pDeviceObj; pExt->StSzDeviceName=StDeviceName; pExt->StSzSysLinkName=StSysLinkName; KdPrint(( "Create obj 执行成功!\n" )); }
pDeviceObj->Flags|=DO_BUFFERED_IO;是以缓冲区的方式进行读取,所以在read派遣函数中可直接将数据复制到irp->AssociatedIrp.SystemBuffer,在write中则是
if(buffer==NULL)
buffer=(PCHAR)irp->AssociatedIrp.SystemBuffer;//缓冲区模式读取
如果是 直接读取 方式pDeviceObj->Flags|=DO_DIRECT_IO 则read write中可用MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority);得到MDL在内核模式下的映射
具体的读代码为
#pragma code_seg( "PAGE" ) NTSTATUS ReadDispatch(PDEVICE_OBJECT pDevice, PIRP irp) { PCHAR buffer=NULL; ULONG BufferLenth=0; ULONG ReadOffset=0; PDEVICE_EXT pDExt; PIO_STACK_LOCATION pStack = NULL; pDExt=(PDEVICE_EXT)pDevice->DeviceExtension; pStack = IoGetCurrentIrpStackLocation( irp ); BufferLenth=pStack->Parameters.Read.Length;//获取指定的读取长度 //获取锁定缓冲区的长度 ULONG mdl_len=MmGetMdlByteCount(irp->MdlAddress); //获取锁定缓冲区的首地址 ULONG mdl_add=MmGetMdlVirtualAddress(irp->MdlAddress); //获取锁定缓冲区的偏移量 ULONG mdl_offset=MmGetMdlByteOffset(irp->MdlAddress); //MDL长度应该和读取长度相等 if (mdl_len!=BufferLenth)
{ KdPrint(("Read Size error\r\n")); BufferLenth=0; } else { PVOID kernel_add=MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority); RtlCopyMemory(kernel_add,pDExt->buffer+ReadOffset,BufferLenth); } irp->IoStatus.Information = BufferLenth; irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( irp, IO_NO_INCREMENT ); KdPrint(( "Irp_DispatchRoutine 执行完毕" )); return STATUS_SUCCESS; }
Write下的代码基本类同
二、其他模式下的读取方式 Flags的设置既不是DO_DIRECT_IO也不是DO_BUFFERED_IO,上一篇中在Write派遣函数中 buffer=(PCHAR)irp->UserBuffer; 这就是其他模式下的缓存区,只需对此缓冲区进行操作即可实现,具体代码此处略。