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;
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/172857.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE4基础篇十七:分析性能

一、性能瓶颈定位 原文地址:小能猫吃牙膏:UE4 性能 - (一)瓶颈定位 P.S. 对于某个具体问题,我个人偏向于遵循 WHY → WHAT → HOW 的思考方法(重要性逐级递减) 加以理解。因为如果找不到做某件事情的意义(WHY)所在,或是对这件事情本身的定义(WHAT)都模棱两可,那么即便经…

一文读懂 Linux 网络 IO 模型

文章目录 1.从一个问题说起2.多进程模型3.多线程模型4.I/O 多路复用5.select、poll、epoll 的区别&#xff1f;5.1 select5.2 poll5.3 epoll5.4 两种事件触发模式 参考文献 1.从一个问题说起 互联网发展历史上&#xff0c;曾经有一个著名的问题&#xff1a;C10K 问题。 C 是 …

el-form动态表单动态验证(先验证不为空,再验证长度在20以内,最后向后台发送请求验证账号是否重复)

data(){var checkSno (rule, value, callback) > {if (!value) {callback(new Error("请输入账号"));} else if (value.length > 20) {callback(new Error("长度为1-20"));} else {if (this.form.id) {// 修改时检查账号是否重复selectLoginId({ sn…

Python Opencv实践 - 二维码和条形码识别

使用pyzbar模块来识别二维码和条形码。ZBar是一个开源软件&#xff0c;用来从图像中读取条形码&#xff0c;支持多种编码,比如EAN-13/UPC-A、UPC-E、EAN-8、代码128、代码39、交错2/5以及二维码。 pyzbar是python封装ZBar的模块&#xff0c;我们用它来做条形码和二维码的识别。…

2021年03月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 小猫在沙漠中旅行好不容易找到了一杯水,初始位置如下图所示,下面哪个程序可以帮助它成功喝到水? A: B: C: D:

观光奶牛 (01分数规划、负环)

01分数规划问题&#xff1a;类似于观光奶牛这个题中的&#xff0c;求的路径上的点权值和与边权值和的商最大最小。 当前问题的推到如下&#xff1a; 该问题其实可以用二分图来解决&#xff0c; 在不断的二分答案中获取符合条件的最大值。然后问题就转化为如何是否存在和为mid的…

linux之chmod命令

在linux系统中经常遇到需要对文件修改读写执行的权限&#xff0c;下面对chomod命令进行梳理总结。 1、文件权限 在linux系统中&#xff0c;每个文件都有归属的所有者和所有组&#xff0c;并且规定了文件的所有者、以及其他人对文件所拥有的可读&#xff08;r&#xff09;、可写…

线程(线程基本概念、java实现多线程、使用多线程、线程的生命周期、线程同步、线程死锁)

&#xff08;一&#xff09;线程基本概念 一、 程序, 进程, 线程的概念 程序: 使用某种语言编写一组指令(代码)的集合,静态的 进程: 运行的程序,表示程序一次完整的执行, 当程序运行完成, 进程也就结束了 个人电脑: CPU 单个, 双核, CPU的时间分片, 抢占式 每个独立执行的程…

整套数字化招采平台安全防御体系

招采平台作为数字化供应链的重要组成部分&#xff0c;需要确保招标采购过程的安全性,主体信息和交易数据信息尤为重要,通过必要的安全架构、技术和安全管理制度&#xff0c;做到事前防范、事中监管和事后审计的安全防御。 一、平台技术安全架构 1、先进的技术架构&#xff0c…

算法设计与分析复习--回溯(一)

文章目录 上一篇回溯法性质子集和问题装载问题下一篇 上一篇 算法设计与分析复习–贪心&#xff08;二&#xff09; 回溯法性质 类似穷举的搜索尝试过程&#xff0c;在搜索尝试过程中寻找问题的解&#xff0c;组织得井井有条&#xff08;避免遗漏&#xff09;&#xff0c; 高…

KNN(k近邻法)算法理论和实战

KNN概念 k近邻法&#xff08;k-nearest neighbor&#xff0c;k-NN&#xff09;是一种基本分类与回归方法。 k近邻法的输入为实例的特征向量对应于特征空间的点&#xff1b;输出为实例的类别&#xff0c;可以取多类。 k近邻法假设给定一个训练数据集&#xff0c;其中的实例类…

【机器学习】039_合理初始化

一、稳定训练 目标&#xff1a;使梯度值在更合理的范围内 常见方法如下&#xff1a; 将乘法变为加法 ResNet&#xff1a;当层数较多时&#xff0c;会加入一些加法进去 LSTM&#xff1a;如果时序序列较长时&#xff0c;把一些对时序的乘法做加法 归一化 梯度归一化&…

全链路压测的步骤及重要性

全链路压测是一种系统性的性能测试方法&#xff0c;旨在模拟真实用户场景下的完整操作流程&#xff0c;全面评估软件系统在不同压力下的性能表现。这种测试方法对于保证应用程序的高可用性、稳定性和可扩展性至关重要。 1. 全链路压测概述 全链路压测是在模拟实际用户使用场景的…

SMU可以供电的同时测量电流和电压

SMU可以供电的同时测量电流和电压 SMU本身能够提供电流或电压&#xff0c;同时测量负载或被测设备&#xff08;DUT&#xff1a;Device Under Test&#xff09;上的电流和电压。这是与传统电源相比使用SMU的优势之一。 SMU测量的电流和电压值将反映在NI-DCPower软面板中&#…

(swjtu西南交大)数据库实验(数据库需求分析):音乐软件数据管理系统

实验内容&#xff1a; 数据库需求分析&#xff1a;各用户组需求描述&#xff0c;绘出数据流图&#xff08;详细案例参见教材p333~p337&#xff0c;陶宏才&#xff0c;数据库原理及设计&#xff0c;第三版&#xff09;&#xff1b; 一、选题背景 近年来&#xff0c;“听歌”逐…

【docker】虚拟化和docker容器概念

基础了解 IAAS&#xff1a; 基础设施服务&#xff0c;&#xff08;只提供基础设施&#xff0c;没有系统&#xff09; **SAAS&#xff1a; ** 软件即服务&#xff0c;&#xff08;提供基础设施和系统&#xff09; PAAS&#xff1a; 平台即服务&#xff0c;&#xff08;提供基…

【Docker】从零开始:1.Docker概述

【Docker】从零开始&#xff1a;1.Docker概述 1.什么是Docker2.为什么要使用Docker3.传统虚拟机技术与Linux容器技术的区别(1).传统虚拟机技术(2).Linux容器 4.Docker的特点一次构建、随处运行a.更快速的应用交付和部署b.更便捷的升级和扩缩容&#xff1a;c.更简单的系统运维d.…

三字经||无聊数了下三字经的字数

三字经总字数去除标点后1416个 该文章无技术含量&#xff0c;仅三字经原文&#xff0c;学技术的同学可以止步了 三字经&#xff08;原文&#xff09; 【作者】王应麟 【朝代】南宋 人之初&#xff0c;性本善。性相近&#xff0c;习相远。 苟不教&#xff0c;性乃迁。教之道&a…

视频接入网关的用法

视频接入网关是一种多功能的视频网关设备&#xff0c;可以解决各种视频接入&#xff0c;视频输出&#xff0c;视频转码&#xff0c;视频融合的问题。可以应用在应急指挥&#xff0c;智慧融合等项目中&#xff0c;与各种系统进行对接&#xff0c;解决视频能力跨系统集成的难题。…