两种模式
这个虚拟地址和物理地址的映射关系需要记录下来。在Windows中,有2种方式:
- 非物理地址扩展模式
- 物理地址扩展模式(PAE)
非物理地址扩展模式建立映射时,直接把虚拟地址和物理地址记录到一张表中,表明这个物理地址已经使用。但是,这个表也要占很多内存。因此,虚拟地址和物理地址的映射关系不能这么保存。
PAE使32位的操作系统能够访问超出4Gb的物理内存,非PAE模式下只能访问4Gb以内的内存,在非PAE模式下,即使电脑安装了8Gb内存条也只能使用4Gb。
分页机制原理
4KB为一页,4K个分页为一个页表,页目录表PDT中的页目录项PDE会索引到页表。
非物理地址扩展模式windbg实验
int main()
{
printf("%p\n", "aaabbb\n" );
system("pause");
return 0;
}
必须关闭系统的 PAE 模式:
- win7 32位系统,且CPU个数是1个,内存大小为4Gb以下;
- 管理员方式运行CMD,输入以下指令:
BCDEdit /set PAE ForceDisable
BCDEdit /set NX AlwaysOff
- 重启系统
虚拟地址会被拆分成3个部分:
- 页目录表索引(10个比特位)
- 页表索引(10个比特位)
- 字节索引(12个比特位)
上面的程序输出了0x41B730
,二进制展开:
kd> .formats 41b730
Binary: 0000000001 0000011011 011100110000
得到1-0x17-0xB30
kd> !process 0 0 test.exe
PROCESS 87c46030 SessionId: 1 Cid: 08ac Peb: 7ffdf000 ParentCid: 05e
DirBase: 3946f000 ObjectTable: ac410490 HandleCount: 9.
Image: test.exe
在输出的信息中,DirBase:3946f000
就是本进程的页目录首地址了,注意,每个进程的页目录首地址都是不一样的。每个进程都有自己的页目录。需要注意的是,这个页目录地址是一个物理地址,windbg中的 d 系列命令只能查看虚拟地址,不能
查看物理地址,查看物理地址需要使用!d
系列命令.
// 页目录
kd> !dd 3946f000
#3946f000 387f0867 392ec867 00000000 00000000
//查看页表, 页表中保存的每个元素是分页首地址,
kd>!dd 392ec000 + 17 *4
#392ec05c 38d6d025 38b2e025 00000000 37993867
// 分页首地址+页内偏移得到真正的物理地址
kd> !db 38d6d000 + B30
#38d6db30 61 61 61 62 62 62 63 63‐63 00 00 00 c7 fd b6 af aaabbbccc......
通过虚拟地址查看
kd> .process /i 87c46030 /*切换到进程地址空间, 格式为 .process /i PROCESS地址*/
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g /*g一下再执行!vtop指令*/
Break instruction exception ‐ code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
8405dd00 cc int 3
kd> db 417b30 /*直接查看虚拟地址*/
00417b30 61 61 61 62 62 62 63 63‐63 00 00 00 c7 fd b6 af aaabbbccc.......
kd> !vtop 0 417b30 /*查看进程虚拟地址对应的物理地址, 格式为 !vtop 0 虚拟地址*/
X86VtoP: Virt 00417b30, pagedir 3946f000
X86VtoP: PDE 3946f004 ‐ 392ec867
X86VtoP: PTE 392ec05c ‐ 38d6d025
X86VtoP: Mapped phys 38d6db30
Virtual address 417b30 translates to physical address 38d6db30.
物理地址扩展模式windbg实验
管理员运行cmd,开启PAE:
BCDEdit /set PAE Forceenable
BCDEdit /set NX Alwayson
重启。
虚拟地址被拆分为4个部分:
- 页目录表指针索引(2个二进制位)
- 页目录(9个二进制位)
- 页表(9个二进制位)
- 页内偏移(12个二进制位)
也就是 2‐9‐9‐12
需要注意,非PAE模式下使用4个字节保存页表首地址和分页首地址,在
PAE模式下,使用8字节来保存。所以查看命令要用!dq
。
还是上面的程序,输出0x00417BF0
.
kd> !process 0 0 CTest.exe
PROCESS 89176030 SessionId: 1 Cid: 0d3c Peb: 7ffdf000 ParentCid: 0638
DirBase: be8dc500 ObjectTable: 8f2f7810 HandleCount: 15.
Image: CTest.exe
页目录地址be8dc500
.
kd> .formats 00417BF0
Evaluate expression:
Hex: 00417bf0
Decimal: 4291568
Octal: 00020275760
Binary: 00000000 01000001 01111011 11110000
00 000000010 000010111 1011 11110000 == 0-2-0x17-0xbf0
。
下面的步骤,记住低12位是属性。
// 查看页目录表
kd> !dq be8dc500
#be8dc500 00000000`ad081801 00000000`acd82801
//页目录表
kd> !dq 00000000`ad081000+8*2
#ad081010 00000000`42ebc867 00000000`00000000
// 页表
kd> !dq 00000000`42ebc000+17*8
#42ebc0b8 80000000`07ed6025 80000000`ae6bd005
#42ebc0c8 00000000`00000000 80000000`7c50f867
// 分页首地址
kd> !db 80000000`07ed6000+0xbf0
#8000000007ed6bf0 61 61 61 62 62 62 0a 00-00 00 00 00 25 70 0a 00 aaabbb......%p..
然后查看一下虚拟地址
kd> .process /i 89176030
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
8407a394 cc int 3
kd> db 417bf0
00417bf0 61 61 61 62 62 62 0a 00-00 00 00 00 25 70 0a 00 aaabbb......%p..