Windows内核实验:非PAE分页(Non-PAE paging)

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:004197B0
请按任意键继续. . .

物理地址解析过程

windbg

kd> !process 0 0 test.exe
Failed to get VadRoot
PROCESS 81398480 SessionId: 0 Cid: 01e4 Peb: 7ffd9000 ParentCid: 04a8
DirBase: 00dac000 ObjectTable: e2571638 HandleCount: 15.
Image: test.exe

image-20230601151108340

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

image-20230601152207229

004197B0就是我们的线性地址,按照经典二级页表分开

00000000 01 //0x1
000001 1001 //0x19
0111 10110000 //0x7B0
kd> !dd 0xdac000
# dac000 0303a067 00899067 00000000 00000000

windbg 前面加个! 查看物理内存

第一项找到页目录项 00899067,后面三位是属性位,页表地址为00899000

kd> !dd 00899000 + 0x19*4
# 899064 0025f067 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 004197B0
X86VtoP: Virt 00000000004197b0, pagedir 0000000000dac000
X86VtoP: PDE 0000000000dac004 - 00899067
X86VtoP: PTE 0000000000899064 - 0025f067
X86VtoP: Mapped phys 000000000025f7b0
Virtual address 4197b0 translates to physical address 25f7b0.

查看进程低2G内存

直接d来的低2g,由于系统有很多进程,dbg不知道读哪个

kd> db 004197B0
004197b0 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
004197c0 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????

可以.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位系统大部分这样实现

image-20230601202830592

页目录表是放在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:004197B0
请按任意键继续. . .
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> ?? ((0x04197B0>> 12) << 2) + 0xc0000000
unsigned int 0xc0001064
kd> dd 0xc0001064
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 00000000007f3064
# 7f3064 0c889067 0025b067 039aa025 00000000
# 7f3074 00000000 00000000 00000000 00000000
# 7f3084 00000000 00000000 00000000 00000000
# 7f3094 00000000 00000000 00000000 00000000
# 7f30a4 00000000 00000000 00000000 00000000
# 7f30b4 00000000 00000000 00000000 00000000
# 7f30c4 00000000 00000000 00000000 00000000
# 7f30d4 00000000 00000000 00000000 00000000
kd> ?? ((0x04197B0 >> 22) <<2) + 0xc0300000
unsigned int 0xc0300004
kd> dd 0xc0300004
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 0000000001fcc004
# 1fcc004 007f3067 00000000 00000000 00000000
# 1fcc014 00000000 00000000 00000000 00000000
# 1fcc024 00000000 00000000 00000000 00000000
# 1fcc034 00000000 00000000 00000000 00000000
# 1fcc044 00000000 00000000 00000000 00000000
# 1fcc054 00000000 00000000 00000000 00000000
# 1fcc064 00000000 00000000 00000000 00000000
# 1fcc074 00000000 00000000 00000000 00000000

可以看到实际是一块物理内存