1. 内存管理方式
(1)段式内存管理
(2)页式内存管理
2. 逻辑地址到虚拟地址的转换
(1)段寄存器(cs/ds/ss/es/fs/gs)的值为段选择器(Segment Selector),x86/x64段寄存器大小均为 16 位0:
(2)根据选择器(Segment Selector)的 Table Indicator 位,在 GDT 或者 LDT 中查找段描述符(Segment Descriptor):
(3)根据段描述符(Segment Descriptor)的具体结构,得出段基址:
【x86 段描述符结构】:(注意 x64 的段描述符结构不一样)
(4)【例子】x86 下获取 fs:0 代表的虚拟地址:
2: kd> r fs
fs=00000030
2: kd> .formats 30
Evaluate expression:
Binary: 00000000 00000000 00000000 00110000
分布 index->6 TI->0 RPL->0
2: kd> r gdtr
gdtr=8c708c20
2: kd> dq 8c708c20 + (0x6 * 0x8) L1
8c708c50 8c409370`00003748
fs:0 -> 0x8c700000
2: kd> dt _kpcr 0x8c700000
nt!_KPCR
...
+0x01c SelfPcr : 0x8c700000 _KPCR
+0x020 Prcb : 0x8c700120 _KPRCB
...
3. 虚拟地址到物理地址的转换
(1)用 windbg 的 !process 查看进程信息的时候会有一个 DirBase 的项目,其实它就是 进程(KProcess)结构中的一个域 DirectoryTableBase,指向进程顶层 PDE(Page Directory Entry)。且与当前进程的 cr3 寄存器的值相同。
一、首先看看 MiInitMachineDependent 这个函数,这个函数的一部分功能就是建立虚拟内存机制。里面对 KProcess.DirectoryTableBase 的操作是:
CurrentProcess->Pcb.DirectoryTableBase[0] = DirBase;
;
; Load the new CR3 and as a side effect flush non-global TB entries.
;
mov eax, [ebp]+PrDirectoryTableBase ; get new directory base
mov cr3, eax ; and flush TB
(2)PDE/PTE、物理地址、PFN 之间的关系
物理地址 = PFN + 物理页面内偏移(12bit)
PDE/PTE = 其他部分 + PFN + PDE/PTE 标记(12bit)
(3)虚拟地址的分布
(4)【例子】(x86 PAE):修改虚拟机中 calc.exe 虚拟地址为 0x8F9768 对应的物理地址内存单元
!process 0 0
PROCESS 88a64788 SessionId: 1 Cid: 0908 Peb: 7ffd9000 ParentCid: 08f8
DirBase: 11e15460 ObjectTable: 9478afc0 HandleCount: 38.
Image: calc.exe
1: kd> .formats 0x8F9768
Evaluate expression:
Binary: 00000000 10001111 10010111 01101000
分布 2->0x0, 9->0x4, 9->0xF9, 12->0x768
1: kd> !dq 11e15460
#11e15460 00000000`06876801 00000000`068b8801
1: kd> !dq 06876000 + 0x8 * 0x4
# 6876020 00000000`06e6c867 00000000`00000000
1: kd> !dq 06e6c000 + 0x8 * 0xF9
# 6e6c7c8 00000000`10b0a005 00000000`0bb82005
1: kd> !db 10b0a000 + 0x768
#10b0a768 e8 4b fd ff ff 6a 58 68-e0 98 8f 00 e8 ab ea
1: kd> !eb 10b0a768 cc