搜索
您的当前位置:首页正文

Windows x64内核学习笔记(四)—— 9-9-9-9-12分页

来源:欧得旅游网

前言

9-9-9-9-12分页

描述:随着计算机技术的发展,64位系统逐渐占据主流地位,那么也就表示CPU的最大寻址范围为64位。但实际上,CPU只使用了其中的48位用于寻址,并使用9-9-9-9-12分页模式。即便如此,在未来较长一段时间里,48位寻址范围也足够大部分人的日常使用了。

由于之后的大部分操作都是使用WinDbg完成的,因此我们在之后的笔记中都使用微软对四级页表的命名方式。

实验一:线性地址转物理地址

第一步:打开记事本
启动一个64位的notepad.exe,写入字符串“Hello World”。

0 0000 0100			//004
0 0110 1110			//06e
1 0101 1111			//15f
1 0101 0010			//152
1001 0010 0000		//920

页表基址

而在x64系统中,页表基址不再是固定的值,而是每次系统启动后随机生成的。

定位基址

描述:如果系统每次启动时,基址是随机分配的,那么该如何定位基址呢?其实方法有挺多的,大部分方式是通过提取特征码。

PTE to PXE

计算公式:PAE = PTE_BASE + (Address >> 12) << 3;

实验二:通过页表基址定位各级页表的物理页

代码实现

#include "ntddk.h"

ULONG64 g_NT_BASE = 0xfffff80348aa4000;	// lm命令得到
ULONG64 g_PTE_BASE;
ULONG64 g_PDE_BASE;
ULONG64 g_PPE_BASE;
ULONG64 g_PXE_BASE;

//卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("Driver Unload .\r\n");
}

ULONG64 GetPTEAddress(PVOID address)
{
	return (PULONG64)(g_PTE_BASE + ((((ULONG64)address & 0xffffffffffff) >> 12) << 3));
}

ULONG64 GetPDEAddress(PVOID address)
{
	return (PULONG64)(g_PDE_BASE + ((((ULONG64)address & 0xffffffffffff) >> 21) << 3));
}

ULONG64 GetPPEAddress(PVOID address)
{
	return (PULONG64)(g_PPE_BASE + ((((ULONG64)address & 0xffffffffffff) >> 30) << 3));
}

ULONG64 GetPXEAddress(PVOID address)
{
	return (PULONG64)(g_PXE_BASE + ((((ULONG64)address & 0xffffffffffff) >> 39) << 3));
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Driver Load .\r\n");
	DriverObject->DriverUnload = DriverUnload;

	ULONG64 offset = 0xa4ad;		// 页表基址硬编码相对于内核文件基址的偏移量
	g_PTE_BASE = *(PULONG64)(g_NT_BASE + offset);
	g_PDE_BASE = GetPTEAddress(g_PTE_BASE);
	g_PPE_BASE = GetPTEAddress(g_PDE_BASE);
	g_PXE_BASE = GetPTEAddress(g_PPE_BASE);

	DbgPrint("g_PTE_BASE: %p \r\n", g_PTE_BASE);
	DbgPrint("g_PDE_BASE: %p \r\n", g_PDE_BASE);
	DbgPrint("g_PPE_BASE: %p \r\n", g_PPE_BASE);
	DbgPrint("g_PXE_BASE: %p \r\n", g_PXE_BASE);

	ULONG64 gdtr = 0xfffff8034b290fb0;

	DbgPrint("gdtr - PXE: %p \r\n", GetPXEAddress(gdtr));
	DbgPrint("gdtr - PPE: %p \r\n", GetPPEAddress(gdtr));
	DbgPrint("gdtr - PDE: %p \r\n", GetPDEAddress(gdtr));
	DbgPrint("gdtr - PTE: %p \r\n", GetPTEAddress(gdtr));

	return STATUS_SUCCESS;
}

运行结果

使用WinDbg进行验证

参考资料

  • bilibili周壑:

因篇幅问题不能全部显示,请点此查看更多更全内容

Top