内核空间与内核模块

前言:内核空间与内核模块的学习笔记

内核空间概念

interlX86下每个进程都有4GB的虚拟内存空间下,其中高2G是共享的内核空间,在低2G的私有内存也就是用户空间

内核模块概念

1、硬件种类繁多,不可能做一个兼容所有硬件的内核,所以,微软提供规定的接口格式,让硬件驱动人员安装规定的格式编写"驱动程序"。

2、这些驱动程序每一个都是一个模块,称为"内核模块",都可以加载到内核中,都遵守PE结构。但本质上讲,任意一个.sys文件与内核文件没有区别。

知识点:驱动程序和应用程序本质上讲其实没有区别,都是遵守了PE结构,.sys其实和.exe是一样的,唯一不同的就是后缀名和所在的运行空间还有入口函数

DRIVER_OBJECT结构体

每一个被加载的驱动模块sys都会有一个驱动对象DRIVER_OBJECT来描述当前驱动模块的信息,如下所示,这个值保存的是当前驱动模块对象DRIVER_OBJECT

通过windbg来进行查看对应的结构体,命令为dt _DRIVER_OBJECT

kd> dt _driver_object
ntdll!_DRIVER_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x008 Flags            : Uint4B
   +0x00c DriverStart      : Ptr32 Void
   +0x010 DriverSize       : Uint4B
   +0x014 DriverSection    : Ptr32 Void
   +0x018 DriverExtension  : Ptr32 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING
   +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
   +0x028 FastIoDispatch   : Ptr32 _FAST_IO_DISPATCH
   +0x02c DriverInit       : Ptr32     long 
   +0x030 DriverStartIo    : Ptr32     void 
   +0x034 DriverUnload     : Ptr32     void 
   +0x038 MajorFunction    : [28] Ptr32     long 

通过DRIVER_OBJECT找到当前模块信息:

DbgPrint("DRIVER_OBJECT对象地址:%x\n",driver);
DbgPrint("驱动名称:%ws\n",driver->DriverName.Buffer);
DbgPrint("模块基址:%x\n",driver->DriverStart);
DbgPrint("模块大小:%x\n",driver->DriverSize);

结果如下图所示:

这里还可以查看已加载的驱动模块的结构体,通过dt _DRIVER_OBJECT 当前DRIVER_OBJECT的地址,上面可以看到对应的驱动模块基址0x86b58ae8

dt _DRIVER_OBJECT 0x86b58ae8,可以看到相关的驱动名称

+0x00c DriverStart : 0xf79b6000 Void

模块在高2G内存中的起始位置:+0x00c DriverStart : 0xf79b6000 Void

模块的大小:+0x010 DriverSize : 0x6000

模块的名称:+0x01c DriverName : _UNICODE_STRING "\Driver\WinDriverStudy01"

该模块DriverSection(偏移为0x014)实际上就是一个LDR_DATA_TABLE_ENTRY结构体,它跟三环下的PEB相关的LDR_DATA_TABLE_ENTRY结构体一样

dt _LDR_DATA_TABLE_ENTRY DriverSection的地址

这里还可以通过双向链表来进行遍历,如下图所示

练习1

遍历内核模块,输出模块名称,基址以及大小

#include <ntddk.h>

typedef struct _PEB_LDR_DATA
{
	ULONG Length;
	BOOLEAN Initialized;
	PVOID SsHandle;
	LIST_ENTRY InLoadOrderModuleList;          //代表按加载顺序构成的模块列表
	LIST_ENTRY InMemoryOrderModuleList;            //代表按内存顺序构成的模块列表
	LIST_ENTRY InInitializationOrderModuleList; //代表按初始化顺序构成的模块链表
}PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderModuleList;  //代表按加载顺序构成的模块列表
	LIST_ENTRY InMemoryOrderModuleList;    //代表按内存顺序构成的模块列表
	LIST_ENTRY InInitializeationOrderModuleList; //代表按初始化顺序构成的模块链表
	PVOID DllBase;     //该模块的基地址
	PVOID EntryPoint;  //该模块的入口
	ULONG SizeOfImage; //该模块的影像大小
	UNICODE_STRING FullDllName;    //模块的完整路径
	UNICODE_STRING BaseDllName;    //模块名
	ULONG Flags;
	SHORT LoadCount;
	SHORT TlsIndex;
	HANDLE SectionHandle;
	ULONG CheckSum;
	ULONG TimeDataStamp;
}LDR_MODULE, *PLDR_MODULE;

VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint(("Uninstall Driver Is OK \n"));
}

void getAllDriverModules(PDRIVER_OBJECT Driver)
{
	__try{
		// 遍历内核模块,输出模块名称,基址以及大小
		LDR_MODULE* pLdrModule = NULL;
		pLdrModule = (LDR_MODULE*)(*(ULONG*)((CHAR*)Driver + 0x14));
		while (pLdrModule->DllBase != NULL)
		{
			DbgPrint("DllName: %ws DllBase: 0x%x, SizeOfImage: 0x%x\n", pLdrModule->BaseDllName.Buffer, pLdrModule->DllBase, pLdrModule->SizeOfImage);
			pLdrModule = (LDR_MODULE*)pLdrModule->InLoadOrderModuleList.Blink;
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		DbgPrint("Exception Error...");
	}
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint(("hello zpchcbd \n"));
	getAllDriverModules(Driver);
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

posted @ 2022-02-26 14:21  zpchcbd  阅读(273)  评论(0)    收藏  举报