Windows内核详解:分页机制

[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

    e197d3836a35f6956ac6a72451d70705.png

检查分页情况

查看是否开启了分页

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

64463d9d17b87e216911b685f2ea81c6.png

第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