读取另一驱动
驱动通过"\Driver\XueTr"获取到了XueTr工具的驱动,并Hook了XueTr驱动的分发函数。
具体的驱动代码如下:
1 //FilterDriver.c 2 //2016.07.15 3 4 #include "ntddk.h" 5 6 NTKERNELAPI 7 NTSTATUS 8 ObReferenceObjectByName( 9 IN PUNICODE_STRING ObjectName, 10 IN ULONG Attributes, 11 IN PACCESS_STATE PassedAccessState OPTIONAL, 12 IN ACCESS_MASK DesiredAccess OPTIONAL, 13 IN POBJECT_TYPE ObjectType, 14 IN KPROCESSOR_MODE AccessMode, 15 IN OUT PVOID ParseContext OPTIONAL, 16 OUT PVOID *Object 17 ); 18 19 extern POBJECT_TYPE *IoDriverObjectType; 20 21 //global 22 PDRIVER_OBJECT g_FilterDriverObject; 23 PDRIVER_DISPATCH gfn_OrigReadCompleteRoutine; 24 25 //我们的驱动分发函数 26 NTSTATUS FilterReadCompleteRoutine( 27 __in struct _DEVICE_OBJECT *DeviceObject, 28 __inout struct _IRP *Irp) 29 { 30 KdPrint(("IRP_MJ_DEVICE_CONTROL coming.")); 31 32 //处理完毕后,要调用原分发例程 33 return gfn_OrigReadCompleteRoutine(DeviceObject, Irp); 34 } 35 36 //驱动卸载函数 37 VOID UnFilterDriverRoutine(__in struct _DRIVER_OBJECT *DriverObject) 38 { 39 //此内存可读时,恢复 40 if (MmIsAddressValid(gfn_OrigReadCompleteRoutine)) 41 { 42 KdPrint(("UnFilterDriverRoutine Success.")); 43 44 //卸载时恢复原分发例程 45 g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = gfn_OrigReadCompleteRoutine; 46 } 47 } 48 49 //过滤函数 50 NTSTATUS FilterDriverQuery() 51 { 52 NTSTATUS Status; 53 UNICODE_STRING usObjectName; 54 55 RtlInitUnicodeString (&usObjectName, L"\Driver\XueTr"); 56 57 //根据驱动名称获得驱动对象 58 Status = ObReferenceObjectByName ( 59 &usObjectName, 60 OBJ_CASE_INSENSITIVE, //大小写不敏感 61 NULL, 62 0, //访问权限,0是所有权限 63 *IoDriverObjectType, 64 KernelMode, //处理器模式 65 NULL, 66 (PVOID*)&g_FilterDriverObject 67 ); 68 if (!NT_SUCCESS(Status)) 69 { 70 KdPrint(("Filter Failed!")); 71 return Status; 72 } 73 74 KdPrint(("0x%X", g_FilterDriverObject)); //打印驱动对象地址 75 76 //保存原分发例程,并修改为我们的函数 77 gfn_OrigReadCompleteRoutine = g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]; 78 g_FilterDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)FilterReadCompleteRoutine; 79 80 ObDereferenceObject(g_FilterDriverObject); //清除引用计数 81 82 return STATUS_SUCCESS; 83 } 84 85 86 //驱动程序入口函数 87 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) 88 { 89 pDriverObject->DriverUnload = UnFilterDriverRoutine; 90 FilterDriverQuery (); 91 92 return STATUS_SUCCESS; 93 }
其中,ObReferenceObjectByName函数能够根据驱动名获取到相应的驱动对象,函数原型如下:
1 NTKERNELAPI 2 NTSTATUS 3 ObReferenceObjectByName( 4 IN PUNICODE_STRING ObjectName, 5 IN ULONG Attributes, 6 IN PACCESS_STATE PassedAccessState OPTIONAL, 7 IN ACCESS_MASK DesiredAccess OPTIONAL, 8 IN POBJECT_TYPE ObjectType, 9 IN KPROCESSOR_MODE AccessMode, 10 IN OUT PVOID ParseContext OPTIONAL, 11 OUT PVOID *Object 12 );
由于ObReferenceObjectByName函数没有文档化,但是被导出了。所以我们需要在代码中对ObReferenceObjectByName函数进行声明。
另外调用ObReferenceObjectByName函数后,要调用ObDereferenceObject来清除对象的引用计数,否则会造成内存泄漏。
根据XueTr获取到XueTr的驱动对象地址是0x84F79858,大小是0x00068000
根据WinObj工具获得XueTr驱动的路径为"\Driver\XueTr"
用InstDrv安装并启动驱动FilterDriver.sys后,DbgView输出0x84F79858,此地址与上面用XueTr查看的地址相同。说明获取到的XueTr驱动对象的地址是正确的。
在WinDbg输入以下命令查看XueTr驱动的详细信息:
dt _DRIVER_OBJECT -b 84F79858
WinDbg输出如下:
1 lkd> dt_DRIVER_OBJECT -b 84F79858 2 nt!_DRIVER_OBJECT 3 +0x000 Type : 4 4 +0x002 Size : 168 5 +0x004 DeviceObject : 0x8617b100 6 +0x008 Flags : 0x12 7 +0x00c DriverStart : 0xed5ce000 8 +0x010 DriverSize : 0x68000 9 +0x014 DriverSection : 0x862e2220 10 +0x018 DriverExtension : 0x84f79900 11 +0x01c DriverName : _UNICODE_STRING "DriverXueTr" 12 +0x000 Length : 0x1a 13 +0x002 MaximumLength : 0x1a 14 +0x004 Buffer : 0xe1605358 "DriverXueTr" 15 +0x024 HardwareDatabase : 0x80691b90 16 +0x028 FastIoDispatch : (null) 17 +0x02c DriverInit : 0xed62b03e 18 +0x030 DriverStartIo : (null) 19 +0x034 DriverUnload : 0xed619668 20 +0x038 MajorFunction : 21 [00] 0xed619792 22 [01] 0x804fe101 23 [02] 0xed619792 24 [03] 0x804fe101 25 [04] 0x804fe101 26 [05] 0x804fe101 27 [06] 0x804fe101 28 [07] 0x804fe101 29 [08] 0x804fe101 30 [09] 0x804fe101 31 [10] 0x804fe101 32 [11] 0x804fe101 33 [12] 0x804fe101 34 [13] 0x804fe101 35 [14] 0xf7c37000 36 [15] 0x804fe101 37 [16] 0x804fe101 38 [17] 0x804fe101 39 [18] 0x804fe101 40 [19] 0x804fe101 41 [20] 0x804fe101 42 [21] 0x804fe101 43 [22] 0x804fe101 44 [23] 0x804fe101 45 [24] 0x804fe101 46 [25] 0x804fe101 47 [26] 0x804fe101 48 [27] 0x804fe101
上面代码中修改的分发函数是IRP_MJ_DEVICE_CONTROL,也就是14号分发例程(0至27)
XueTr驱动的14号分发函数地址为0xf7c37000
由XueTr知道我们的驱动FilterDriver.sys基地址为0xF7C36000,大小为0x00006000。
所以XueTr驱动的14号分发函数地址(0xf7c37000)在我们的驱动内(0xF7C36000~0xF7C36000+0x00006000)
然后当我们在XueTr工具内刷新时,DbgView内输出
IRP_MJ_DEVICE_CONTROL coming.
遍历所有驱动
遍历所有驱动需要用到一个结构_LDR_DATA_TABLE_ENTRY,具体的驱动代码如下:
1 //EnumDriver.c 2 //2016.07.17 3 4 #include <ntddk.h> 5 6 typedef struct _LDR_DATA_TABLE_ENTRY{ 7 LIST_ENTRY InLoadOrderLinks; //链表 保存了所有已经读取到内存中的驱动地址 8 LIST_ENTRY InMemoryOrderLinks; //链表 保存了已经安装,但没启动(没执行DriverEntry)的驱动地址 9 LIST_ENTRY InInitializationOrderLinks; //链表 保存了已经安装,同时也启动了(执行了DriverEntry)的驱动地址 10 PVOID DllBase; 11 PVOID EntryPoint; 12 ULONG SizeOfImage; 13 UNICODE_STRING FullDllName; 14 UNICODE_STRING BaseDllName; 15 ULONG Flags; 16 USHORT LoadCount; 17 USHORT TlsIndex; 18 LIST_ENTRY HashLinks; 19 PVOID SectionPointer; 20 ULONG CheckSum; 21 ULONG TimeDateStamp; 22 PVOID LoadedImports; 23 PVOID EntryPointActivationContext; 24 PVOID PatchInformation; 25 }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 26 27 VOID MyDriverUnload(PDRIVER_OBJECT pDriverObject) 28 { 29 // 30 KdPrint(("Unload EnumDriver.sys Success.")); 31 } 32 33 VOID EnumDriver(PDRIVER_OBJECT pDriverObject) 34 { 35 PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry, pTempLdrDataTableEntry; 36 PLIST_ENTRY pList; 37 int i = 0; 38 39 pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; 40 if (!MmIsAddressValid(pLdrDataTableEntry)) 41 { 42 return; 43 } 44 45 pList = &pLdrDataTableEntry->InLoadOrderLinks; 46 47 while (pList != pLdrDataTableEntry->InLoadOrderLinks.Blink) 48 { 49 //ToDo 50 pTempLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pList; 51 i++; 52 53 if(MmIsAddressValid(pTempLdrDataTableEntry)) 54 { 55 if (MmIsAddressValid(&pTempLdrDataTableEntry->BaseDllName) && MmIsAddressValid(&pTempLdrDataTableEntry->BaseDllName)) 56 KdPrint(("%d:%wZ %wZ", i, &pTempLdrDataTableEntry->BaseDllName, &pTempLdrDataTableEntry->FullDllName)); 57 } 58 59 pList = pList->Flink; 60 } 61 } 62 63 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) 64 { 65 pDriverObject->DriverUnload = MyDriverUnload; 66 EnumDriver(pDriverObject); 67 68 return STATUS_SUCCESS; 69 }
用Windbg在XP虚拟机下查看该结构
lkd> dt_LDR_DATA_TABLE_ENTRY nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY +0x008 InMemoryOrderLinks : _LIST_ENTRY +0x010 InInitializationOrderLinks : _LIST_ENTRY +0x018 DllBase : Ptr32 Void +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void
因为结构_LDR_DATA_TABLE_ENTRY是未导出的,所以要在代码开头定义一下:
1 typedef struct _LDR_DATA_TABLE_ENTRY{ 2 LIST_ENTRY InLoadOrderLinks; //链表 保存了所有已经读取到内存中的驱动地址 3 LIST_ENTRY InMemoryOrderLinks; //链表 保存了已经安装,但没启动(没执行DriverEntry)的驱动地址 4 LIST_ENTRY InInitializationOrderLinks; //链表 保存了已经安装,同时也启动了(执行了DriverEntry)的驱动地址 5 PVOID DllBase; 6 PVOID EntryPoint; 7 ULONG SizeOfImage; 8 UNICODE_STRING FullDllName; 9 UNICODE_STRING BaseDllName; 10 ULONG Flags; 11 USHORT LoadCount; 12 USHORT TlsIndex; 13 LIST_ENTRY HashLinks; 14 PVOID SectionPointer; 15 ULONG CheckSum; 16 ULONG TimeDateStamp; 17 PVOID LoadedImports; 18 PVOID EntryPointActivationContext; 19 PVOID PatchInformation; 20 }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
InLoadOrderLinks是一个双向的循环链表,保存了所有驱动的地址。我们只要遍历它,就能够找到所有的驱动了。
FullDllName是驱动的完整路径(路径+名称),BaseDllName是驱动的名称(不包含路径)
驱动加载后的输出如下:
其中的第二个 2:(null)(null)是XueTr的驱动,应该是做了特殊处理