首页
社区
课程
招聘
定位Windows分页结构内存区域
2023-10-19 22:35 5515

定位Windows分页结构内存区域

2023-10-19 22:35
5515

定位Windows分页结构内存区域

定位原理

由于处理器指令只能使用虚拟地址,而没有办法通过直接指定物理地址来更新一个内存位置的内容。因此访问PML4PDPT等的唯一方法是将它们也映射到相应的虚拟地址上。虚拟内存管理才能够修改处理器的分页结构。

PML4 Auto-Entry

解决这个问题的方案是以一种非常特殊的方式使用一项PML4e:即Windows无页表随机化以前使用0x1ed处的项存储PML4自身的PFN,我们将这项称为PML4 Auto-Entry. 接下来我们将看到他的作用。

我们知道一个PML4e映射了512GB的虚拟地址空间,那么因为这个特殊项的存在,那么一定有那么一个范围大小的空间为这个特殊目的而保留。

接下来我们就确定一下这个PML4e所对应的地址空间范围。

我们知道PML4的索引被存储到VA的第39-47位,那么索引为0x1ed时,对应的虚拟地址就可以相应的推出来。

0x1ed = 1 1110 1101b

bit # 6   4  4  4    4 3
            3...8  7  4    0 9
            1...1  1111 0110 1xxx x...x 

虚拟地址的39-47反推为0x1ed,因为47位为1,所以48-63也必须为1. 而0-38位可以从全0到全1. 因此地址范围就可以很快知道

1
2
3
4
5
6
bit # 6   4  4  4    4 3  3
            3...8  7  4    0 9  6
            1...1  1111 0110 1xxx x...x
            |___|  |___||___||___|
              |      |    |    |
            FFFF     F    6   8-F

最终推出这个虚拟地址范围为

0xFFFFF68000000000 -- 0xFFFFF6FFFFFFFFFF

如果以范围后的首字节位结束地址那么范围为

0xFFFFF68000000000 -- 0xFFFFF70000000000

这个地址范围的虚拟地址的索引全是0x1ed,PML4e即为PML4 Auto-Entry。本来应该利用这个项的PFN定位PDPT,但是他却指向了PML4自身。在这种情况下,虚拟地址的30-38位索引得到的就是PDPTE,从21-29位索引得到的就是PDE。接着从20-12位索引得到的就是PTE。

PTE的虚拟地址就从0xFFFFF680`00000000开始,也就是我们常说的PTE_BASE。

PTEs是8字节大小,因此下一个PTE的虚拟地址就是0xFFFFF680`000000081

给定一个虚拟地址,那么他的PTE一定在512GB区域的某一个地方。在哪里呢?

求解方法:

给定一个虚拟地址,我们进行如下转化:

  • VA中的所有索引位向右移9位
  • 最左边未使用的位全部设置为1
  • PML4 index替换成 PML4 Auto-Entry的 index
  • 将0-2位置0

就会得到一个新的虚拟地址,即为所求。

得到这个PTE的虚拟地址后,进一步转化:

  • 左移9位
  • 根据移位完成后的第47位设置48-63位。

又得到一个新的虚拟地址,这个值是PTE映射的虚拟页的首地址。

PML4 index 和 PDPT index域设置成auto-entry index,这样实际上PD index索引的就是PDPTPT index索引的就是PD,即可看到PDEs。

PDE的范围因此也可以相应的计算出来

1
2
3
4
5
6
7
8
1 1110 1101
 
bit # 6   4  4  4    4 3  3    3 32
            3...8  7  4    0 9  6    1 09
            1...1  1111 0110 1111 1011 01..
            |___|  |___||___||__| |__| |___|
              |      |    |    |   |     |
            FFFF     F    6    F   B    4-7

PDE开始地址 : 0xFFFFF6FB'40000000 即PDE_BASE

PDE结束地址:0xFFFFF6FB'80000000

可以发现这个地址范围在之前计算出来的PTE里。

也就是说他把实际的PTE范围分成了两个区域,中间的范围是拿给PDE映射的,而不是PTE

给定一个VA也可以计算出其PDE的虚拟地址。一个PDE映射了512个PTE。

PDPTEs的虚拟地址就是左边填3个auto-entry index项。

PDPTE的起始地址就是 0xFFFFF6FB'7DA00000,即PPE_BASE

PDPTE的结束地址就是 0xFFFFF6FB'7DC00000

给定一个VA也可以计算出其PDPTE的虚拟地址。(移出三个index空位,分别将auto-entry index填入PML4,PDPT,PD

如果四个索引位都设置成auto-entry index的话,那么会得到一个4kb的范围.

PML4E 起始地址 0xFFFFF6FB'7DBED000,即PXE_BASE

PML4E 结束地址 0xFFFFF6FB'7DBEE000

PML4 auto-entryindex是0x1e8。他的offset=0x1e8 x 8 = 0xf68。那么他的VA就是0xFFFFF6FB'7DBED000 + 0xF68 = 0XFFFFF6FB7DBEDF68。

由此可做如下内存区域区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
FFFFF700`00000000 |------------| --------------------------------------
                  |            |                                      |
                  |  PTE High  |                                      |
                  |            |                                      |
FFFFF6FB`80000000 |------------| -----------------------------        |
                  |            |                             |        |
                  |  PDE High  |                             |        |
                  |            |                             |        |
FFFFF6FB`7D000000 |------------|------------------           |        |
                  |            |                 |           |        |
                  | PDPTE High |                 |           |        |
FFFFF6FB`7DBEE000 |------------|-----            |           |        |
                  | PML4E      |    | 4KB        | 2MB       | 1GB    | 512GB
FFFFF6FB`7DBED000 |------------|----- PXE_BASE   |           |        |
                  |            |                 |           |        |
                  | PDPTE Low  |                 |           |        |
FFFFF6FB`7DA00000 |------------|------------------ PPE_BASE  |        |
                  |            |                             |        |
                  |  PDE Low   |                             |        |
                  |            |                             |        |
FFFFF6FB`40000000 |------------| ---------------------------- PDE_BASE|
                  |            |                                      |
                  |  PTE Low   |                                      |
                  |            |                                      |
FFFFF680`00000000 |------------| -------------------------------------- PTE_BASE
                       
             Paging Structures Region
ed nt!Kd_SXS_Mask 0
ed nt!Kd_FUSION_Mask 0

接下来可以编写代码完成相关功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ULONG_PTR pte_base, pde_base, ppe_base, pxe_base;
pte_base = pde_base = ppe_base = pxe_base = 0;
PHYSICAL_ADDRESS pml4;
pml4.QuadPart = __readcr3();
// get the PXE virtual address
PMMPTE_HARDWARE page_directory_va
    = (PMMPTE_HARDWARE)MmGetVirtualForPhysical(pml4);
KdPrint(("pml4: %p\n", page_directory_va));
pxe_base = (ULONG_PTR)page_directory_va;
ULONG_PTR pxe_end = pxe_base + (1ull << 12);
ULONG_PTR auto_entry_index = (pxe_base >> 12) & 0x1ff;
KdPrint(("auto entry index: 0x%x\n", auto_entry_index));
ULONG_PTR va = 0xFFFF0000'00000000;
pte_base = va | (auto_entry_index << 39);
ULONG_PTR pte_end = pte_base + (1ull << 39);
pde_base = pte_base | (auto_entry_index << 30);
ULONG_PTR pde_end = pde_base + (1ull << 30);
ppe_base = pde_base | (auto_entry_index << 21);
ULONG_PTR ppe_end = ppe_base + (1ull << 21);
 
KdPrint(("pte_base: %p,end: %p\n", pte_base, pte_end));
KdPrint(("pde_base: %p,end: %p\n", pde_base, pde_end));
KdPrint(("ppe_base: %p,end: %p\n", ppe_base, ppe_end));
KdPrint(("pxe_base: %p,end: %p\n", pxe_base, pxe_end));

测试结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0: kd> uf nt!MiGetPteAddress
nt!MiGetPteAddress:
fffff806`09e64bf4 48c1e909        shr     rcx,9
fffff806`09e64bf8 48b8f8ffffff7f000000 mov rax,7FFFFFFFF8h
fffff806`09e64c02 4823c8          and     rcx,rax
fffff806`09e64c05 48b8000000008081ffff mov rax,0FFFF818000000000h
fffff806`09e64c0f 4803c1          add     rax,rcx
fffff806`09e64c12 c3              ret
0: kd> !pte 0
                                           VA 0000000000000000
PXE at FFFF81C0E0703000    PPE at FFFF81C0E0600000    PDE at FFFF81C0C0000000    PTE at FFFF818000000000
contains 8A00000101B3E867  contains 0A00000101B3F867  contains 0000000000000000
pfn 101b3e    ---DA--UW-V  pfn 101b3f    ---DA--UWEV  contains 0000000000000000
not valid
 
0: kd> g
pml4: FFFF81C0E0703000
auto entry index: 0x103
pte_base: FFFF818000000000,end: FFFF820000000000
pde_base: FFFF81C0C0000000,end: FFFF81C100000000
ppe_base: FFFF81C0E0600000,end: FFFF81C0E0800000
pxe_base: FFFF81C0E0703000,end: FFFF81C0E0704000

完整代码github:
https://github.com/BeneficialCode/PagingStructuresRegion


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-10-19 22:38 被VirtualCC编辑 ,原因: 修正代码显示问题
收藏
点赞4
打赏
分享
最新回复 (1)
雪    币: 19323
活跃值: (28938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-10-20 16:17
2
1
感谢分享
游客
登录 | 注册 方可回帖
返回