Page Table - Virtual address to physical address
Author: 堇姬Naup
前言
把之前寫到一半的完善好了,丟上來
https://hackmd.io/@naup96321/H1gx5xJDle


qemu monitor
https://qemu-project.gitlab.io/qemu/system/monitor.html
可以用他來讀寫物理記憶體或是做很多事情
把 Qemu 加上 -monitor unix:/tmp/qemu-monitor.sock,server,nowait
後 load 這支
https://github.com/Naupjjin/slub-gdbext/tree/main
就可以通過 socket,來去操作 qemu monitorqemu_monitor 'monitor_command_string'
1 | import socket |
實際用起來長這樣

原理
Virtual address 對應的就是 page table offset
通過他來查表可以查出 physical address
VA 實際上只會用到 48 bits,其餘是 Sign Extension
9 bits PML4I (Page-Map Level-4 Index)
9 bits PDPI (Page Directory Pointer Index)
9 bits PDI (Page Directory Index)
9 bits PTI (Page Table Index)
12 bits Physical Page Offset
0xffffffff82b6a3a0
Unused (bits 63–48) : 0xffff (65535)
PML4 Index : 0x1ff (511)
PDPT Index : 0x1fe (510)
PD Index : 0x15 (21)
PT Index : 0x16a (362)
Offset : 0x3a0 (928)
參考該docs的2.5(p.3069)
Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4

CR3 register contains the base address of the page-directorypointer table. With 4-level paging and 5-level paging, the CR3 register contains the base address of the PML4 table and PML5 table
0 PWT(Page-level Write-Through)
1 PCD(Page-level Cache Disable)
11:2 保留
63:12 Page table base address(PML4 physical address)
可以從 cr3 來找到 Page table 最上層
只要把最低 12 bits mask 掉,就是 page table physical address,把他轉為 virtual address 來看比較方便


每一個 Table 為 1 Page (4 KB)
每一個 Entry 為 8 Bytes
因此每一個 Table 含有 512 個 Entries (分別就對應 9 bits, 2^9 = 512)
高四個 page table 找到想找的 page 後
通過最後低位 12 bits
找到該 page 具體位置
就是個先映射到實際 page,在從該 page 找實際位置的轉換方式
cr3 找到第一個頁表的位置後,就可以通過 VA 算出的第一個值,找 offset,以此類推
512**4*0x1000-1 = 0xffffffffffff
就是 48 bits
gdb (2MB page)
目標將
1 | gef> p &slab_caches |
手動轉成 physical address
這邊不知道他是 2MB 還是 4KB,不過前三張找法是一樣的
Unused (bits 63–48) : 0xffff (65535)
PML4 Index : 0x1ff (511)
PDPT Index : 0x1fe (510)
PD Index : 0x15 (21)
cr3 to PML4

先找 cr3

0x0000000004866000 & ~0xfff = 0x0000000004866000
這樣就找到 PML4 base (PA) = 0x0000000004866000
VA = 0xffff888004866000

PML4 to PDP
PML4,Linux Kernel 的 PGD (Page Global Directory)
PML4 entry 長這樣,整張 PML4 頁表共有 512 個

高 9 bits 轉 offset,找到對應 PML4E
0xffff888004866000 + 511 * 8 = 0xffff888004866ff8

根據 PML4E 去掉低 12 bits,跟高 1 bits0x0000000002a33067 & ~0xfff = 0x2a33000

這樣就找到 PDP base (PA) = 0x2a33000
VA = 0xffff888002a33000
PDP 2 PD
PDP, Linux Kernel 的 PUD (Page Upper Directory)
接下來從 PDP 找出 PD base
PDPE 長這樣

算 offset 找到0xffff888002a33000 + 510 * 8 = 0xffff888002a33ff0

根據 PDPE 去掉低 12 bits,跟高 1 bits0x0000000002a34063 & ~0xfff = 0x2a34000

這樣就找到 PD base (PA) = 0x2a34000
VA = 0xffff888002a34000
PD find any
PD,Linux Kernel 的 PMD (Page Middle Directory)
PDE 長這樣



算 offset 找到0xffff888002a34000 + 0x15 * 8 = 0xffff888002a340a8

找到的 PDE 長這樣0x8000000002a000e3
0b1000000000000000000000000000000000000010101000000000000011100011
這邊跟先前的不太一樣
可以關注到這邊的 PDE 有兩種形式
在 2 MB / 4 KB Page Size 的情況結構不同
會根據 PS 來標示是哪種
1 的話是 2 MB
4KB 找到的是 PT base
在 2MB 狀況下沒有 PT,是直接找到該 physical page frame
所以轉換一下0x0000000002a000e3 & ~0xfffff = 0x2a00000
PS: 這邊附上 PT 的 PTE

page frame + offset
所以前面的重新計算一下
2MB:
Unused (bits 63–48) : 0xffff (65535)
PML4 Index : 0x1ff (511)
PDPT Index : 0x1fe (510)
PD Index : 0x15 (21)
Offset (2MB page) : 0x16a3a0 (1483680)
physical page frame = 0x2a00000
加上 offset 0x16a3a0
0x2a00000 + 0x16a3a0 = 0x2b6a3a0
這樣就找到 physical adress 啦

gdb (4KB page)
這次把 kaslr 打開來,並搭配 monitor
要找 0xffffffff8538adc0
1 | gef> x/6xg 0xffffffff8538adc0 |

cr3 to PML4

先找 cr3

0x2068000 & ~0xfff = 0x2068000
這樣就找到 PML4 base (PA): 0x2068000
PML4 to PDP
PML4,Linux Kernel 的 PGD (Page Global Directory)
PML4 entry 長這樣,整張 PML4 頁表共有 512 個

高 9 bits 轉 offset,找到對應 PML4E
0x2068000 + 511 * 8 = 0x2068ff8

根據 PML4E 去掉低 12 bits,跟高 1 bits0x0000000015033067 & ~0xfff = 0x15033000
這樣就找到 PDP base (PA) = 0x15033000
PDP 2 PD
PDP, Linux Kernel 的 PUD (Page Upper Directory)
接下來從 PDP 找出 PD base
PDPE 長這樣

算 offset 找到0x15033000 + 510 * 8 = 0x15033ff0

根據 PDPE 去掉低 12 bits,跟高 1 bits0x0000000015034063 & ~0xfff = 0x15034000
這樣就找到 PD base (PA) = 0x15034000
PD find PT
PD,Linux Kernel 的 PMD (Page Middle Directory)
PDE 長這樣



算 offset 找到0x15034000 + 0x29 * 8 = 0x15034148

0x000000000240e063 = 0b10010000001110000001100011
第 7 個是 0,是 4 KB,有 PT
0x000000000240e063 & ~0xfff = 0x240e000
這樣就找到 PT base (PA) = 0x240e000
PT to physical page frame
PT
PTE 長這樣

0x240e000 + 0x18a * 8 = 0x240ec50

0x000000001478a021 & ~0xfff = 0x1478a000
這樣就找到那張 page 了
page base 是 0x1478a000
page frame + offset
0x1478a000 + 0xdc0 = 0x1478adc0
長的一模一樣,找到了

after all
以上就是如何轉換
終於寫完了