• 通过 InLoadOrderLinks 遍历系统中所有的驱动


    我们的驱动在被系统加载的同时,内存中会出现一个描述我们驱动信息的对象:DRIVER OBJECT,而这个对象的地址,其实就保存在我们驱动的入口函数 Driver Entry 的第1个参数中。

    在 DriverObject 对象中,有一个 Driver Section 成员,它所指向的是一个名叫 _LDR_DATA_TABLE_ENTRY 的结构体,该结构体每个驱动模块都有一份,在这个结构体中就保存着一个驱动模块的所有信息。

    要想遍历系统中所有的驱动模块,这个结构体就是我们要重点关注的地方。先来看下该结构体的结构(看下第1个和第7个就行):

     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;//驱动的进入点 DriverEntry
     7     ULONG SizeOfImage;
     8     UNICODE_STRING FullDllName;//驱动的满路径
     9     UNICODE_STRING BaseDllName;//不带路径的驱动名字
    10     ULONG Flags;
    11     USHORT LoadCount;
    12     USHORT TlsIndex;
    13     union {
    14         LIST_ENTRY HashLinks;
    15         struct {
    16             PVOID SectionPointer;
    17             ULONG CheckSum;
    18         };
    19     };
    20     union {
    21         struct {
    22             ULONG TimeDateStamp;
    23         };
    24         struct {
    25             PVOID LoadedImports;
    26         };
    27     };
    28 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

    我们唯一需要关注的就是这个结构体的第一个成员:InLoadOrderLinks,它也是个结构体,有两个成员:Flink 和 Blink。看到这两个东西估计你已经能窥探出一些端倪了,没错,这是个链表。

    系统中有一个双向链表,其中每一个节点都保存着一个驱动模块的所有信息,而 InLoadOrderLinks 就是该链表中的节点类型,Flink 指向下一个驱动对象的  _LDR_DATA_TABLE_ENTRY,Blink 指向上一个驱动对象的 _LDR_DATA_TABLE_ENTRY。

    因此,我们只要遍历这个 InLoadOrderLinks ,就能获取系统中所有驱动的模块信息。例如,使用以下代码就能完成遍历所有驱动的操作:

     1 #include <ntddk.h>
     2 
     3 typedef struct _LDR_DATA_TABLE_ENTRY {
     4     LIST_ENTRY InLoadOrderLinks;//这个成员把系统所有加载(可能是停止没被卸载)已经读取到内存中 我们关系第一个  我们要遍历链表 双链表 不管中间哪个节点都可以遍历整个链表 本驱动的驱动对象就是一个节点
     5     LIST_ENTRY InMemoryOrderLinks;//系统已经启动 没有被初始化 没有调用DriverEntry这个历程的时候 通过这个链表进程串接起来
     6     LIST_ENTRY InInitializationOrderLinks;//已经调用DriverEntry这个函数的所有驱动程序
     7     PVOID DllBase;
     8     PVOID EntryPoint;//驱动的进入点 DriverEntry
     9     ULONG SizeOfImage;
    10     UNICODE_STRING FullDllName;//驱动的满路径
    11     UNICODE_STRING BaseDllName;//不带路径的驱动名字
    12     ULONG Flags;
    13     USHORT LoadCount;
    14     USHORT TlsIndex;
    15     union {
    16         LIST_ENTRY HashLinks;
    17         struct {
    18             PVOID SectionPointer;
    19             ULONG CheckSum;
    20         };
    21     };
    22     union {
    23         struct {
    24             ULONG TimeDateStamp;
    25         };
    26         struct {
    27             PVOID LoadedImports;
    28         };
    29     };
    30 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
    31 
    32 VOID DriverUnload(PDRIVER_OBJECT pDriverObject) {
    33     DbgPrint("Unloaded.");
    34 }
    35 
    36 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
    37 
    38     DbgPrint("Start Running...");
    39     pDriverObject->DriverUnload = DriverUnload;
    40     DbgPrint("对象基址:%x",pDriverObject);
    41     DbgPrint("驱动名:%ws",pDriverObject->DriverName.Buffer);
    42     DbgPrint("该驱动包含如下模块:");
    43     PLDR_DATA_TABLE_ENTRY p = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
    44     DbgPrint("DriverSection:%x",p);
    45     PLDR_DATA_TABLE_ENTRY item = (PLDR_DATA_TABLE_ENTRY)p->InLoadOrderLinks.Flink;
    46     DbgPrint("First LDR TABLE:%x",item);
    47     PLDR_DATA_TABLE_ENTRY first = item;
    48     while(item != NULL)
    49     {
    50         DbgPrint("%ws",item->FullDllName.Buffer);
    51         item = (PLDR_DATA_TABLE_ENTRY)item->InLoadOrderLinks.Flink;
    52         if(item == first)
    53             break;
    54     }
    55     return STATUS_SUCCESS;
    56 }

    这段代码唯一需要注意的是 “判断是否遍历结束”,因为是循环链表(即末尾节点的Flink指向起始节点),如果不加以判断将进入死循环。

    解决方法很简单,就如上面的代码中写的那样,将遍历的第一个节点的地址保存下来,然后开始遍历,只要遍历到的节点又和这个节点的地址相同,就说明已经遍历完成。

  • 相关阅读:
    curl获取HTTP返回状态码
    存储过程中如何实现从数组获取数据
    ElasticsearchParseException: malformed, expected settings to start with 'object', instead was [VALUE_STRING]
    【并发编程】如果让你用三个线程循环打印ABC,你有几种写法?
    【基础】IdentityHashMap
    【基础】ThreadPoolExecutor
    【算法】快速排序
    【Java8新特性Stream】list转map
    【算法】华为南研所-括号匹配
    windows sourceTree 密码错误
  • 原文地址:https://www.cnblogs.com/dubh3/p/13285103.html
Copyright © 2020-2023  润新知