页表
知识点
内核文件
32位特有的
- 如果是29912分页, 运行的内核 ntkrnlpa.exe;
- 如果是101012分页, 运行的内核 ntoskrnl.exe;
C:\Windows\System32\drivers目录下保存的都是一些系统驱动;
- 线性地址一致, 为什么内存数据不一致
- 物理内存小于虚拟内存
物理地址的拆分
10-10-12分页拆分
- 在notepad中键入字符串后使用CE找到该字符串的逻辑地址: 0009DE08
- 拆分地址
0009DE08 => 0000 0000 0000 | 0000 1001 1101 | 1110 0000 1000
0000 0000 0000 => 0 // 页目录项
0000 1001 1101 => 09D // 页表项
1110 0000 1000 => E08 // 页内偏移 - 在WinDBG中查找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48// 首先使用命令!process 0 0找到notepad进程的CR3
// 注意:物理内存要使用感叹号(!)
kd> !dd 32f99000 // notepad进程的CR3(代表这本书)
#32f99000 1c1ce867 25e09867 1c16c867 18485867
#32f99010 00000000 00000000 00000000 00000000
#32f99020 05265867 17c66867 00000000 00000000
#32f99030 00000000 00000000 00000000 00000000
#32f99040 00000000 00000000 00000000 00000000
#32f99050 00000000 00000000 00000000 00000000
#32f99060 00000000 00000000 00000000 00000000
#32f99070 00000000 00000000 00000000 00000000
kd> !dd 32f99000+0*4 // 每一项代表的是指针, 32位下为4字节, 所以需要乘以4
#32f99000 1c1ce867 25e09867 1c16c867 18485867
#32f99010 00000000 00000000 00000000 00000000
#32f99020 05265867 17c66867 00000000 00000000
#32f99030 00000000 00000000 00000000 00000000
#32f99040 00000000 00000000 00000000 00000000
#32f99050 00000000 00000000 00000000 00000000
#32f99060 00000000 00000000 00000000 00000000
#32f99070 00000000 00000000 00000000 00000000
kd> !dd 1c1ce000+09D*4 // 去除最后的12位(后面的12位在页目录下代表了注意事项, 也就是属性), 然后加上页表项09D
#1c1ce274 2cea5867 212fc867 27c7e867 2d13f867
#1c1ce284 20f43867 28843867 286c3867 03244867
#1c1ce294 02b85847 3038b867 0a4ca847 00000000
#1c1ce2a4 00000000 00000000 00000000 00000000
#1c1ce2b4 00000000 00000000 00000000 00000000
#1c1ce2c4 00000000 00000000 00000000 00000000
#1c1ce2d4 00000000 00000000 00000000 00000000
#1c1ce2e4 00000000 00000000 00000000 00000000
kd> !dd 2cea5000+E08 // 同样去除后12位后加上页内偏移后找到这个字
#2cea5e08 00620061 00640063 00320031 00340033
#2cea5e18 00370035 00000000 00000000 00000000
#2cea5e28 00000000 00000000 00000000 00000000
#2cea5e38 00000000 00000000 00000000 00000000
#2cea5e48 00000000 005f0004 59f3c08e 0800730b
#2cea5e58 000a1aa0 000a1c20 5cf3c08b 08007303
#2cea5e68 00000409 0019f2e0 0019f220 0019f2e0
#2cea5e78 001865cc 00000003 0019ee7c 00000000
kd> !db 2cea5000+E08
#2cea5e08 61 00 62 00 63 00 64 00-31 00 32 00 33 00 34 00 a.b.c.d.1.2.3.4.
#2cea5e18 35 00 37 00 00 00 00 00-00 00 00 00 00 00 00 00 5.7.............
#2cea5e28 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2cea5e38 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#2cea5e48 00 00 00 00 04 00 5f 00-8e c0 f3 59 0b 73 00 08 ......_....Y.s..
#2cea5e58 a0 1a 0a 00 20 1c 0a 00-8b c0 f3 5c 03 73 00 08 .... ......\.s..
#2cea5e68 09 04 00 00 e0 f2 19 00-20 f2 19 00 e0 f2 19 00 ........ .......
#2cea5e78 cc 65 18 00 03 00 00 00-7c ee 19 00 00 00 00 00 .e......|.......
计算一次缓存的字节数
总字节数 / linesize / x way = y组
y 组 / x way = 1组z行 z行 * linesize = 一组缓存的字节数
(32K * 1024) / 64 / 8 = 总组数(64)
64(总组数) / 8 = 8行
8 * 64字节 = 512组的字节数
P_US_RW
PDE和PTE是与的关系(PDE.arr & PTE.arr), 最后得出为1的才是有效的;
P位
如果是PDE的P位置0, 那么代表PTT为无效;
如果是PTE的P为置0, 那么代表物理页为无效;
R/W位
R/W位为0, 代表只读;
R/W位为1, 代表可写;
代码实验
- 拆分地址
a57 b30 => 0000 0000 10 | 10 0101 0111 | 1011 0011 0000
0000 0000 0010 => 2
0010 0101 0111 => 257
1011 0011 0000 => b30
- WinDBG中设置
1 | kd> !dd 1622e000+2*4 // 1622e000为实验程序的CR3, PDE(18996867)最后一位为7(0111), 证明可写 |
- 代码
1 | // 10_14_PageProperties(页属性).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
U/S位(user/super)
如果U/S位为0, 代表只有内核可以访问页;
如果U/S位为1, 代表三环可以访问页;
代码实验
- 拆分地址
80b98800 => 0010 0000 0010 | 0011 1001 1000 | 1000 0000 0000
0010 0000 0010 => 202 // 前面的往后移, 前面补0
0011 1001 1000 => 398
1000 0000 0000 => 100
- 查询gdtr属性
1 | kd> !pte 0x80b98800 // 查询默认gdtr地址 |
- WinDBG中设置
1 | kd> !dd 0199a000+202*4 // 获取当前进程的PDE |
- 实验代码
1 | // 10_14_PageProperties(页属性).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
A位
不是人为设置, 如果从来没有访问过可能是个0, 一旦访问过一次(读或者写)就会变成1;
G位(全局页)
挂页(幽灵地址)
申请内存并挂到0地址上
- 拆地址
1d0000 => 0000 0000 00 | 01 1101 0000 | 0000 0000 0000
0000 0000 0000 => 0
0001 1101 0000 => 1d0
0000 0000 0000 => 0
- WinDBG中设置
PTE: 04922847
1 | kd> !dd 1c2c5000 // 通过CR3获取PDE |
- 实验代码
1 | // 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
在本进程中的0地址上执行shellcode
- 拆地址
2f0000 => 0000 0000 00 | 10 1111 0000 | 0000 0000 0000
0000 0000 0000 => 0
0010 1111 0000 => 2f0
0000 0000 0000 => 0
- WinDBG中设置
PTE: 0a512867
1 | kd> !dd 20f6a000 // 根据进程CR3获取PDE |
- 实验代码
1 | // 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
将物理页挂到其他进程并执行shellcode
注意
- 该实验无法在cheatengine-i386.exe(CE)上成功复现, 在notepad.exe上成功复现;
- 拆地址
180000 => 0000 0000 00 | 01 1000 0000 | 0000 0000 0000
0000 0000 0000 => 0
0001 1000 0000 => 180
0000 0000 0000 => 0
- WinDBG中设置
- notepad.exe进程信息
PROCESS 87460570 SessionId: 1 Cid: 0978 Peb: 7ffda000 ParentCid: 0a48
DirBase: 015de000 ObjectTable: b3a87c30 HandleCount: 60.
Image: notepad.exe - 实验进程信息
PROCESS 87620030 SessionId: 1 Cid: 03f8 Peb: 7ffdc000 ParentCid: 060c
DirBase: 03005000 ObjectTable: a4d11110 HandleCount: 19.
Image: 10_16_HangingPage(¹ÒÒ³).exe
1 | kd> !dd 03005000 // 首先通过本进程的CR3获取PDE |
- 实验代码
1 | // 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
带页内偏移挂页
- 拆地址
80000 => 0000 0000 00 | 00 1000 0000 | 0000 0000 0000
0000 0000 0000 => 0
0000 1000 0000 => 080
0000 0000 0000 => 0
- WinDBG中设置
notepad.exe进程信息
PROCESS 87564030 SessionId: 1 Cid: 129c Peb: 7ffdf000 ParentCid: 0a48
DirBase: 34cc7000 ObjectTable: 95581928 HandleCount: 60.
Image: notepad.exe实验程序进程信息
PROCESS 86d307c8 SessionId: 1 Cid: 151c Peb: 7ffd9000 ParentCid: 1478
DirBase: 1611b000 ObjectTable: 954c7388 HandleCount: 19.
Image: 10_16_HangingPage(¹ÒÒ³).exe
1 | kd> !dd 1611b000 // 通过实验程序获取PDE |
- 实验代码
1 | // 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |