遍历Device Tree

看的是网上别人的代码https://github.com/MartinDrab/VrtuleTree

  • 通过ZwOpenDirectoryObject, ZwQueryDirectoryObject,打开"\Driver"和"\FileSystem", 遍历得到所有的驱动名
  • 有了驱动名,通过ObReferenceObjectByName 得到 DriverObject,然后遍历 DeviceObject链

一些函数和结构

typedef struct _OBJECT_DIRECTORY_INFORMATION {
    UNICODE_STRING Name;
    UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;

ZwQueryDirectoryObject(
  _In_      HANDLE  DirectoryHandle,
  _Out_opt_ PVOID   Buffer,                       // OBJECT_DIRECTORY_INFORMATION 结构
  _In_      ULONG   Length,
  _In_      BOOLEAN ReturnSingleEntry,            // TRUE 一次返回一个,   FALSE 一次全部返回
  _In_      BOOLEAN RestartScan,                  // FALSE 不重新遍历,   TRUE  重新遍历
  _Inout_   PULONG  Context,
  _Out_opt_ PULONG  ReturnLength
){...}
所以要么是ZwQueryDirectoryObject(,,,TRUE,FALSE,,) 每次返回一个
   要么是ZwQueryDirectoryObject(,,,FALSE,TRUE,,) 一次性返回所有 
typedef struct _OBJECT_HEADER_NAME_INFO{	
	POBJECT_DIRECTORY        Directory;
	UNICODE_STRING           Name;                  // 返回这个
	ULONG                    ReferenceCount;
}OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;

ObQueryNameString(object) 
{
      ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
      NameInfo = ObpReferenceNameInfo( ObjectHeader );  //      是 POBJECT_HEADER_NAME_INFO 结构,  ObjectHeader - (ObjectHeader)->NameInfoOffset;
                                                        //      #define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) \
                                                        //        ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))

       // 一般来说这个是NULL,而 Object Hook 就是设置ObjectHeader->Type->TypeInfo下面的各种Procedure
      if (ObjectHeader->Type->TypeInfo.QueryNameProcedure != NULL) { 
            Status = (*ObjectHeader->Type->TypeInfo.QueryNameProcedure)( Object,
                                                                         (BOOLEAN)((NameInfo != NULL) && (NameInfo->Name.Length != 0)),
                                                                         ObjectNameInfo,
                                                                         Length,
                                                                         ReturnLength );
            ...
      }

      ...

      return NameInfo->Name;
}
IoGetDiskDeviceObject( 
      IN  PDEVICE_OBJECT  FileSystemDeviceObject, 
      OUT PDEVICE_OBJECT  *DiskDeviceObject 
){
	*DiskDeviceObject = FileSystemDeviceObject->DeviceObjectExtension->Vpb->RealDevice; // 如果有的话,返回的是这个
}

例如:
lkd> !drvobj \filesystem\ntfs                           // ...
Driver object (8a0e2238) is for:
 \FileSystem\Ntfs
Driver Extension List: (id , addr)

Device Object list:
8953b770  88806770  8a0ae020  896ad030                   
-
lkd> dt _device_object 8953b770                                 // FileSystemDeviceObject
nt!_DEVICE_OBJECT 
   +0x000 Type             : 0n3
   +0x002 Size             : 0x860
   ...
   +0x09c DeviceLock       : _KEVENT
   +0x0ac SectorSize       : 0x200
   +0x0ae Spare1           : 1
   +0x0b0 DeviceObjectExtension : 0x8953bfd0 _DEVOBJ_EXTENSION  //
   +0x0b4 Reserved         : (null) 
-
lkd> dt _devobj_extension 8953bfd0                              // FileSystemDeviceObject->DeviceObjectExtension
nt!_DEVOBJ_EXTENSION
   +0x000 Type             : 0n13
   ...
   +0x024 StartIoFlags     : 0
   +0x028 Vpb              : 0x8a1a7240 _VPB                    //
-
lkd> dt _vpb 8a1a7240                                           // FileSystemDeviceObject->DeviceObjectExtension->Vpb
nt!_VPB
   +0x000 Type             : 0n10
   ...
   +0x00c RealDevice       : 0x8a0e3898 _DEVICE_OBJECT          // FileSystemDeviceObject->DeviceObjectExtension->Vpb->RealDevice
   +0x010 SerialNumber     : 0x8b0e472a
   +0x014 ReferenceCount   : 0x40
   +0x018 VolumeLabel      : [32] 0x6587
-
IoGetNextIrpStackLocation( Irp )  { (Irp)->Tail.Overlay.CurrentStackLocation - 1  },  为什么要用这个函数,为什么要-1,主要是因为

     IoAllocateIrp(Irp){...} 里调用了下面这个定义,可以看到CurrentStackLocation 指向的不是最后一个,而是最后一个的末尾
	      #define IopInitializeIrp( Irp, PacketSize, StackSize ) {            \   // StackSize为设备栈的层数,每层一个StackLocation
    	            ...
    	            (Irp)->Tail.Overlay.CurrentStackLocation =                    \
        	      ((PIO_STACK_LOCATION) ((UCHAR *) (Irp) +                    \
            	      sizeof( IRP ) +                                             \
            	      ( (StackSize) * sizeof( IO_STACK_LOCATION )))); } 	      // 指向最后一个末尾

另外设备栈里的设备,最上面的设备,它的IO_STACK_LOCATION是在最下面, 例如有4个设备从高到低,1-2-3-4, 那他的IO_STACK_LOCATION 存放是如下,4-3-2-1
Irp  -
IO_STACK_LOCATION 
低 【4】-        <- 最底层的设备,它的stack 最高,通过一层层的 -1,到达这里
   【3】
   【2】  	<-  本层进入IoCallDriver之前,(Irp)->Tail.Overlay.CurrentStackLocation 指向的是【1】
高 【1】  	<-  IoCallDriver函数里会调用IoGetNextIrpStackLocation ,这样就指向【1】了。 如果想修改【2】的内容,通过IoGetNextIrpStackLocation
        	<-  初始化,IoAllocateIrp 后 (Irp)->Tail.Overlay.CurrentStackLocation指向这里,stack的末尾

if (DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) // DeviceObject里 Flags 的属性, 参考 :https://blog.csdn.net/u011471873/article/details/51339995

#define DO_DEVICE_HAS_NAME                  0x00000040         
#define DO_BUS_ENUMERATED_DEVICE            0x00001000 

下面是个人电脑上网卡设备。 设备管理器->网络适配器->自己使用的那个无线网卡,看"属性"里面驱动程序

lkd> !drvobj netwlx32                                                                  
Driver object (8a05f730) is for:
 \Driver\NETwLx32
Driver Extension List: (id , addr)
(4e4d4944 895d9980)  
Device Object list:
895ca030  
-
lkd> !devstack 895ca030
  !DevObj   !DrvObj            !DevExt   ObjectName
> 895ca030  \Driver\NETwLx32   895ca0e8  {538C9000-F540-4327-8235-59E6653436EC}
  8a0ca2f0  \Driver\PCI        8a0ca3a8  NTPNP_PCI0024                              // 挂在这里 (8a0ca2f0  )
!DevNode 8a010ee8 :
  DeviceInst is "PCI\VEN_8086&DEV_4230&SUBSYS_11108086&REV_61\4&eb37384&0&00E1"
  ServiceName is "NETwLx32"
-
lkd> dt _device_object 8a0ca2f0  
nt!_DEVICE_OBJECT
   +0x000 Type             : 0n3
   ...
   +0x01c Flags            : 0x1040                                                 // DO_BUS_ENUMERATED_DEVICE | DO_DEVICE_HAS_NAME                           
   +0x020 Characteristics  : 0x100
   +0x024 Vpb              : (null) 
   ...
   +0x0ae Spare1           : 1
   +0x0b0 DeviceObjectExtension : 0x8a0ca470 _DEVOBJ_EXTENSION                      //  _devobj_extension, 0x8a0ca470 
   +0x0b4 Reserved         : (null) 
-
lkd> dt _devobj_extension 8a0ca470
nt!_DEVOBJ_EXTENSION
   +0x000 Type             : 0n13
   ...
   +0x014 DeviceNode       : 0x8a010ee8 Void                                        //  _device_node, 0x8a010ee8 
   ...
   +0x028 Vpb              : (null) 
-
lkd> dt _device_node 8a010ee8
nt!_DEVICE_NODE
   +0x000 Sibling          : (null)                                                 // 同一级
   +0x004 Child            : (null)                                                 // 子级
   +0x008 Parent           : 0x8a1a6828 _DEVICE_NODE                                // 父级
   ...
   +0x088 PhysicalDeviceObject : 0x8a0ca2f0 _DEVICE_OBJECT
   +0x08c ResourceList     : 0xe18113c0 _CM_RESOURCE_LIST
   +0x090 ResourceListTranslated : 0xe182e1e0 _CM_RESOURCE_LIST
   +0x094 InstancePath     : "PCI\VEN_8086&DEV_4230&SUBSYS_11108086&REV_61\4&eb37384&0&00E1" // "属性"里面"详细信息"-"设备范例 Id"
   +0x09c ServiceName      : _UNICODE_STRING "NETwLx32"
   +0x0a4 DuplicatePDO     : (null) 
   +0x0a8 ResourceRequirements : 0xe1013930 _IO_RESOURCE_REQUIREMENTS_LIST
   +0x0ac InterfaceType    : 0xffffffff (No matching name)
   +0x0b0 BusNumber        : 0xfffffff0
   +0x0b4 ChildInterfaceType : 5 ( PCIBus )
   +0x0b8 ChildBusNumber   : 3                                                       // 这个是设备的总线number?
   +0x0bc ChildBusTypeIndex : 0
   ...
   +0x114 DriverUnloadRetryCount : 0

=======
IoGetDeviceProperty (DevicePropertyBusNumber)
      case DevicePropertyBusNumber:
        if ((deviceNode->ChildBusNumber & 0x80000000) != 0x80000000) 
                *(PULONG)PropertyBuffer = deviceNode->ChildBusNumber;                // 总线number?

IoGetLowerDeviceObject(DeviceObject){return DeviceObject->DeviceObjectExtension->AttachedTo;}  // 当前设备挂在哪个设备上,也就是设备栈的低一层设备(竖向)

IoGetAttachedDeviceReference(DeviceObject)  {          // 获得设备栈的顶层设备(竖向)
	irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
        // 循环遍历到设备栈的顶层
    	DeviceObject = IoGetAttachedDevice (DeviceObject);  ////  while (DeviceObject->AttachedDevice) { DeviceObject = DeviceObject->AttachedDevice;}
    	ObReferenceObject (DeviceObject);
   	 KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
	return DeviceObject ;
}
IoEnumerateDeviceObjectList(DriverObject,DeviceObjectList){               // 遍历同一层的所有设备(横向), 返回到DeviceObjectList里面
	deviceObject = DriverObject->DeviceObject;
    	while (deviceObject) { numDeviceObjects++; deviceObject = deviceObject->NextDevice; }  // driver下device的总数
	numListEntries = DeviceObjectListSize / sizeof(PDEVICE_OBJECT);                        // DeviceObjectList 能容纳的device的个数
	while ((numListEntries > 0) && deviceObject) {
        	 *DeviceObjectList = deviceObject;                        // 依次加入到 DeviceObjectList
       		 DeviceObjectList++;
        	 deviceObject = deviceObject->NextDevice;
       		 numListEntries--;
        }
}
posted @ 2020-11-10 19:22  一条小鳄鱼  阅读(497)  评论(0)    收藏  举报