• 驱动中遍历模块,以及获取ntoskrnl.exe基址


    方法是基于PsLoadModuleList方式

    驱动中遍历模块

    一丶简介

    简介:

    进入内核了.遍历内核中使用的模块该怎么办. 其实在驱动中.我们的DriverEntry入口位置.
    提供了两个参数. 一个是DrIverObject另一个则是注册表路径.

    其实遍历模块的技巧就在这个DriverObject中.

    众所周知在Ring3下遍历模块可以通过TEB PEB遍历. 我们会接触一个结构体叫做LDR_DATA_TABLE_ENTRY的结构体.
    内核中也会使用这个结构体. 看下DriverObject对象所代表的含义.

    
    typedef struct _DRIVER_OBJECT {
        CSHORT Type;
        CSHORT Size;
    
        PDEVICE_OBJECT DeviceObject;                //驱动对象
        ULONG Flags;                                //驱动的标志
    
    
        PVOID DriverStart;                          //驱动的起始位置
        ULONG DriverSize;                           //驱动的大小
        PVOID DriverSection;                        //指向驱动程序映像的内存区对象
        PDRIVER_EXTENSION DriverExtension;          //驱动的扩展空间
    
        UNICODE_STRING DriverName;                  //驱动名字
    
        PUNICODE_STRING HardwareDatabase;
    
    
        PFAST_IO_DISPATCH FastIoDispatch;
    
    
        PDRIVER_INITIALIZE DriverInit;
        PDRIVER_STARTIO DriverStartIo;
        PDRIVER_UNLOAD DriverUnload;
        PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
    
    } DRIVER_OBJECT;
    typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; 
    
    

    在这里主要使用 DriverSection这个成员 这个成员则可以解释为LDR_DATA_TABLE_ENTRY结构体.
    里面存放着我们的所有模块.

    
    typedef struct _LDR_DATA_TABLE_ENTRY {
    	LIST_ENTRY InLoadOrderLinks;               //链表存储,指向下一个LDR_DATA_TABLE_ENTRY结构
    	LIST_ENTRY InMemoryOrderLinks;
    	LIST_ENTRY InInitializationOrderLinks;
    	PVOID DllBase;                             //基址
    	PVOID EntryPoint;
    	ULONG SizeOfImage;
    	UNICODE_STRING FullDllName;
    	UNICODE_STRING BaseDllName;                //存放着驱动模块名
    	ULONG Flags;
    	USHORT LoadCount;
    	USHORT TlsIndex;
    	union {
    		LIST_ENTRY HashLinks;
    		struct {
    			PVOID SectionPointer;
    			ULONG CheckSum;
    		};
    	};
    	union {
    		struct {
    			ULONG TimeDateStamp;
    		};
    		struct {
    			PVOID LoadedImports;
    		};
    	};
    }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
    
    

    所以代码就很简单了.直接遍历自身结构体的 DriverSection成员即可.解释为(LDR_DATA_TABLE_ENTRY)结构.

    二丶代码以及演示.

    #include "Driver.h" //这个替换为自己的. 包含Ntddk.h即可.
    #include <wdm.h>
    
    //KLDR_DATA_TABLE_ENTRY
    
    typedef struct _LDR_DATA_TABLE_ENTRY {
    	LIST_ENTRY InLoadOrderLinks;
    	LIST_ENTRY InMemoryOrderLinks;
    	LIST_ENTRY InInitializationOrderLinks;
    	PVOID DllBase;
    	PVOID EntryPoint;
    	ULONG SizeOfImage;
    	UNICODE_STRING FullDllName;
    	UNICODE_STRING BaseDllName;
    	ULONG Flags;
    	USHORT LoadCount;
    	USHORT TlsIndex;
    	union {
    		LIST_ENTRY HashLinks;
    		struct {
    			PVOID SectionPointer;
    			ULONG CheckSum;
    		};
    	};
    	union {
    		struct {
    			ULONG TimeDateStamp;
    		};
    		struct {
    			PVOID LoadedImports;
    		};
    	};
    }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
    
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
    {
    	ULONG iCount = 0;
    	NTSTATUS ntStatus;
    	pDriverObj->DriverUnload = DriverUnLoad;
    
    	KdBreakPoint();
    
    	/*
    	主要是遍历DriverObject中的 DriverSection 它可以解释为LDR_DATA_TABLE_ENTRY结构体
    	*/
    
    	
    	PLDR_DATA_TABLE_ENTRY pLdr = NULL;
    	PLIST_ENTRY pListEntry = NULL;
    	PLIST_ENTRY pCurrentListEntry = NULL;
    
    	PLDR_DATA_TABLE_ENTRY pCurrentModule = NULL;
    	pLdr = (PLDR_DATA_TABLE_ENTRY)pDriverObj->DriverSection;
    	pListEntry = pLdr->InLoadOrderLinks.Flink;
    	pCurrentListEntry = pListEntry->Flink;
    
    	while (pCurrentListEntry != pListEntry) //前后不相等
    	{
    		//获取LDR_DATA_TABLE_ENTRY结构
    		pCurrentModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
    		
    			if (pCurrentModule->BaseDllName.Buffer != 0)
    			{
    				DbgPrint("ModuleName = %wZ ModuleBase = %p 
    ", 
    					pCurrentModule->BaseDllName,
    				 pCurrentModule->DllBase);
    			}
    			pCurrentListEntry = pCurrentListEntry->Flink;
    	}
    	return STATUS_SUCCESS;
    }
    
    

    结果.

    代码简单改一下.还可以获得指定的模块的基址以及结束地址.

    代码如下

    VOID GetModuleBaseByName(PDRIVER_OBJECT pDriverObj,UNICODE_STRING ModuleName)
    {
    	PLDR_DATA_TABLE_ENTRY pLdr = NULL;
    	PLIST_ENTRY pListEntry = NULL;
    	PLIST_ENTRY pCurrentListEntry = NULL;
    
    	PLDR_DATA_TABLE_ENTRY pCurrentModule = NULL;
    	pLdr = (PLDR_DATA_TABLE_ENTRY)pDriverObj->DriverSection;
    	pListEntry = pLdr->InLoadOrderLinks.Flink;
    	pCurrentListEntry = pListEntry->Flink;
    
    	while (pCurrentListEntry != pListEntry) //前后不相等
    	{
    		//获取LDR_DATA_TABLE_ENTRY结构
    		pCurrentModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
    
    		if (pCurrentModule->BaseDllName.Buffer != 0)
    		{
    		
    			if (RtlCompareUnicodeString(&pCurrentModule->BaseDllName, &ModuleName, TRUE) == 0)
    			{
    				DbgPrint("ModuleName = %wZ ModuleBase = %p ModuleEndBase = %p
    ",
    					pCurrentModule->BaseDllName,
    					pCurrentModule->DllBase,
    					(LONGLONG)pCurrentModule->DllBase + pCurrentModule->SizeOfImage);
    			}
    			
    		}
    		pCurrentListEntry = pCurrentListEntry->Flink;
    	}
    }
    
  • 相关阅读:
    Linq to SQL -- 入门篇
    进程和线程(线程是轻量级进程)(上)
    复制文件夹中的所有文件夹与文件到另一个文件夹
    C# 特性(Attribute)
    文件的输入与输出
    正则表达式
    预处理指令
    String类
    可空类型(Nullable)
    参数传递
  • 原文地址:https://www.cnblogs.com/iBinary/p/11693606.html
Copyright © 2020-2023  润新知