看的是网上别人的代码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的末尾
#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--;
}
}