Windows内核详解:分页机制
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:238
- 发布: 2025-06-15 13:03
- 最后更新: 2025-06-15 13:03
[toc]
分页
-
Offset:页内偏移,表示在一个物理也内的实际起始地址
-
PT(Page Table),页表,内部的每一项叫做页表项(PTE)页表中每一项指向最终的页框(物理页),相当于一个指针的值,由于每个页框的大小为4K,所以这个指针的最后12位不是地址,而是当前物理页的属性。最终的页内偏移,是通过线性地址中最后的12位来表示的。
-
PD(Page Directory),页目录表,内部的每一项叫做页目录项(PDE)页目录中,存储的是下一级页目录或者页表的地址,相当于指针的形式,所以页目录中的每一项的长度,和当前架构下指针的长度相同(32位系统为4Byte,64位为 8Byte)。
-
PDPT(Page Directory Pointer Table),页目录指针表,其中每一项叫做PDPTE -
PML4(Page Map Level 4),四级页表,其中每一项叫做PML4E
检查分页情况
查看是否开启了分页
bash
# cr0.PG 是第31位,设置为1表示已经开启分页
3: kd> r cr0
cr0=0000000080050033
3: kd> .formats 0000000080050033
Evaluate expression:
Hex: 00000000`80050033
Decimal: 2147811379
Octal: 0000000000020001200063
Binary: 00000000 00000000 00000000 00000000 10000000 00000101 00000000 00110011
Chars: .......3
Time: ***** Invalid
Float: low -4.59249e-040 high 0
Double: 1.06116e-314
查看是否开启64位分页
bash
# 查看是否开启了64位
3: kd> rdmsr c0000080
msr[c0000080] = 00000000`00000d01
3: kd> .formats 00000000`00000d01
Evaluate expression:
Hex: 00000000`00000d01
Decimal: 3329
Octal: 0000000000000000006401
Binary: 00000000 00000000 00000000 00000000 00000000 00000000 00001101 00000001
Chars: ........
Time: Thu Jan 1 08:55:29 1970
Float: low 4.66492e-042 high 0
Double: 1.64474e-320

第8和第10位是我们需要关注的,如果是1的话表示开启。(本例已经可以看到已经设置为1),证明已经开启了64位。
查看开启了那种分页模式
其中PAE是第5位,LA57 是第12位,CR4.PAE = 1, CR4.LA57 = 0 综上本系统开启了 level 4 的分页模式
bash
3: kd> r cr4
cr4=00000000003506f8
3: kd> .formats 00000000003506f8
Evaluate expression:
Hex: 00000000`003506f8
Decimal: 3475192
Octal: 0000000000000015203370
Binary: 00000000 00000000 00000000 00000000 00000000 00110101 00000110 11111000
Chars: .....5..
Time: Tue Feb 10 13:19:52 1970
Float: low 4.86978e-039 high 0
Double: 1.71697e-317
分页情况手动分析
线性地址拆分
段寄存器.base + 逻辑地址 = 线性地址
线性地址可以根据分页规则进行拆分,如地址:1E9CA5A6540,在64位分页模式为 9-9-9-9-12情况下,可以拆分成如下的形式:
c
// 将以下地址转为二进制模式(页面偏移部分不用转,从右往左开始按照分页模式,进行二进制的拆分):
78b7f04000(000)
ffffdf86eb7f4000
0111 1000 1011 1111 0000 0100(000)
0000 0111 1000 1011 0111 1111 0000 0100 0000 0000 0000 // 0x78b7f04000i64
0000 0000 0000 0011 1100 0101 1011 1111 1000 0010 0000 // 0x78b7f04000i64 >> 9
0000 0111 1111 1111 1111 1111 1111 1111 1111 1111 1000 // 0x7FFFFFFFF8i64
0000 0000 0000 0011 1100 0101 1011 1111 1000 0010 0000 // (0x78b7f04000 >> 9)&0x7FFFFFFFF8
1001 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 // 0x98000000000i64
1111111111111111111101101000000000111100010110111111100000100000 // FFFF F680 3C5B F820
9 => 0 => 0x0 // PML4
9 => 0001 1110 => 0x1e // Directory Ptr
9 => 0000 0101 1111 => 0x5f // Directory
9 => 0001 0000 0100 => 0x104 // Table
12 => 000 // Offset
页目录基址算法
-
(PML4E & 0xFFFF FFFF F000) * 8 + 基址 -
(PDPTE & 0xFFFFFFFFF000) * 8 + 基址 -
(PDE & 0xFFFFFFFFF000) * 8 + 基址
找到 PML4 的指针
每个进程都有自己的页目录基地址(DirBase),此地址为页目录的基地址,且为物理地址。
bash
# 查找进程列表,找到目的进程的信息
!process 0 0
PROCESS ffffb9071bdf8080
SessionId: 1 Cid: 2260 Peb: 78b7f04000 ParentCid: 14b8
DirBase: 28712000 ObjectTable: ffff8c06186741c0 HandleCount: 245.
Image: notepad.exe
PROCESS ffffb9071bdf8080
SessionId: 1 Cid: 2260 Peb: 78b7f04000 ParentCid: 14b8
DirBase: 28712000 ObjectTable: ffff8c06186741c0 HandleCount: 245.
Image: notepad.exe
3: kd> !pte 78b7f04000
VA 00000078b7f04000
PXE at FFFFB85C2E170000 PPE at FFFFB85C2E000F10 PDE at FFFFB85C001E2DF8 PTE at FFFFB8003C5BF820
contains 8A0000000E488867 contains 0000000000000000
pfn e488 ---DA--UW-V contains 0000000000000000
not valid
3: kd> !dq bd8f1000 + 0 * 8 # 0 为一级页目录的索引号,8表示每个指针占用的空间长度
#bd8f1000 0a000000`bd894867 0a000000`ab10c867
#bd8f1010 00000000`00000000 0a000000`b9b12867
#bd8f1020 00000000`00000000 00000000`00000000
!dq 0a000000`bd894000 + 7a * 8