5.2 Windows驱动开发:内核取KERNEL模块基址

2023-11-22 04:45

本文主要是介绍5.2 Windows驱动开发:内核取KERNEL模块基址,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

模块是程序加载时被动态装载的,模块在装载后其存在于内存中同样存在一个内存基址,当我们需要操作这个模块时,通常第一步就是要得到该模块的内存基址,模块分为用户模块和内核模块,这里的用户模块指的是应用层进程运行后加载的模块,内核模块指的是内核中特定模块地址,本篇文章将实现一个获取驱动ntoskrnl.exe的基地址以及长度,此功能是驱动开发中尤其是安全软件开发中必不可少的一个功能。

关于该程序的解释,官方的解析是这样的ntoskrnl.exeWindows操作系统的一个重要内核程序,里面存储了大量的二进制内核代码,用于调度系统时使用,也是操作系统启动后第一个被加载的程序,通常该进程在任务管理器中显示为System

使用ARK工具也可看出其代表的是第一个驱动模块。

那么如何使用代码得到如上图中所展示的基地址以及大小呢,实现此功能我们需要调用ZwQuerySystemInformation这个API函数,这与上一篇文章《判断自身是否加载成功》所使用的NtQuerySystemInformation只是开头部分不同,但其本质上是不同的,如下是一些参考资料;

  • 从内核模式调用NtZw系列API,其最终都会连接到nooskrnl.lib导出库:

    • Nt系列API将直接调用对应的函数代码,而Zw系列API则通过调用KiSystemService最终跳转到对应的函数代码。
    • 重要的是两种不同的调用对内核中previous mode的改变,如果是从用户模式调用Native APIprevious mode是用户态,如果从内核模式调用Native APIprevious mode是内核态。
    • 如果previous为用户态时Native API将对传递的参数进行严格的检查,而为内核态时则不会检查。

调用Nt API时不会改变previous mode的状态,调用Zw API时会将previous mode改为内核态,因此在进行Kernel Mode Driver开发时可以使用Zw系列API可以避免额外的参数列表检查,提高效率。Zw*会设置KernelMode已避免检查,Nt*不会自动设置,如果是KernelMode当然没问题,如果就UserMode就挂了。

回到代码上来,下方代码就是获取ntoskrnl.exe基地址以及长度的具体实现,核心代码就是调用ZwQuerySystemInformation得到SystemModuleInformation,里面的对比部分是在比较当前获取的地址是否超出了ntoskrnl的最大和最小范围。

#include <ntifs.h>static PVOID g_KernelBase = 0;
static ULONG g_KernelSize = 0;#pragma pack(4)
typedef struct _PEB32
{UCHAR InheritedAddressSpace;UCHAR ReadImageFileExecOptions;UCHAR BeingDebugged;UCHAR BitField;ULONG Mutant;ULONG ImageBaseAddress;ULONG Ldr;ULONG ProcessParameters;ULONG SubSystemData;ULONG ProcessHeap;ULONG FastPebLock;ULONG AtlThunkSListPtr;ULONG IFEOKey;ULONG CrossProcessFlags;ULONG UserSharedInfoPtr;ULONG SystemReserved;ULONG AtlThunkSListPtr32;ULONG ApiSetMap;
} PEB32, *PPEB32;typedef struct _PEB_LDR_DATA32
{ULONG Length;UCHAR Initialized;ULONG SsHandle;LIST_ENTRY32 InLoadOrderModuleList;LIST_ENTRY32 InMemoryOrderModuleList;LIST_ENTRY32 InInitializationOrderModuleList;
} PEB_LDR_DATA32, *PPEB_LDR_DATA32;typedef struct _LDR_DATA_TABLE_ENTRY32
{LIST_ENTRY32 InLoadOrderLinks;LIST_ENTRY32 InMemoryOrderLinks;LIST_ENTRY32 InInitializationOrderLinks;ULONG DllBase;ULONG EntryPoint;ULONG SizeOfImage;UNICODE_STRING32 FullDllName;UNICODE_STRING32 BaseDllName;ULONG Flags;USHORT LoadCount;USHORT TlsIndex;LIST_ENTRY32 HashLinks;ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
#pragma pack()typedef struct _RTL_PROCESS_MODULE_INFORMATION
{HANDLE Section;PVOID MappedBase;PVOID ImageBase;ULONG ImageSize;ULONG Flags;USHORT LoadOrderIndex;USHORT InitOrderIndex;USHORT LoadCount;USHORT OffsetToFileName;UCHAR  FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;typedef struct _RTL_PROCESS_MODULES
{ULONG NumberOfModules;RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;typedef enum _SYSTEM_INFORMATION_CLASS
{SystemModuleInformation = 0xb,
} SYSTEM_INFORMATION_CLASS;// 取出KernelBase基地址
// By: lyshark
PVOID UtilKernelBase(OUT PULONG pSize)
{NTSTATUS status = STATUS_SUCCESS;ULONG bytes = 0;PRTL_PROCESS_MODULES pMods = 0;PVOID checkPtr = 0;UNICODE_STRING routineName;if (g_KernelBase != 0){if (pSize)*pSize = g_KernelSize;return g_KernelBase;}RtlInitUnicodeString(&routineName, L"NtOpenFile");checkPtr = MmGetSystemRoutineAddress(&routineName);if (checkPtr == 0)return 0;__try{status = ZwQuerySystemInformation(SystemModuleInformation, 0, bytes, &bytes);if (bytes == 0){DbgPrint("Invalid SystemModuleInformation size\n");return 0;}pMods = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPoolNx, bytes, "lyshark");RtlZeroMemory(pMods, bytes);status = ZwQuerySystemInformation(SystemModuleInformation, pMods, bytes, &bytes);if (NT_SUCCESS(status)){PRTL_PROCESS_MODULE_INFORMATION pMod = pMods->Modules;for (ULONG i = 0; i < pMods->NumberOfModules; i++){if (checkPtr >= pMod[i].ImageBase &&checkPtr < (PVOID)((PUCHAR)pMod[i].ImageBase + pMod[i].ImageSize)){g_KernelBase = pMod[i].ImageBase;g_KernelSize = pMod[i].ImageSize;if (pSize)*pSize = g_KernelSize;break;}}}}__except (EXCEPTION_EXECUTE_HANDLER){return 0;}if (pMods)ExFreePoolWithTag(pMods, "lyshark");return g_KernelBase;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(("hello lyshark \n"));PULONG ulong = 0;UtilKernelBase(ulong);DbgPrint("ntoskrnl.exe 模块基址: 0x%p \n", g_KernelBase);DbgPrint("模块大小: 0x%p \n", g_KernelSize);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

我们编译并运行上方代码,效果如下:

这篇关于5.2 Windows驱动开发:内核取KERNEL模块基址的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/407601

相关文章

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Windows系统宽带限制如何解除?

《Windows系统宽带限制如何解除?》有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文就跟大家一起来看看Windows系统解除网络限制的操作方法吧... 有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Windows 上如果忘记了 MySQL 密码 重置密码的两种方法

《Windows上如果忘记了MySQL密码重置密码的两种方法》:本文主要介绍Windows上如果忘记了MySQL密码重置密码的两种方法,本文通过两种方法结合实例代码给大家介绍的非常详细,感... 目录方法 1:以跳过权限验证模式启动 mysql 并重置密码方法 2:使用 my.ini 文件的临时配置在 Wi

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Python中的getopt模块用法小结

《Python中的getopt模块用法小结》getopt.getopt()函数是Python中用于解析命令行参数的标准库函数,该函数可以从命令行中提取选项和参数,并对它们进行处理,本文详细介绍了Pyt... 目录getopt模块介绍getopt.getopt函数的介绍getopt模块的常用用法getopt模