分享
 
 
 

在用户态进行虚拟空间地址向物理空间地址的转换

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

http://flier_lu.blogone.net/?id=1428057

《自动获取 NT 系统服务描述表与函数名映射表》一文中,我给出了一个从虚地址向物理地址转换的经验函数。

以下为引用:

PHYSICAL_ADDRESS TPhysicalMemoryMapping::LinearAddressToPhysicalAddress(LPCVOID lpVirtualAddress)

{

PHYSICAL_ADDRESS addr = { 0, 0 };

if((DWORD)lpVirtualAddress < 0x80000000L || (DWORD)lpVirtualAddress >= 0xA0000000L)

addr.QuadPart = (DWORD)lpVirtualAddress & 0x0FFFF000;

else

addr.QuadPart = (DWORD)lpVirtualAddress & 0x1FFFF000;

return addr;

}

这个函数实际上只处理了0x8000000 - 0xA0000000这段内存地址的转换,而对0xA0000000以上内存,则只是用 PA = VA & 0x0FFFF000 保障访问不会出错,这实际上并不能获取这段内存的实际内容。了解 WinNT/2K 内存布局的朋友应该知道,为了系统实现简便并保障地址转换效率,WinNT将0x80000000 - 0xA0000000内存端直接映射到物理内存,转换算法就是一个简单的 PA = VA & 0x1FFFF000;而对 0xA0000000 以上的虚拟地址,则是使用两级页表索引来实现虚地址页向物理地址页的映射(如启用 AWE 则为三级,这里暂不讨论,实现原理类似)。因此要真正访问 0xA0000000 以上虚地址内存,必须读取进程的 PDE/PTE 表。

但问题是PDE页表一般存放在虚地址 0xC0300000,PTE 页表则从虚地址 0xC0000000 开始。也就是说这些页表本身,就存放在以页表才能访问的虚地址上。要查PDE/PTE表进行虚地址向物理地址转换,首先要知道 0xC0300000 和 0xC0000000 映射在哪个物理页上。这样一来就变成了先有鸡还是先有蛋的问题了,呵呵。 NT 内核本身,则可以通过进程 CR3 寄存器中保存的 PDE 页表起始物理地址直接访问,但不巧的是,访问 CR3 需要有 Ring 0 的状态。因此大多数介绍虚地址向物理地址转换的文章,在描述完两级映射之后,都是提供 Ring 0 层的代码演示实现,例如 webcrazy 的大作《小议Windows NT/2000分页机制》

因为此类的文章较多了,这里我就不在罗嗦内存结构和转换算法了,有兴趣研究的朋友可以参考 Inside Win2K 3nd 和 webcrazy 的相关文章。

既然无法知道 PDE/PTE 的物理地址,也不能直接访问 CR3,我就开始琢磨各种迂回的途径。昨天折腾了大半天,翻越了 ntos\ke 和 ntos\mm 目录下的一堆源码,在大大体验了一把 Open Source Windows NT 的优势之后,终于找到了一个还算完美的解决方法 :P

我们知道 PDE/PTE 是进程相关的。因为每个进程都有自己的虚拟空间,因此必须有一整套独立的页表备查。核心在进行线程切换时,如果两个线程在一个进程内,无需做页表的切换;如果两个线程跨越了进程,就必须将目标线程所在进程的Context载入,这其中就包括我们所需要的 CR3 的内容。而在翻越代码后,我发现 CR3 的内容被保存到 EPROCESS::KPROCESS::DirectoryTableBase[0] 中。这个变量保存了 PDE 页表物理地址和 hyber space PTE 页表物理地址(以后再详细介绍)。

于是实现思路就清晰了:

1.取当前进程的 EPROCESS

2.读取 PDE 页表物理地址

3.通过分解虚地址获取 PDE/PTE 表的索引

4.查表获得目标物理页地址,读取物理页内容。

1.取当前进程的 EPROCESS

当前进程的 EPROCESS 地址在 ntoskrnl.exe 的空间中,因此可以通过直接映射内存访问。使用OpenProcess打开当前进程,获得句柄;使用NTDLL::ZwQuerySystemInformation函数获取所有核心句柄表,线性搜索到进程句柄,其指向的内核对象就是 EPROCESS。

2.读取 PDE 页表物理地址

PDE 页表物理地址在 EPROCESS 结构的偏移 0x18 处

3.通过分解虚地址获取 PDE/PTE 表的索引

将目标虚地址如 0xA01A8148 分解为三部分:

DDDDDDDDDDTTTTTTTTTTBBBBBBBBBBBB

01234567890123456789012345678901

高10位是PDE索引;中间10位是PTE索引;末尾12位是页内字节索引。

4.查表获得目标物理页地址,读取物理页内容。

PDE/PTE表项都是一个DWORD,其高20位定义下一级的索引。

以下为引用:

typedef struct _MMPTE_HARDWARE {

ULONG Valid : 1;

ULONG Write : 1; // UP version

ULONG Owner : 1;

ULONG WriteThrough : 1;

ULONG CacheDisable : 1;

ULONG Accessed : 1;

ULONG Dirty : 1;

ULONG LargePage : 1;

ULONG Global : 1;

ULONG CopyOnWrite : 1; // software field

ULONG Prototype : 1; // software field

ULONG reserved : 1; // software field

ULONG PageFrameNumber : 20;

} MMPTE_HARDWARE, *PMMPTE_HARDWARE;

具体查表转换算法如下

以下为引用:

#define GetPdeAddress(base, va) (LPCVOID)((base) + (((ULONG)(va) >> 22) << 2))

#define GetPteAddress(base, va) (LPCVOID)((base) + ((((ULONG)(va) >> 12) & 0x3FF) << 2))

const PHYSICAL_ADDRESS TPhysicalMemoryMapping::LinearAddressToPhysicalAddress(LPCVOID lpVirtualAddress)

{

PHYSICAL_ADDRESS addr = { 0, 0 };

if((DWORD)lpVirtualAddress >= 0x80000000L && (DWORD)lpVirtualAddress < 0xA0000000L)

{

addr.QuadPart = (DWORD)lpVirtualAddress & 0x1FFFF000;

}

else

{

MMPTE_HARDWARE PDE, PTE;

m_pManager->ReadPhysicalMemoryPage(GetPdeAddress(m_pManager->PTE.LowPart, lpVirtualAddress), &PDE, sizeof(PDE));

m_pManager->ReadPhysicalMemoryPage(GetPteAddress(PDE.PageFrameNumber << PAGE_SHIFT, lpVirtualAddress), &PTE, sizeof(PTE));

addr.LowPart = (PTE.PageFrameNumber << PAGE_SHIFT) + BYTE_OFFSET(lpVirtualAddress);

}

return addr;

}

知道了目标页面的物理地址,就可以通过读取 \Device\PhysicalMemory 直接获取了

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有