Windows内核实验:非PAE分页(Non-PAE paging) PAE(Physical Address Extension)
multi(0 )disk(0 )rdisk(0 )partition(1 )\WINDOWS="Microsoft Windows XP Home Edition DEBUG" /noexecute=optin /fastdetect /debugport=COM1 /baudrate=115200
把原来的noexecute改为execute,来关闭pae
multi(0 )disk(0 )rdisk(0 )partition(1 )\WINDOWS="Microsoft Windows XP Home Edition DEBUG" /execute=optin /fastdetect /debugport=COM1 /baudrate=115200
cr4寄存器的第五位(从0开始)是pae标识位,验证下
kd> .formats cr4 Evaluate expression: Hex: 000006d9 Decimal: 1753 Decimal (unsigned) : 1753 Octal: 00000003331 Binary: 00000000 00000000 00000110 11011001 Chars: .... Time: Thu Jan 1 08:29:13 1970 Float: low 2.45648e-042 high 0 Double: 8.66097e-321
第五位是0,没有开启pae
测试程序 # include <stdio.h> # include <stdlib.h> # include <windows.h> DWORD local_num = 0x12345678; DWORD g_cr3; void __declspec(naked) IdtEntry() {//裸函数不会帮我们生成栈帧,单纯一个call __asm { mov eax,cr3 mov g_cr3, eax iretd } } void interrupt() { __asm { int 0x20 } } int main() { if (0x401040 != IdtEntry) { printf("IdtRntry address wrong"); system("pause"); exit(-1); } //eq 8003f500 0040ee00`00081040 interrupt(); printf("g_cr3:0x%x\n", g_cr3); printf("local num address:%p\n",&local_num); system("pause"); }
g_cr3:0xdac000 local num address:004197B 0 请按任意键继续. . .
物理地址解析过程 windbg
kd> !process 0 0 test.exe Failed to get VadRoot PROCESS 81398480 SessionId: 0 Cid: 01e4 Peb: 7f fd9000 ParentCid: 04 a8 DirBase: 00 dac000 ObjectTable: e2571638 HandleCount: 15. Image: test.exe
dirbase就是页目录地址基址,就是cr3里的值 ps: PDBR(Page Directory Base Register)
kd> .formats 004197B0 Evaluate expression: Hex: 004197b0 Decimal: 4298672 Decimal (unsigned) : 4298672 Octal: 00020313660 Binary: 00000000 01000001 10010111 10110000 Chars: .A.. Time: Fri Feb 20 02:04:32 1970 Float: low 6.02372e-039 high 0 Double: 2.12383e-317
004197B0就是我们的线性地址,按照经典二级页表分开
00000000 01 000001 1001 0111 10110000
kd> !dd 0xdac000 # dac000 0303 a067 00899067 00000000 00000000
windbg 前面加个! 查看物理内存
第一项找到页目录项 00899067,后面三位是属性位,页表地址为00899000
kd> !dd 00899000 + 0x19 *4 # 899064 0025f 067 00861067 00004025 00000000
找到页表项PTE 0025f067 同样后面三位是属性,物理基地址为0025f000
kd> !db 0025f000 + 0x7B0 # 25f7b0 78 56 34 12 00 00 00 00-00 00 00 00 00 00 00 00 xV4.............
windbg提供了!vtop 扩展将虚拟地址转换为相应的物理地址
!vtop PFN VirtualAddress PFN Specifies the page frame number (PFN) of the directory base for the process. VirtualAddress Specifies the virtual address whose page is desired.
kd> !vtop 0xdac 004197B 0 X86VtoP: Virt 00000000004197b 0, pagedir 0000000000 dac000 X86VtoP: PDE 0000000000 dac004 - 00899067 X86VtoP: PTE 0000000000899064 - 0025f 067 X86VtoP: Mapped phys 000000000025f 7b0 Virtual address 4197b 0 translates to physical address 25f 7b0.
查看进程低2G内存 直接d来的低2g,由于系统有很多进程,dbg不知道读哪个
kd> db 004197B 0 004197b 0 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????004197 c0 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
可以.process 81398480
kd> .process 81398480 ReadVirtual: 81398498 not properly sign extended Implicit process is now 81398480 WARNING: .cache forcedecodeuser is not enabled kd> db 004197B0 004197b0 78 56 34 12 00 00 00 00-00 00 00 00 00 00 00 00 xV4............. kd> r cr3 cr3=00039000
但是他的cr3还是原来的,可能自己有时候不注意导致一些不必要的麻烦
最好.process /i 81398480(/i 将调试器的当前进程切换到指定进程映像路径对应的进程) 然后g一下
kd> .process /i 81398480 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: 804e4592 cc int 3 kd> r cr3 cr3=00dac000 kd> db 004197B0 004197b0 78 56 34 12 00 00 00 00-00 00 00 00 00 00 00 00 xV4.............
页目录和页表在虚拟内存里的表
CR3中存储的是物理地址,不能在程序中直接读取的。如果想读取,也要把Cr3的值挂到PDT和PTT中才能访问,那么怎么通过线性地址访问PDT和PTT呢?
有了固定地址,这样我们就可以通过线性地址来访问页目录和页表,方便维护 似乎32位系统大部分这样实现
页目录表是放在0xc0300000处,二级页表前3g是从0xc0000000处,后面1G是从0xc030 0000开始
这里我觉的一个比较巧妙的点是,中间的4k的页目录表
首先0xc000 0000是虚拟内存3G的起点,页目录表是从0xc0300000开始占4k,相当于虚拟地址3G开始处的4M不用描述,这个4M正好是所有页表的总大小
所有从虚拟地址addr得到他的页表项虚拟地址公式为 ((addr >> 12) << 2) + 0xc0000000
>>12相当于除以page大小4k算出index(因为一个页表项描述4k大小物理内存),<<2一个页表项4byte
页目录项虚拟地址公式为 ((addr >> 22) <<2) + 0xc0300000
>>22除以4M(因为一个页目录项描述4M内存)
调试
手残。。,把原来的test.exe关了,现在cr3是下面的
g_cr3:0x1fcc000 local num address:004197B 0 请按任意键继续. . .
kd> !process 0 0 test.exe Failed to get VadRoot PROCESS 8162dc30 SessionId: 0 Cid: 00c8 Peb: 7ffd6000 ParentCid: 04a4 DirBase: 01fcc000 ObjectTable: e2436230 HandleCount: 15. Image: test.exe kd> .process /i 8162dc30 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 ntStatus=0Break instruction exception - code 80000003 (first chance) nt!RtlpBreakWithStatusInstruction: 804e4592 cc int 3 kd> r cr3 cr3=01fcc000 kd> !vtop 1fcc 004197B0 X86VtoP: Virt 00000000004197b0, pagedir 0000000001fcc000 X86VtoP: PDE 0000000001fcc004 - 007f3067 X86VtoP: PTE 00000000007f3064 - 0c889067 X86VtoP: Mapped phys 000000000c8897b0 Virtual address 4197b0 translates to physical address c8897b0. kd> !db c8897b0 l8 # c8897b0 78 56 34 12 00 00 00 00 xV4......EN..... kd> !pte 004197B0 VA 004197b0 PDE at C0300004 PTE at C0001064 contains 007F3067 contains 0C889067 pfn 7f3 ---DA--UWEV pfn c889 ---DA--UWEV kd> ?? ((0 x04197B0>> 12 ) << 2 ) + 0 xc0000000 unsigned int 0xc0001064 kd> dd 0 xc0001064 c0001064 0c889067 0025b067 039aa025 00000000 c0001074 00000000 00000000 00000000 00000000 c0001084 00000000 00000000 00000000 00000000 c0001094 00000000 00000000 00000000 00000000 c00010a4 00000000 00000000 00000000 00000000 c00010b4 00000000 00000000 00000000 00000000 c00010c4 00000000 00000000 00000000 00000000 c00010d4 00000000 00000000 00000000 00000000 kd> !dd 00000000007 f3064 # 7 f3064 0 c889067 0025 b067 039 aa025 00000000 # 7 f3074 00000000 00000000 00000000 00000000 # 7 f3084 00000000 00000000 00000000 00000000 # 7 f3094 00000000 00000000 00000000 00000000 # 7 f30a4 00000000 00000000 00000000 00000000 # 7 f30b4 00000000 00000000 00000000 00000000 # 7 f30c4 00000000 00000000 00000000 00000000 # 7 f30d4 00000000 00000000 00000000 00000000 kd> ?? ((0 x04197B0 >> 22 ) <<2 ) + 0 xc0300000 unsigned int 0xc0300004 kd> dd 0 xc0300004 ReadVirtual: c0300004 not properly sign extended c0300004 007f3067 00000000 00000000 00000000 c0300014 00000000 00000000 00000000 00000000 c0300024 00000000 00000000 00000000 00000000 c0300034 00000000 00000000 00000000 00000000 c0300044 00000000 00000000 00000000 00000000 c0300054 00000000 00000000 00000000 00000000 c0300064 00000000 00000000 00000000 00000000 c0300074 00000000 00000000 00000000 00000000 kd> !dd 0000000001 fcc004 # 1 fcc004 007 f3067 00000000 00000000 00000000 # 1 fcc014 00000000 00000000 00000000 00000000 # 1 fcc024 00000000 00000000 00000000 00000000 # 1 fcc034 00000000 00000000 00000000 00000000 # 1 fcc044 00000000 00000000 00000000 00000000 # 1 fcc054 00000000 00000000 00000000 00000000 # 1 fcc064 00000000 00000000 00000000 00000000 # 1 fcc074 00000000 00000000 00000000 00000000
可以看到实际是一块物理内存