抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

页表

知识点

内核文件

32位特有的

  • 如果是29912分页, 运行的内核 ntkrnlpa.exe;
  • 如果是101012分页, 运行的内核 ntoskrnl.exe;

C:\Windows\System32\drivers目录下保存的都是一些系统驱动;

  1. 线性地址一致, 为什么内存数据不一致
  2. 物理内存小于虚拟内存

物理地址的拆分

10-10-12分页拆分

  1. 在notepad中键入字符串后使用CE找到该字符串的逻辑地址: 0009DE08
  2. 拆分地址
    0009DE08 => 0000 0000 0000 | 0000 1001 1101 | 1110 0000 1000
    0000 0000 0000 => 0 // 页目录项
    0000 1001 1101 => 09D // 页表项
    1110 0000 1000 => E08 // 页内偏移
  3. 在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, 代表可写;

代码实验

  1. 拆分地址
    a57 b30 => 0000 0000 10 | 10 0101 0111 | 1011 0011 0000
    0000 0000 0010 => 2
    0010 0101 0111 => 257
    1011 0011 0000 => b30
  1. 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
49
kd> !dd 1622e000+2*4        // 1622e000为实验程序的CR3, PDE(18996867)最后一位为7(0111), 证明可写
#1622e008 18996867 00000000 00000000 00000000
#1622e018 00000000 00000000 00000000 00000000
#1622e028 00000000 00000000 00000000 00000000
#1622e038 00000000 00000000 00000000 00000000
#1622e048 00000000 00000000 00000000 00000000
#1622e058 00000000 00000000 00000000 00000000
#1622e068 00000000 00000000 00000000 00000000
#1622e078 00000000 00000000 00000000 00000000
kd> !dd 18996000+257*4 // 去除后12位加上页表项乘以4, PTE(0abb8005)最后一位为5(0101), 证明不可写
#1899695c 0abb8005 1cc79005 00000000 19352847
#1899696c 31ba6005 09e2f205 3685e005 3d0da005
#1899697c 00000000 00000000 00000000 00000000
#1899698c 00000000 00000000 00000000 00000000
#1899699c 00000000 00000000 00000000 00000000
#189969ac 00000000 00000000 00000000 00000000
#189969bc 00000000 00000000 00000000 00000000
#189969cc 00000000 00000000 00000000 00000000
kd> !ed 1899695c 0abb8007 // 将0abb8005修改为0abb8007, PTE(0abb8007)最后一位为7(0111), &之后R/W位为1, 修改为可写状态
kd> !dd 0abb8000+b30
# abb8b30 61647361 73676473 00616664 00000000
# abb8b40 0a0d7825 00000000 73756170 00000065
# abb8b50 0a0d7325 00000000 00a57c18 00a57d28
# abb8b60 00a57e80 00a57ea4 00a57ee4 00a57f18
# abb8b70 00000001 00000000 00000001 00000001
# abb8b80 00000001 00000001 63617453 7261206b
# abb8b90 646e756f 65687420 72617620 6c626169
# abb8ba0 00272065 61772027 6f632073 70757272
kd> !db 0abb8000+b30 // 实验程序中的字符串
# abb8b30 61 73 64 61 73 64 67 73-64 66 61 00 00 00 00 00 asdasdgsdfa.....
# abb8b40 25 78 0d 0a 00 00 00 00-70 61 75 73 65 00 00 00 %x......pause...
# abb8b50 25 73 0d 0a 00 00 00 00-18 7c a5 00 28 7d a5 00 %s.......|..(}..
# abb8b60 80 7e a5 00 a4 7e a5 00-e4 7e a5 00 18 7f a5 00 .~...~...~......
# abb8b70 01 00 00 00 00 00 00 00-01 00 00 00 01 00 00 00 ................
# abb8b80 01 00 00 00 01 00 00 00-53 74 61 63 6b 20 61 72 ........Stack ar
# abb8b90 6f 75 6e 64 20 74 68 65-20 76 61 72 69 61 62 6c ound the variabl
# abb8ba0 65 20 27 00 27 20 77 61-73 20 63 6f 72 72 75 70 e '.' was corrup
kd> g
nt!RtlpBreakWithStatusInstruction:
84066ed0 cc int 3
kd> !db 0abb8000+b30 // 已经被修改
# abb8b30 31 73 64 61 73 64 67 73-64 66 61 00 00 00 00 00 1sdasdgsdfa.....
# abb8b40 25 78 0d 0a 00 00 00 00-70 61 75 73 65 00 00 00 %x......pause...
# abb8b50 25 73 0d 0a 00 00 00 00-18 7c a5 00 28 7d a5 00 %s.......|..(}..
# abb8b60 80 7e a5 00 a4 7e a5 00-e4 7e a5 00 18 7f a5 00 .~...~...~......
# abb8b70 01 00 00 00 00 00 00 00-01 00 00 00 01 00 00 00 ................
# abb8b80 01 00 00 00 01 00 00 00-53 74 61 63 6b 20 61 72 ........Stack ar
# abb8b90 6f 75 6e 64 20 74 68 65-20 76 61 72 69 61 62 6c ound the variabl
# abb8ba0 65 20 27 00 27 20 77 61-73 20 63 6f 72 72 75 70 e '.' was corrup
  1. 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 10_14_PageProperties(页属性).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

int main()
{
char *x = (char*)"asdasdgsdfa";

printf("%x\r\n", x);

system("pause");

printf("%s\r\n", x);
x[0] = '1';
printf("%s\r\n", x);
system("pause");

return 0;
}

U/S位(user/super)

如果U/S位为0, 代表只有内核可以访问页;
如果U/S位为1, 代表三环可以访问页;

代码实验

  1. 拆分地址
    80b98800 => 0010 0000 0010 | 0011 1001 1000 | 1000 0000 0000
    0010 0000 0010 => 202 // 前面的往后移, 前面补0
    0011 1001 1000 => 398
    1000 0000 0000 => 100
  1. 查询gdtr属性
1
2
3
4
5
kd> !pte 0x80b98800     // 查询默认gdtr地址
VA 80b98800
PDE at C0300808 PTE at C0202E60
contains 0018A063 contains 00B98163 // 最后一位是3(0011), 代表P位和R/W位有值, U/S位为0, 意味着用户模式下访问不到, 只能内核访问
pfn 18a ---DA--KWEV pfn b98 -G-DA--KWEV
  1. 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
49
50
51
52
53
54
55
56
57
58
59
60
kd> !dd 0199a000+202*4      // 获取当前进程的PDE
# 199a808 0018a063 3d3c7863 001b7063 001b8063
# 199a818 001b9063 001ba063 001bb063 001bc063
# 199a828 001bd063 001be063 001bf063 21a3c863
# 199a838 210aa863 001c2063 001c3063 001c4063
# 199a848 00000000 00000000 001c7063 05400863
# 199a858 05801863 3fec0863 3fe81863 3fe82863
# 199a868 3fe83863 3fe84863 3fe85863 3fe86863
# 199a878 3fe87863 18c23863 3a3a8863 3d3c3863
kd> !ed 199a808 0018a067 // 设置PDE中U/S位为1
kd> !dd 0199a000+202*4
# 199a808 0018a067 3d3c7863 001b7063 001b8063
# 199a818 001b9063 001ba063 001bb063 001bc063
# 199a828 001bd063 001be063 001bf063 21a3c863
# 199a838 210aa863 001c2063 001c3063 001c4063
# 199a848 00000000 00000000 001c7063 05400863
# 199a858 05801863 3fec0863 3fe81863 3fe82863
# 199a868 3fe83863 3fe84863 3fe85863 3fe86863
# 199a878 3fe87863 18c23863 3a3a8863 3d3c3863
kd> !dd 0018a000+398*4 // 查询当前进程的PTE
# 18ae60 00b98163 00b99163 00b9a163 00b9b163
# 18ae70 00b9c163 00b9d163 00b9e163 00b9f163
# 18ae80 00ba0163 00000000 00000000 00000000
# 18ae90 00000000 00000000 00000000 00000000
# 18aea0 00000000 00000000 00000000 00000000
# 18aeb0 00bac963 00bad121 00bae121 00baf963
# 18aec0 03d01060 00000000 00000000 00000000
# 18aed0 00000000 00000000 00000000 00000000
kd> !ed 18ae60 00b98167 // 设置PTE的U/S位为1
kd> !dd 0018a000+398*4
# 18ae60 00b98167 00b99163 00b9a163 00b9b163
# 18ae70 00b9c163 00b9d163 00b9e163 00b9f163
# 18ae80 00ba0163 00000000 00000000 00000000
# 18ae90 00000000 00000000 00000000 00000000
# 18aea0 00000000 00000000 00000000 00000000
# 18aeb0 00bac963 00bad121 00bae121 00baf963
# 18aec0 03d01060 00000000 00000000 00000000
# 18aed0 00000000 00000000 00000000 00000000
kd> !vtop 0199a000 0x80b98800 // 查询当前进程的CR3信息
X86VtoP: Virt 0000000080b98800, pagedir 000000000199a000
X86VtoP: PDE 000000000199a808 - 0018a067
X86VtoP: PTE 000000000018ae60 - 00b98167
X86VtoP: Mapped phys 0000000000b98800
Virtual address 80b98800 translates to physical address b98800.
kd> !ed 18ae60 00b98067 // 设置PTE的G位为1
kd> !dd 0018a000+398*4
# 18ae60 00b98067 00b99163 00b9a163 00b9b163
# 18ae70 00b9c163 00b9d163 00b9e163 00b9f163
# 18ae80 00ba0163 00000000 00000000 00000000
# 18ae90 00000000 00000000 00000000 00000000
# 18aea0 00000000 00000000 00000000 00000000
# 18aeb0 00bac963 00bad121 00bae121 00baf963
# 18aec0 03d01060 00000000 00000000 00000000
# 18aed0 00000000 00000000 00000000 00000000
kd> !vtop 0199a000 0x80b98800 // 查询当前进程的CR3信息
X86VtoP: Virt 0000000080b98800, pagedir 000000000199a000
X86VtoP: PDE 000000000199a808 - 0018a067
X86VtoP: PTE 000000000018ae60 - 00b98067
X86VtoP: Mapped phys 0000000000b98800
Virtual address 80b98800 translates to physical address b98800.
  1. 实验代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 10_14_PageProperties(页属性).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

int main()
{
// u/s位代码试验
char buf[6] = { 0 };
__asm
{
sgdt buf;
}

int address = *(PULONG)&buf[2];
int * x = (int*)address;
system("pause");
printf("%x\r\n", *x);

system("pause");

return 0;
}

A位

不是人为设置, 如果从来没有访问过可能是个0, 一旦访问过一次(读或者写)就会变成1;

G位(全局页)

挂页(幽灵地址)

申请内存并挂到0地址上

  1. 拆地址
    1d0000 => 0000 0000 00 | 01 1101 0000 | 0000 0000 0000
    0000 0000 0000 => 0
    0001 1101 0000 => 1d0
    0000 0000 0000 => 0
  1. WinDBG中设置
    PTE: 04922847
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
kd> !dd 1c2c5000        // 通过CR3获取PDE
#1c2c5000 23325867 06e4b867 00000000 376e3867
#1c2c5010 00000000 00000000 00000000 00000000
#1c2c5020 00000000 00000000 00000000 00000000
#1c2c5030 00000000 00000000 00000000 00000000
#1c2c5040 00000000 00000000 00000000 00000000
#1c2c5050 00000000 00000000 00000000 00000000
#1c2c5060 00000000 00000000 00000000 00000000
#1c2c5070 00000000 00000000 00000000 00000000
kd> !dd 23325000+1d0*4 // 获取PTE
#23325740 04922847 00000000 00000000 00000000
#23325750 00000000 00000000 00000000 00000000
#23325760 00000000 00000000 00000000 00000000
#23325770 00000000 00000000 00000000 00000000
#23325780 00000000 00000000 00000000 00000000
#23325790 00000000 00000000 00000000 00000000
#233257a0 00000000 00000000 00000000 00000000
#233257b0 00000000 00000000 00000000 00000000
kd> !dd 04922000 // 查看PTE
# 4922000 00000000 00000000 00000000 00000000
# 4922010 00000000 00000000 00000000 00000000
# 4922020 00000000 00000000 00000000 00000000
# 4922030 00000000 00000000 00000000 00000000
# 4922040 00000000 00000000 00000000 00000000
# 4922050 00000000 00000000 00000000 00000000
# 4922060 00000000 00000000 00000000 00000000
# 4922070 00000000 00000000 00000000 00000000
kd> !dd 1c2c5000 // 获取PDE
#1c2c5000 23325867 06e4b867 00000000 376e3867
#1c2c5010 00000000 00000000 00000000 00000000
#1c2c5020 00000000 00000000 00000000 00000000
#1c2c5030 00000000 00000000 00000000 00000000
#1c2c5040 00000000 00000000 00000000 00000000
#1c2c5050 00000000 00000000 00000000 00000000
#1c2c5060 00000000 00000000 00000000 00000000
#1c2c5070 00000000 00000000 00000000 00000000
kd> !dd 23325000 // 查看PDE
#23325000 00000000 00000000 00000000 00000000
#23325010 00000000 00000000 00000000 00000000
#23325020 00000000 00000000 00000000 00000000
#23325030 00000000 00000000 00000000 00000000
#23325040 0b841847 00000000 00000000 00000000
#23325050 00000000 00000000 00000000 00000000
#23325060 00000000 00000000 00000000 00000000
#23325070 00000000 00000000 00000000 00000000
kd> !ed 23325000 04922847 // 将PDE指针指向PTE的值(04922847)
kd> !dd 23325000
#23325000 04922847 00000000 00000000 00000000
#23325010 00000000 00000000 00000000 00000000
#23325020 00000000 00000000 00000000 00000000
#23325030 00000000 00000000 00000000 00000000
#23325040 0b841847 00000000 00000000 00000000
#23325050 00000000 00000000 00000000 00000000
#23325060 00000000 00000000 00000000 00000000
#23325070 00000000 00000000 00000000 00000000
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
84066ed0 cc int 3
kd> !dd 23325000
#23325000 04922867 00000000 00000000 00000000
#23325010 00000000 00000000 00000000 00000000
#23325020 00000000 00000000 00000000 00000000
#23325030 00000000 00000000 00000000 00000000
#23325040 0b841847 00000000 00000000 00000000
#23325050 00000000 00000000 00000000 00000000
#23325060 00000000 00000000 00000000 00000000
#23325070 00000000 00000000 00000000 00000000
kd> !db 04922000 // 成功修改成100(0x64)
# 4922000 64 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 d...............
# 4922010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 4922070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

  1. 实验代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

int main()
{
int * x = 0;
int * mem = (int*)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

memset(mem, 0, 0x1000);
printf("%x\r\n", mem);
system("pause");

*x = 100;
system("pause");
printf("%d\r\n", *mem);
system("pause");

return 0;
}

在本进程中的0地址上执行shellcode

  1. 拆地址
    2f0000 => 0000 0000 00 | 10 1111 0000 | 0000 0000 0000
    0000 0000 0000 => 0
    0010 1111 0000 => 2f0
    0000 0000 0000 => 0
  1. WinDBG中设置
    PTE: 0a512867
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
kd> !dd 20f6a000        // 根据进程CR3获取PDE
#20f6a000 38736867 03c45867 00000000 00000000
#20f6a010 00000000 00000000 00000000 00000000
#20f6a020 00000000 00000000 00000000 00000000
#20f6a030 00000000 00000000 00000000 00000000
#20f6a040 00000000 00000000 00000000 00000000
#20f6a050 00000000 00000000 00000000 00000000
#20f6a060 00000000 00000000 00000000 00000000
#20f6a070 00000000 00000000 00000000 00000000
kd> !dd 38736000+2f0*4 // 获取PTE
#38736bc0 0a512867 00000000 00000000 00000000
#38736bd0 00000000 00000000 00000000 00000000
#38736be0 00000000 00000000 00000000 00000000
#38736bf0 00000000 00000000 00000000 00000000
#38736c00 00000000 00000000 00000000 00000000
#38736c10 00000000 00000000 00000000 00000000
#38736c20 00000000 00000000 00000000 00000000
#38736c30 00000000 00000000 00000000 00000000
kd> !db 0a512000 // 查看数据
# a512000 6a 00 6a 00 6a 00 6a 00-b8 b1 ed da 75 ff d0 c3 j.j.j.j.....u...
# a512010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# a512070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
kd> !dd 38736000 // 查看0地址
#38736000 00000000 00000000 00000000 00000000
#38736010 00000000 00000000 00000000 00000000
#38736020 00000000 00000000 00000000 00000000
#38736030 00000000 00000000 00000000 00000000
#38736040 0c350847 00000000 00000000 00000000
#38736050 00000000 00000000 00000000 00000000
#38736060 00000000 00000000 00000000 00000000
#38736070 00000000 00000000 00000000 00000000
kd> !ed 38736000 0a512867 // 将PTE(0a512867)挂到0地址上
  1. 实验代码
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
// 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

typedef void(__stdcall * FuncProc)();

int main()
{
int * mem = (int*)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
FuncProc func = NULL;

memset(mem, 0, 0x1000);

char bufcode[] =
{
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0xb8, 0, 0, 0, 0, // mov eax, 0x12345678
0xff, 0xd0, // call eax
0xc3, // ret
};

*(int*)&bufcode[9] = (ULONG)MessageBoxA;
memcpy(mem, bufcode, sizeof(bufcode));

printf("%x\r\n", mem);
system("pause");

// FuncProc func = (FuncProc)mem;
func();


system("pause");
printf("%d\r\n", *mem);
system("pause");

return 0;
}

将物理页挂到其他进程并执行shellcode

注意

  • 该实验无法在cheatengine-i386.exe(CE)上成功复现, 在notepad.exe上成功复现;
  1. 拆地址
    180000 => 0000 0000 00 | 01 1000 0000 | 0000 0000 0000
    0000 0000 0000 => 0
    0001 1000 0000 => 180
    0000 0000 0000 => 0
  1. 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
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
kd> !dd 03005000            // 首先通过本进程的CR3获取PDE
# 3005000 22edd867 1fd2e867 00000000 00000000
# 3005010 00000000 00000000 00000000 00000000
# 3005020 00000000 00000000 00000000 00000000
# 3005030 00000000 00000000 00000000 00000000
# 3005040 00000000 00000000 00000000 00000000
# 3005050 00000000 00000000 00000000 00000000
# 3005060 00000000 00000000 00000000 00000000
# 3005070 00000000 00000000 00000000 00000000
kd> !dd 22edd000+180*4 // 获取本进程的PTE
#22edd600 27e84867 00000000 00000000 00000000
#22edd610 00000000 00000000 00000000 00000000
#22edd620 00000000 00000000 00000000 00000000
#22edd630 00000000 00000000 00000000 00000000
#22edd640 39944005 381d4867 1fdd5867 021d6867
#22edd650 36457867 29bd8867 1d119867 22b1a867
#22edd660 3175c867 30d5d867 2e620867 291a1867
#22edd670 29f21867 14a62867 253e2867 03c23867
kd> !db 27e84000 // 查看数据
#27e84000 6a 00 6a 00 6a 00 6a 00-b8 b1 ed da 75 ff d0 c3 j.j.j.j.....u...
#27e84010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#27e84070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
kd> !dd 015de000 // 通过notepad.exe的CR3获取PDE
# 15de000 3b822867 37a23867 0c64e867 07f55867
# 15de010 00000000 00000000 00000000 29faf867
# 15de020 285b3867 38cf1867 023f5867 04737867
# 15de030 00000000 00000000 00000000 00000000
# 15de040 00000000 00000000 00000000 00000000
# 15de050 00000000 00000000 00000000 00000000
# 15de060 00000000 00000000 00000000 00000000
# 15de070 00000000 00000000 00000000 00000000
kd> !dd 3b822000 // 查看notepad.exe的PTE
#3b822000 00000000 00000000 00000000 00000000
#3b822010 00000000 00000000 00000000 00000000
#3b822020 00000000 00000000 00000000 00000000
#3b822030 00000000 00000000 00000000 00000000
#3b822040 321f8847 00000000 00000000 00000000
#3b822050 00000000 00000000 00000000 00000000
#3b822060 00000000 00000000 00000000 00000000
#3b822070 00000000 00000000 00000000 00000000
kd> !ed 3b822000 27e84867 // 将进程的PTE挂到notepad.exe的0地址上
  1. 实验代码
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
49
50
51
52
53
54
55
56
// 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

typedef void(__stdcall * FuncProc)();

int main()
{
int * mem = (int*)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
FuncProc func = NULL;

memset(mem, 0, 0x1000);

char bufcode[] =
{
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0xb8, 0, 0, 0, 0, // mov eax, 0x12345678
0xff, 0xd0, // call eax
0xc3, // ret
};

*(int*)&bufcode[9] = (ULONG)MessageBoxA;
memcpy(mem, bufcode, sizeof(bufcode));

printf("%x\r\n", mem);
system("pause");

// FuncProc func = (FuncProc)mem;
// func();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 2424);
if (INVALID_HANDLE_VALUE == hProcess)
{
printf("OpenProcess Failed\r\n");
}

HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, NULL, NULL, NULL, NULL);
if (INVALID_HANDLE_VALUE == hThread)
{
printf("CreateRemoteThread Failed\r\n");
}
WaitForSingleObject(hThread, 0);

CloseHandle(hThread);
CloseHandle(hProcess);

system("pause");
printf("%d\r\n", *mem);
system("pause");

return 0;
}

带页内偏移挂页

  1. 拆地址
    80000 => 0000 0000 00 | 00 1000 0000 | 0000 0000 0000
    0000 0000 0000 => 0
    0000 1000 0000 => 080
    0000 0000 0000 => 0
  1. 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
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
49
50
51
52
53
54
55
56
kd> !dd 1611b000        // 通过实验程序获取PDE
#1611b000 2915f867 0c066867 00000000 05cdc867
#1611b010 00000000 00000000 00000000 00000000
#1611b020 00000000 00000000 00000000 00000000
#1611b030 00000000 00000000 00000000 00000000
#1611b040 00000000 00000000 00000000 00000000
#1611b050 00000000 00000000 00000000 00000000
#1611b060 00000000 00000000 00000000 00000000
#1611b070 00000000 00000000 00000000 00000000
kd> !dd 2915f000+080*4 // 获取PTE
#2915f200 06204867 00000000 00000000 00000000
#2915f210 00000000 00000000 00000000 00000000
#2915f220 00000000 00000000 00000000 00000000
#2915f230 00000000 00000000 00000000 00000000
#2915f240 00000000 00000000 00000000 00000000
#2915f250 00000000 00000000 00000000 00000000
#2915f260 00000000 00000000 00000000 00000000
#2915f270 00000000 00000000 00000000 00000000
kd> !dd 06204000 // 查看数据
# 6204000 00000000 00000000 00000000 00000000
# 6204010 00000000 00000000 00000000 00000000
# 6204020 00000000 00000000 00000000 00000000
# 6204030 00000000 00000000 00000000 00000000
# 6204040 00000000 00000000 00000000 00000000
# 6204050 00000000 00000000 00000000 00000000
# 6204060 00000000 00000000 00000000 00000000
# 6204070 00000000 00000000 00000000 00000000
kd> !db 06204000+0x100 // 由于页内偏移为0x100, 所以需要加上0x100
# 6204100 6a 00 6a 00 6a 00 6a 00-b8 b1 ed da 75 ff d0 c3 j.j.j.j.....u...
# 6204110 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204130 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204140 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
# 6204170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
kd> !dd 34cc7000 // 获取notepad.exe的PDE
#34cc7000 09f40867 3af52867 00000000 00000000
#34cc7010 26825867 22be6867 0c4c7867 30d00867
#34cc7020 3d901867 00000000 26fd8867 00000000
#34cc7030 00000000 00000000 00000000 00000000
#34cc7040 00000000 00000000 00000000 00000000
#34cc7050 00000000 00000000 00000000 00000000
#34cc7060 00000000 00000000 00000000 00000000
#34cc7070 00000000 00000000 00000000 00000000
kd> !dd 09f40000 // 获取notepad.exe的PTE
# 9f40000 00000000 00000000 00000000 00000000
# 9f40010 00000000 00000000 00000000 00000000
# 9f40020 00000000 00000000 00000000 00000000
# 9f40030 00000000 00000000 00000000 00000000
# 9f40040 28f16847 00000000 00000000 00000000
# 9f40050 00000000 00000000 00000000 00000000
# 9f40060 00000000 00000000 00000000 00000000
# 9f40070 00000000 00000000 00000000 00000000
kd> !ed 09f40000 06204867 // 将实验程序的PTE挂到notepad.exe的0地址上
kd> g
  1. 实验代码
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
49
50
51
52
53
54
55
56
// 10_16_HangingPage(挂页).cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>

typedef void(__stdcall * FuncProc)();

int main()
{
char * mem = (char*)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
FuncProc func = NULL;

memset(mem, 0, 0x1000);

char bufcode[] =
{
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0x6A, 0, // push 0
0xb8, 0, 0, 0, 0, // mov eax, 0x12345678
0xff, 0xd0, // call eax
0xc3, // ret
};

*(int*)&bufcode[9] = (ULONG)MessageBoxA;
memcpy(mem+0x100, bufcode, sizeof(bufcode));

printf("%x\r\n", mem);
system("pause");

// FuncProc func = (FuncProc)mem;
// func();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 4764);
if (INVALID_HANDLE_VALUE == hProcess)
{
printf("OpenProcess Failed\r\n");
}

HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)0x100, NULL, NULL, NULL);
if (INVALID_HANDLE_VALUE == hThread)
{
printf("CreateRemoteThread Failed\r\n");
}
WaitForSingleObject(hThread, 0);

CloseHandle(hThread);
CloseHandle(hProcess);

system("pause");
printf("%d\r\n", *mem);
system("pause");

return 0;
}

评论