驱动开发:内核解析内存四级页表

这篇具有很好参考价值的文章主要介绍了驱动开发:内核解析内存四级页表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当今操作系统普遍采用64位架构,CPU最大寻址能力虽然达到了64位,但其实仅仅只是用到了48位进行寻址,其内存管理采用了9-9-9-9-12的分页模式,9-9-9-9-12分页表示物理地址拥有四级页表,微软将这四级依次命名为PXE、PPE、PDE、PTE这四项。

关于内存管理和分页模式,不同的操作系统和体系结构可能会有略微不同的实现方式。9-9-9-9-12的分页模式是一种常见的分页方案,其中物理地址被分成四级页表:PXE(Page Directory Pointer Table Entry)、PPE(Page Directory Entry)、PDE(Page Table Entry)和PTE(Page Table Entry)。这种分页模式可以支持大量的物理内存地址映射到虚拟内存地址空间中。每个级别的页表都负责将虚拟地址映射到更具体的物理地址。通过这种层次化的页表结构,操作系统可以更有效地管理和分配内存。

首先一个PTE管理1个分页大小的内存也就是0x1000字节,PTE结构的解析非常容易,打开WinDBG输入!PTE 0即可解析,如下所示,当前地址0位置处的PTE基址是FFFF898000000000,由于PTE的一个页大小是0x1000所以当内存地址高于0x1000时将会切换到另一个页中,如下FFFF898000000008则是另一个页中的地址。

0: kd> !PTE 0
                                           VA 0000000000000000
PXE at FFFF89C4E2713000    PPE at FFFF89C4E2600000    PDE at FFFF89C4C0000000    PTE at FFFF898000000000
contains 8A0000000405F867  contains 0000000000000000
pfn 405f      ---DA--UW-V  not valid

0: kd> !PTE 0x1000
                                           VA 0000000000001000
PXE at FFFF89C4E2713000    PPE at FFFF89C4E2600000    PDE at FFFF89C4C0000000    PTE at FFFF898000000008
contains 8A0000000405F867  contains 0000000000000000
pfn 405f      ---DA--UW-V  not valid

由于PTE是动态变化的,找到该地址的关键就在于通过MmGetSystemRoutineAddress函数动态得到MmGetVirtualForPhysical的内存地址,然后向下扫描特征寻找mov rdx,0FFFF8B0000000000h并将内部的地址提取出来。

驱动开发:内核解析内存四级页表

这段代码完整版如下所示,代码可动态定位到PTE的内存地址,然后将其取出;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include <ntifs.h>
#include <ntstrsafe.h>

// 指定内存区域的特征码扫描
PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize)
{
	PVOID pAddress = NULL;
	PUCHAR i = NULL;
	ULONG m = 0;

	// 扫描内存
	for (i = (PUCHAR)pStartAddress; i < (PUCHAR)pEndAddress; i++)
	{
		// 判断特征码
		for (m = 0; m < ulMemoryDataSize; m++)
		{
			if (*(PUCHAR)(i + m) != pMemoryData[m])
			{
				break;
			}
		}
		// 判断是否找到符合特征码的地址
		if (m >= ulMemoryDataSize)
		{
			// 找到特征码位置, 获取紧接着特征码的下一地址
			pAddress = (PVOID)(i + ulMemoryDataSize);
			break;
		}
	}

	return pAddress;
}

// 获取到函数地址
PVOID GetMmGetVirtualForPhysical()
{
	PVOID VariableAddress = 0;
	UNICODE_STRING uioiTime = { 0 };

	RtlInitUnicodeString(&uioiTime, L"MmGetVirtualForPhysical");
	VariableAddress = (PVOID)MmGetSystemRoutineAddress(&uioiTime);
	if (VariableAddress != 0)
	{
		return VariableAddress;
	}
	return 0;
}

// 驱动卸载例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("Uninstall Driver \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Hello LyShark \n");

	// 获取函数地址
	PVOID address = GetMmGetVirtualForPhysical();

	DbgPrint("GetMmGetVirtualForPhysical = %p \n", address);

	UCHAR pSecondSpecialData[50] = { 0 };
	ULONG ulFirstSpecialDataSize = 0;

	pSecondSpecialData[0] = 0x48;
	pSecondSpecialData[1] = 0xc1;
	pSecondSpecialData[2] = 0xe0;
	ulFirstSpecialDataSize = 3;

	// 定位特征码
	PVOID PTE = SearchMemory(address, (PVOID)((PUCHAR)address + 0xFF), pSecondSpecialData, ulFirstSpecialDataSize);
	__try
	{
		PVOID lOffset = (ULONG)PTE + 1;
		DbgPrint("PTE Address = %p \n", lOffset);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		DbgPrint("error");
	}

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

运行如上代码可动态获取到当前系统的PTE地址,然后将PTE填入到g_PTEBASE中,即可实现解析系统内的四个标志位,完整解析代码如下所示;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com

#include <ntifs.h>
#include <ntstrsafe.h>

INT64 g_PTEBASE = 0;
INT64 g_PDEBASE = 0;
INT64 g_PPEBASE = 0;
INT64 g_PXEBASE = 0;

PULONG64 GetPteBase(PVOID va)
{
	return (PULONG64)((((ULONG64)va & 0xFFFFFFFFFFFF) >> 12) * 8) + g_PTEBASE;
}

PULONG64 GetPdeBase(PVOID va)
{
	return (PULONG64)((((ULONG64)va & 0xFFFFFFFFFFFF) >> 12) * 8) + g_PDEBASE;
}

PULONG64 GetPpeBase(PVOID va)
{
	return (PULONG64)((((ULONG64)va & 0xFFFFFFFFFFFF) >> 12) * 8) + g_PPEBASE;
}

PULONG64 GetPxeBase(PVOID va)
{
	return (PULONG64)((((ULONG64)va & 0xFFFFFFFFFFFF) >> 12) * 8) + g_PXEBASE;
}

// 驱动卸载例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("Uninstall Driver \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Hello LyShark \n");

	g_PTEBASE = 0XFFFFF20000000000;

	g_PDEBASE = (ULONG64)GetPteBase((PVOID)g_PTEBASE);
	g_PPEBASE = (ULONG64)GetPteBase((PVOID)g_PDEBASE);
	g_PXEBASE = (ULONG64)GetPteBase((PVOID)g_PPEBASE);

	DbgPrint("PXE = %p \n", g_PXEBASE);
	DbgPrint("PPE  = %p \n", g_PPEBASE);
	DbgPrint("PDE  = %p \n", g_PDEBASE);
	DbgPrint("PTE  = %p \n", g_PTEBASE);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

我的系统内PTE地址为0XFFFFF20000000000,填入变量内解析效果如下图所示;

驱动开发:内核解析内存四级页表文章来源地址https://www.toymoban.com/news/detail-462973.html

到了这里,关于驱动开发:内核解析内存四级页表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 驱动开发:内核解析PE结构导出表

    在笔者的上一篇文章 《驱动开发:内核特征码扫描PE代码段》 中 LyShark 带大家通过封装好的 LySharkToolsUtilKernelBase 函数实现了动态获取内核模块基址,并通过 ntimage.h 头文件中提供的系列函数解析了指定内核模块的 PE节表 参数,本章将继续延申这个话题,实现对PE文件导出表的

    2024年02月07日
    浏览(32)
  • 字符设备驱动(内核态用户态内存交互)

    内核驱动:运行在内核态的动态模块,遵循内核模块框架接口,更倾向于插件。 应用程序:运行在用户态的进程。 应用程序与内核驱动交互通过既定接口,内核态和用户态访问依然遵循内核既定接口。 系统:openEuler-20.03-LTS-SP3 char_module.c Makefile 驱动构建 驱动信息确认 应用程

    2024年02月11日
    浏览(44)
  • 【嵌入式环境下linux内核及驱动学习笔记-(10-内核内存管理)】

    对于包含MMU(内存管理单元)的处理器而言,linux系统以虚拟内存的方式为每个进程分配最大4GB的内存。这真的4GB的内存空间被分为两个部分–用户空间 与 内核空间。用户空间地地址分布为0~3GB,剩下的3 ~ 4GB 为内核空间。如下图。 用户进程通常只能访问用户空间的虚拟地址

    2024年02月11日
    浏览(58)
  • 万字长文教你使用安卓内核驱动进行内存读写

    你是不是经常看到一些游戏辅助声称自己 独家内核驱动 , 支持一切机型 , 无视游戏检测 。 本文将带领你, 从0开始 ,编译属于自己的 安卓内核驱动 。 通过本文:你将从一名初级的游戏辅助开发者,摇身一变成为所谓的 独家内核作者 本文只涉及过检测等内容,不涉及辅

    2024年02月03日
    浏览(108)
  • Spark内核解析-内存管理7(六)

    Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色。理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优。本文中阐述的原理基于 Spark 2.1 版本。 在执行 Spark 的应用程序时,Spark 集群会启动 Driver 和

    2024年02月03日
    浏览(44)
  • 【OSTEP】分页(Paging) | 页表中究竟有什么 | 页表存在哪 | 内存追踪

      💭 写在前面 本系列博客为复习操作系统导论的笔记,内容主要参考自: Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy PiecesA. Silberschatz, P. Galvin, and G. Gagne, Operating System Concepts, 9th Edition, John Wiley Sons, Inc., 2014, ISBN 978-1-118-09375-7.Microsoft. MSDN(Microsoft Developer

    2024年02月04日
    浏览(51)
  • Linux内核中内存管理相关配置项的详细解析5

    接前一篇文章:Linux内核中内存管理相关配置项的详细解析4 对应配置变量为:CONFIG_SHUFFLE_PAGE_ALLOCATOR。 此项只有选中和不选中两种状态,默认为选中。 此项的内核源码详细解释为: Randomization of the page allocator improves the average utilization of a direct-mapped memory-side-cache. See section 5

    2024年02月08日
    浏览(41)
  • Linux内核中内存管理相关配置项的详细解析15

    接前一篇文章:Linux内核中内存管理相关配置项的详细解析14 对应配置变量为:CONFIG_PTE_MARKER_UFFD_WP。 此项只有选中和不选中两种状态,默认为选中。 此项的内核源码详细解释为: Allows to create marker PTEs for userfaultfd write protection purposes. It is required to enable userfaultfd write protecti

    2024年02月08日
    浏览(45)
  • 系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

    虚拟内存是一种操作系统提供的机制,用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上。通过使用虚拟内存,操作系统可以有效地解决多个应用程序直接操作物理内存可能引发的冲突问题。 在使用虚拟内存的情况下,每个进程都有自己的独立的虚

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包