windbg中通过文件句柄查找设备(!handle/!fileobj/!devobj命令)

   有时,在驱动程序中会调用ZwCreateFile获得设备句柄,然后保存在设备扩展区域中供其他例程使用。由于驱动程序经常被动调用----执行的上下文可能不是同一个线程----会获得错误的句柄。那么是否存在某些调试命令供我们在开发阶段判断所用句柄正是某个设备的句柄?强大的windbg提供了!handle/!fileobj/!devobj这些扩展命令来实现这个目的(注意这些命令要正确设置调试符号的路径)。

    为了演示这些功能,我写了2个驱动:a.SampleChar,一个挂载在root总线之上的字符驱动,创建了一个名为\\Deivce\SampleChar的虚拟设备;b.FilterSampleChar,同样是挂载在root总线之上的虚拟字符驱动,创建了一个名为\\Device\FilterSample设备。应用程序打开设备\\Device\FilterSample时,FilterSampleChar在Create派遣函数中调用ZwCreateFile打开设备\\Deivce\SampleChar并获得句柄。下面是FilterSampleChar代码片段:

  1. NTSTATUS FilterSampleCharCreateClose(PDEVICE_OBJECT devObj, PIRP irp)  
  2. {  
  3.     HANDLE sampleCharDev;  
  4.     IO_STACK_LOCATION* currStack = IoGetCurrentIrpStackLocation(irp);  
  5.     NTSTATUS status = STATUS_SUCCESS;  
  6.     UNICODE_STRING devName;  
  7.     OBJECT_ATTRIBUTES fileAttr;  
  8.     IO_STATUS_BLOCK ioStatus;  
  9.     FilterSampleDriverCtx* devCtx = (FilterSampleDriverCtx*)devObj->DeviceExtension;  
  10.   
  11.     RtlInitUnicodeString(&devName, L"\\Device\\SampleChar");  
  12.     InitializeObjectAttributes(&fileAttr,   
  13.                             &devName,  
  14.                             OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,   
  15.                             NULL,NULL);  
  16.   
  17.     switch (currStack->MajorFunction)  
  18.     {  
  19.     case IRP_MJ_CREATE:  
  20.         status = ZwCreateFile(&sampleCharDev,   
  21.                         GENERIC_READ|SYNCHRONIZE,   
  22.                         &fileAttr,   
  23.                         &ioStatus,NULL,  
  24.                         FILE_ATTRIBUTE_NORMAL,  
  25.                         FILE_SHARE_READ,  
  26.                         FILE_OPEN_IF,   
  27.                         FILE_SYNCHRONOUS_IO_NONALERT,   
  28.                         NULL, 0);  
  29.   
  30.         if (status != STATUS_SUCCESS)    ----> 1)  
  31.         {  
  32.             irp->IoStatus.Information = 0;  
  33.             irp->IoStatus.Status = status;  
  34.             IoCompleteRequest(irp, IO_NO_INCREMENT);  
  35.             return status;  
  36.         }  
  37.         else  
  38.         {  
  39.             devCtx->targetDevHd = sampleCharDev;  
  40.         }  
  41.         break;  
  42.     case IRP_MJ_CLEANUP:  
  43.         ZwClose(devCtx->targetDevHd);  
  44.         break;  
  45.     }  
  46.     irp->IoStatus.Information = 0;  
  47.     irp->IoStatus.Status = STATUS_SUCCESS;  
  48.     IoCompleteRequest(irp, IO_NO_INCREMENT);  
  49.   
  50.     return status;  
  51. }  
NTSTATUS FilterSampleCharCreateClose(PDEVICE_OBJECT devObj, PIRP irp)
{
	HANDLE sampleCharDev;
	IO_STACK_LOCATION* currStack = IoGetCurrentIrpStackLocation(irp);
	NTSTATUS status = STATUS_SUCCESS;
	UNICODE_STRING devName;
	OBJECT_ATTRIBUTES fileAttr;
	IO_STATUS_BLOCK ioStatus;
	FilterSampleDriverCtx* devCtx = (FilterSampleDriverCtx*)devObj->DeviceExtension;

	RtlInitUnicodeString(&devName, L"\\Device\\SampleChar");
	InitializeObjectAttributes(&fileAttr, 
							&devName,
							OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, 
							NULL,NULL);

	switch (currStack->MajorFunction)
	{
	case IRP_MJ_CREATE:
		status = ZwCreateFile(&sampleCharDev, 
						GENERIC_READ|SYNCHRONIZE, 
						&fileAttr, 
						&ioStatus,NULL,
						FILE_ATTRIBUTE_NORMAL,
						FILE_SHARE_READ,
						FILE_OPEN_IF, 
						FILE_SYNCHRONOUS_IO_NONALERT, 
						NULL, 0);

		if (status != STATUS_SUCCESS)    ----> 1)
		{
			irp->IoStatus.Information = 0;
			irp->IoStatus.Status = status;
			IoCompleteRequest(irp, IO_NO_INCREMENT);
			return status;
		}
		else
		{
			devCtx->targetDevHd = sampleCharDev;
		}
		break;
	case IRP_MJ_CLEANUP:
		ZwClose(devCtx->targetDevHd);
		break;
	}
	irp->IoStatus.Information = 0;
	irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(irp, IO_NO_INCREMENT);

	return status;
}
在1)处下断点,然后执行测试程序,windbg马上就会停留在断点处:

  1. int main()  
  2. {  
  3.     char interfaceBuff[128] = { 0 };  
  4.     DWORD lstErr;  
  5.     char readBuff[4096] = { 0 };  
  6.     DWORD len = 0, writeLen, readLen;  
  7.   
  8.     hDev = CreateFileA("\\\\.\\filterSampleChar",  
  9.         GENERIC_ALL,  
  10.         FILE_SHARE_READ | FILE_SHARE_WRITE,  
  11.         NULL, OPEN_EXISTING, 0, NULL);  
int main()
{
	char interfaceBuff[128] = { 0 };
	DWORD lstErr;
	char readBuff[4096] = { 0 };
	DWORD len = 0, writeLen, readLen;

	hDev = CreateFileA("\\\\.\\filterSampleChar",
		GENERIC_ALL,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL, OPEN_EXISTING, 0, NULL);

首先查看返回句柄sampleCharDev的值:

  1. kd> ?? sampleCharDev  
  2. void * 0x80000918  
kd> ?? sampleCharDev
void * 0x80000918
句柄值0x80000918。随后,用!handle命令查看句柄信息

  1. kd> !handle 80000918   
  2.   
  3. PROCESS 877bbd40  SessionId: 1  Cid: 027c    Peb: 7ffda000  ParentCid: 08e0  
  4.     DirBase: 7ffd9480  ObjectTable: a1da6070  HandleCount:  13.  
  5.     Image: TestFilterSampleChar.exe  
  6.   
  7. Kernel handle table at 9d800000 with 485 entries in use  
  8.   
  9. 80000918: Object: 86d0f650  GrantedAccess: 00120089 Entry: 9d801230  
  10. Object: 86d0f650  Type: (87602938) File  
  11.     ObjectHeader: 86d0f638 (new version)  
  12.         HandleCount: 1  PointerCount: 1  
kd> !handle 80000918 

PROCESS 877bbd40  SessionId: 1  Cid: 027c    Peb: 7ffda000  ParentCid: 08e0
    DirBase: 7ffd9480  ObjectTable: a1da6070  HandleCount:  13.
    Image: TestFilterSampleChar.exe

Kernel handle table at 9d800000 with 485 entries in use

80000918: Object: 86d0f650  GrantedAccess: 00120089 Entry: 9d801230
Object: 86d0f650  Type: (87602938) File
    ObjectHeader: 86d0f638 (new version)
        HandleCount: 1  PointerCount: 1
这个命令显示了句柄所属的进程信息,对象信息:object 86d0f650,对象类型:file

知道这是文件对象后,可以通过!fileobj获得文件本身的信息:

  1. kd> !fileobj 86d0f650    
  2.   
  3. Device Object: 0x89bf1b18   \Driver\SampleChar  
  4. Vpb is NULL  
  5. Event signalled  
  6.   
  7. Flags:  0x40002  
  8.     Synchronous IO  
  9.     Handle Created  
  10.   
  11. CurrentByteOffset: 0  
kd> !fileobj 86d0f650  

Device Object: 0x89bf1b18   \Driver\SampleChar
Vpb is NULL
Event signalled

Flags:  0x40002
	Synchronous IO
	Handle Created

CurrentByteOffset: 0
通过这个命令,可知:这个文件是打开设备对象Device Object:0x89bf1b18时产生的文件句柄,该设备对象由驱动\Driver\SampleChar创建;另外还有一些文件指针信息,如CurrentByteOffset。
有了设备对象的地址,就可以通过!devstack命令获得设备信息:

  1. kd> !devstack 0x89bf1b18     
  2.   !DevObj   !DrvObj            !DevExt   ObjectName  
  3. > 89bf1b18  \Driver\SampleChar 89bf1bd0  SampleChar  
  4.   8761b980  \Driver\PnpManager 8761ba38  00000045  
  5. !DevNode 8761b7c8 :  
  6.   DeviceInst is "Root\SYSTEM\0003"  
  7.   ServiceName is "SampleChar"  
kd> !devstack 0x89bf1b18   
  !DevObj   !DrvObj            !DevExt   ObjectName
> 89bf1b18  \Driver\SampleChar 89bf1bd0  SampleChar
  8761b980  \Driver\PnpManager 8761ba38  00000045
!DevNode 8761b7c8 :
  DeviceInst is "Root\SYSTEM\0003"
  ServiceName is "SampleChar"
!devstack输出的设备栈信息和文章开头所列的代码意图一致,应该足以判断ZwCreateFile返回的设备句柄背后就是设备对象\\Device\SampleChar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值