Windows 驱动中获取指定的设备对象
2016-06-07 22:53
585 查看
转载自:http://tudian2007.blog.163.com/blog/static/3156641320137295338938/
//我们还可以用ObReferenceObjectByName先根据驱动对象名获取驱动设备,然后再获取驱动设备中的设备对象;
Windows 驱动中获取指定的设备对象
众所周知应用层要和驱动层通讯的话需要先打开驱动设备对象,因为驱动设备名只是对内核模式中的驱动所识别的,应用层是无法识别的,所以一般驱动都有对应的symboliclink供应用层用使用的,如”\\.\C:”,”\??\C:”表示C:分区,\\.\PhysicalDrive0表示磁盘0,如果你需要使用的话只要调用CreateFile就能获得句柄了,还有一种打开驱动设备方法,主要是针对WDM驱动的,就是调用设备接口,相对比较复杂,这里不多讲了; 我们详细来讲讲内核模式下,如何打开一个指定驱动的设备的。1.根据设备名打开:
驱动设备创建的时候,如果需要需要创建控制设备的话我们都会给该设备指定DeviceName和Symboliclink,SymbolicLink上面讲过这里不讲了,DeviceName格式是”\Device\Devicename”,如C:盘就是”\Device\HarddiskVolume1”,如果在创建设备的时候没有指定,系统会默认分配一个”\Device\0000000NUM”之类的;在获取到设备名之后,我们可以调用ZwCreateFIle打开该设备;具体代码如下://代码来源《windows驱动开发详解》第11章 #pragma PAGEDCODE NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("DriverB:Enter B HelloDDKRead\n")); NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING DeviceName; RtlInitUnicodeString( &DeviceName, L"\\Device\\MyDDKDeviceA" ); //初始化objectAttributes OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); HANDLE hDevice; IO_STATUS_BLOCK status_block; //同步打开设备 //设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备 ntStatus = ZwCreateFile(&hDevice, FILE_READ_ATTRIBUTES|SYNCHRONIZE, &objectAttributes, &status_block, NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ, FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0); if (NT_SUCCESS(ntStatus)) { ZwReadFile(hDevice,NULL,NULL,NULL,&status_block,NULL,0,NULL,NULL); } ZwClose(hDevice); // 完成IRP pIrp->IoStatus.Status = ntStatus; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("DriverB:Leave B HelloDDKRead\n")); return ntStatus; }
2.通过符号链接打开设备
SymbolicLink不仅仅对用户模式起作用,驱动中也可以使用,先调用ZwOpenSymbolicLinkObject 得到符号链接的句柄,然后使用ZwQuerySymbolicLinkObject根据句柄得到设备的名字,得到设备名字之后就可以按照方法一里面的办法打开设备对象了;具体代码如下://代码来源《windows驱动开发详解》第11章 #pragma PAGEDCODE NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("DriverB:Enter B HelloDDKRead\n")); NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING DeviceSymbolicLinkName; RtlInitUnicodeString( &DeviceSymbolicLinkName, L"\\??\\HelloDDKA" ); //初始化objectAttributes OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, &DeviceSymbolicLinkName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL ); HANDLE hSymbolic; //设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备 ntStatus = ZwOpenSymbolicLinkObject(&hSymbolic,FILE_ALL_ACCESS,&objectAttributes); #define UNICODE_SIZE 50 UNICODE_STRING LinkTarget; LinkTarget.Buffer = (PWSTR)ExAllocatePool(PagedPool,UNICODE_SIZE); LinkTarget.Length = 0; LinkTarget.MaximumLength = UNICODE_SIZE; ULONG unicode_length; ntStatus = ZwQuerySymbolicLinkObject(hSymbolic,&LinkTarget,&unicode_length); KdPrint(("DriverB:The device name is %wZ\n",&LinkTarget)); InitializeObjectAttributes(&objectAttributes, &LinkTarget, OBJ_CASE_INSENSITIVE, NULL, NULL ); HANDLE hDevice; IO_STATUS_BLOCK status_block; //设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备 ntStatus = ZwCreateFile(&hDevice, FILE_READ_ATTRIBUTES|SYNCHRONIZE, &objectAttributes, &status_block, NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ, FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0); if (NT_SUCCESS(ntStatus)) { ZwReadFile(hDevice,NULL,NULL,NULL,&status_block,NULL,0,NULL,NULL); } ZwClose(hDevice); ZwClose(hSymbolic); ExFreePool(LinkTarget.Buffer); ntStatus = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = ntStatus; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("DriverB:Leave B HelloDDKRead\n")); return ntStatus; } f643
3.用IoGetDeviceObjectPointer
每一个内核态里的句柄都和一个内核对象关联在一起,这个函数可以获取到我们需要打开的驱动设备的设备堆栈最上层的FILE_OBJECT和DEVICE_OBJECT,之后我们只要往这个设备对象发需要的IRP就能通信了;需要注意的是,在调用完这个函数之后,设备对象的引用计数会加1,所以最后我们需要调用ObDereferenceObject来减引用,代码如下://根据汇编逆向出来的IoGetDeviceObjectPointer NTSTATUS COSNVf::IoGetDeviceObjectPointNew(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject) { IO_STATUS_BLOCK ioStatus; OBJECT_ATTRIBUTES objectAttributes; PFILE_OBJECT fileObject; HANDLE fileHandle; NTSTATUS status; InitializeObjectAttributes(&objectAttributes, ObjectName, OBJ_KERNEL_HANDLE, (HANDLE)NULL, (PSECURITY_DESCRIPTOR)NULL); //这里的Open权限我改过了,原版的Open只有exc权限;结果我执行的环境一直失败,所以我改了权限; status = ZwOpenFile(&fileHandle, DesiredAccess, &objectAttributes, &ioStatus, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE); if(NT_SUCCESS(status)) { status = ObReferenceObjectByHandle(fileHandle, 0, *IoFileObjectType, 0, (PVOID *)&fileObject, 0); if(NT_SUCCESS(status)) { *FileObject = fileObject; *DeviceObject = IoGetRelatedDeviceObject(fileObject); } ZwClose(fileHandle); } return status; } //下面是在磁盘卷设备里获取磁盘signature的函数; NTSTATUS COSNFilter::GetDiskSignature(ULONG diskIndex, PULONG pDiskSignature) { NTSTATUS status; PWSTR ntNameBuffer; UNICODE_STRING ntNameUnicodeString; PFILE_OBJECT pDiskFileObject; PDEVICE_OBJECT pDiskDeviceObject, pDiskDeviceObjecttemp; ntNameUnicodeString.MaximumLength = 128 * sizeof(WCHAR); ntNameBuffer = (PWSTR) ExAllocatePoolWithTag(NonPagedPool, ntNameUnicodeString.MaximumLength, OSNTAG); if(!ntNameBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } //所需的设备名 swprintf(ntNameBuffer, L"\\Device\\Harddisk%d\\Partition0", diskIndex); RtlInitUnicodeString(&ntNameUnicodeString, ntNameBuffer); status = IoGetDeviceObjectPointer(&ntNameUnicodeString, FILE_READ_DATA, &pDiskFileObject, &pDiskDeviceObject); if(!NT_SUCCESS(status)) { status = IoGetDeviceObjectPointer(&ntNameUnicodeString, FILE_READ_ATTRIBUTES, &pDiskFileObject, &pDiskDeviceObject); } ExFreePool(ntNameBuffer); if (!NT_SUCCESS(status)) { return status; } PDEVICE_OBJECT pDevice = IoGetRelatedDeviceObject(pDiskFileObject); ULONG size = (128 * sizeof(PARTITION_INFORMATION) + 4); PDRIVE_LAYOUT_INFORMATION pDriveLayout = (PDRIVE_LAYOUT_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,size, OSNTAG); if (!pDriveLayout) { ObDereferenceObject(pDiskFileObject); return STATUS_INSUFFICIENT_RESOURCES; } //往下层设备同步下发,调用的是IoBuildDeviceIoControlRequest函数创建IRP status = COSNFilter::OSNDeviceIoctl(pDevice, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, pDriveLayout, size); if(NT_SUCCESS(status)) { *pDiskSignature = pDriveLayout->Signature; ExFreePool(pDriveLayout); } else { ExFreePool(pDriveLayout); size = (64 * sizeof(PARTITION_INFORMATION_EX) + 4); PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) ExAllocatePoolWithTag(NonPagedPool,size,OSNTAG); if(!pDriveLayoutEx) { ObDereferenceObject(pDiskFileObject); return STATUS_INSUFFICIENT_RESOURCES; } status = COSNFilter::OSNDeviceIoctl(pDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, pDriveLayoutEx, size); if(NT_SUCCESS(status)) { if(pDriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR) { *pDiskSignature = pDriveLayoutEx->Mbr.Signature; } else { RtlCopyMemory(pDiskSignature, &pDriveLayoutEx->Gpt.DiskId, sizeof(ULONG)); } } ExFreePool(pDriveLayoutEx); } ObDereferenceObject(pDiskFileObject); KdPrint(("OSNVf:GetDiskSignature %X sig %X", status, pDriveLayout->Signature)); ExFreePool(pDriveLayout); return status; }
4.ObReferenceObjectByName
这个函数微软是没有公开的,在所有WDK的.h文件里都无法找到,但用Dependency工具是可以查到ntoskrnl.exe是可以导出ObReferenceObjectByName这个函数的。在使用这个函数的时候,我么需要自己声明下这个函数以及函数中也未公开的参数类型;如果是C++编译的话还需要extern “C”。ObReferenceObjectByName和IoGetDeviceObjectPointer 区别在于后者只能获取设备对象的对象指针;而ObReferenceObjectByName还可以获取其他内核对象的指针,如Event,Mutex之类的;同样ObReferenceObjectByName使用完之后,也需要ObDereferenceObjec减引用计数;具体代码如下://对ObReferenceObjectByName和IoDriverObjectType 的声明 #ifdef __cplusplus extern "C" { #endif __cplusplus extern POBJECT_TYPE IoDeviceObjectType; NTSYSAPI NTSTATUS NTAPI ObReferenceObjectByName( IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess OPTIONAL, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, OUT PVOID* Object ); #ifdef __cplusplus } #endif __cplusplus
//调用方法 NTSTATUS GetDeviceName() { UNICODE_STRING DeviceName; NTSTATUS ntSattus; RtlInitUnicodeString( &DeviceName, L"\\device\\deviceA" ); PDEVICE_OBJECT pDeviceObject = NULL; PFILE_OBJECT FileObject = NULL; ntStatus = ObReferenceObjectByName(&DeviceName, OBJ_CASE_INSENSITIVE, NULL, FILE_ALL_ACCESS, IoDeviceObjectType, KernelMode, NULL, (PVOID*)&pDeviceObject ); if(!NT_SUCCESS(ntStatus)) { KdPrint(("FAILED TO GET OBJECT NAME \n")); } }
//我们还可以用ObReferenceObjectByName先根据驱动对象名获取驱动设备,然后再获取驱动设备中的设备对象;
5.IoGetDeviceAttachmentBaseRef
获取设备驱动堆栈或文件系统最底层的设备对象,获取最底层驱动方法比较多,比如设备AddDevice的时候传进来的参数就是PDO最底层设备对象。如果你是上层过滤驱动,可以DEVICEOBJECT->AttachedDevice 一层一层往下找,当然如果你没有attach的话是找不到的,这个和IoGetDeviceAttachmentBaseRef 类似,如果没有attach的话这个函数也会返回NULL的相关文章推荐
- 如何重装TCP/IP协议
- Windows 8 官方高清壁纸欣赏与下载
- 谁是桌面王者?Win PK Linux三大镇山之宝
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows Clang开发环境备忘
- 从Windows系统下访问Linux分区相关软件
- 对《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》一文的商榷
- Windows下搭建本地SVN服务器
- 使用Windows原生命令一键清空剪贴板
- windows用windeployqt发布qt quick application程序
- 利用开源软件打造自己的全功能远程工具
- Windows 8虚拟机不能全屏的解决方法
- 如何在 Linux 上安装设备驱动程序
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- Visual Studio 2012 示例代码浏览器 - 数以千计的开发示例近在手边,唾手可得
- 微软镜像下载
- windows server域用户提升到本地更高权限组中的方法