代码改变世界

梦织未来Windows驱动编程 第05课 小结(读取另一驱动,遍历所有驱动)

2016-07-15 15:24  yusuf  阅读(1779)  评论(0编辑  收藏  举报

读取另一驱动

驱动通过"\\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 }
FilterDriver.c

 

 

其中,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 "\Driver\XueTr"
12       +0x000 Length           : 0x1a
13       +0x002 MaximumLength    : 0x1a
14       +0x004 Buffer           : 0xe1605358  "\Driver\XueTr"
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\t%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 }
EnumDriver.c

 

 

用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的驱动,应该是做了特殊处理