Windows内存管理

简述windows内存管理

windows进程空间划分

分区 x86 32位Windows
空指针赋值区 0x00000000 - 0x0000FFFF
用户模式区 0x00010000 - 0x7FFEFFFF
64KB禁入区 0x7FFF0000 - 0x7FFFFFFF
内核 0x80000000 - 0xFFFFFFFF

首先有个问题,我们都知道用户态空间中存放着用户私有数据代码还有dll,那每当我们需要分配空间时,例如调用virtualalloc函数,操作系统是如何找到一块未被使用的内存呢?

所以说每个进程中都存在一个结构体记录了用户态地址分配情况(内核态基本相同)

VAD

VAD组织成一个AVL自平衡二叉树。

位于eprocess处

image-20200827214645231

image-20200827215302271

查看一波结构

1
2
3
4
5
6
7
8
9
10
11
nt!_MMVAD					
+0x000 StartingVpn //线性地址开始位置(页为单位)
+0x004 EndingVpn //线性地址结束位置(页为单位)
+0x008 Parent //父节点
+0x00c LeftChild //左子树
+0x010 RightChild //右子树
+0x014 u
+0x018 ControlArea
+0x01c FirstPrototypePte
+0x020 LastContiguousPte
+0x024 u2

前俩个成员表示了线性地址开始与结束地址,单位是页,所以乘上0x1000

parent是父节点,因为这是根节点所以是null

u表示了这段内存的属性

image-20200827215516571

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kd> dt _MMVAD_FLAGS
nt!_MMVAD_FLAGS
+0x000 CommitCharge
+0x000 PhysicalMapping
+0x000 ImageMap
//1 镜像文件 0 其他
+0x000 UserPhysicalPages
+0x000 NoChange
+0x000 WriteWatch
+0x000 Protection
//1 READONLY 2 EXECUTE 3 EXECUTE _READ 4 READWITER
//5 WRITECOPY 6 EXECUTE _READWITER 7 EXECUTE_WRITECOPY
+0x000 LargePages
+0x000 MemCommit
+0x000 PrivateMemory
//1 PrivateMemory 2 Map
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
kd> !vad 0x89986468 
VAD Level Start End Commit
8953a9b8 3 10 10 1 Private READWRITE
899b56f0 2 20 20 1 Private READWRITE
899b55b0 5 30 3f 6 Private READWRITE
89521148 4 40 7f 18 Private READWRITE
89984880 3 80 82 0 Mapped READONLY Pagefile section, shared commit 0x3
895191d0 4 90 91 0 Mapped READONLY Pagefile section, shared commit 0x2
89a63878 1 a0 19f 21 Private READWRITE
8997f0a8 4 1a0 1af 6 Private READWRITE
899b5a00 3 1b0 1bf 0 Mapped READWRITE Pagefile section, shared commit 0x3
8952c0a8 4 1c0 1d5 0 Mapped READONLY \WINDOWS\system32\unicode.nls
899b1870 2 1e0 220 0 Mapped READONLY \WINDOWS\system32\locale.nls
899b57f0 4 230 270 0 Mapped READONLY \WINDOWS\system32\sortkey.nls
8997def0 3 280 285 0 Mapped READONLY \WINDOWS\system32\sorttbls.nls
89986468 0 290 2d0 0 Mapped READONLY Pagefile section, shared commit 0x41
89527cc0 5 2e0 3a7 0 Mapped EXECUTE_READ Pagefile section, shared commit 0x4
8997c3f8 6 3b0 3bf 8 Private READWRITE
8956ac58 7 3c0 3c0 1 Private READWRITE
895232a8 8 3d0 3d0 1 Private READWRITE
895211c8 10 3e0 3e1 0 Mapped READONLY Pagefile section, shared commit 0x2
8953a6e0 9 3f0 3f1 0 Mapped READONLY Pagefile section, shared commit 0x2
89c551b0 10 400 40f 3 Private READWRITE
89522b08 4 410 41f 8 Private READWRITE
89519150 3 420 42f 4 Private READWRITE
899798c8 4 430 432 0 Mapped READONLY \WINDOWS\system32\ctype.nls
8954b718 2 440 47f 3 Private READWRITE
8996f178 5 480 582 0 Mapped READONLY Pagefile section, shared commit 0x103
8996f218 4 590 88f 0 Mapped EXECUTE_READ Pagefile section, shared commit 0x22
89b09108 3 890 90f 1 Private READWRITE
89520ae8 5 910 95f 0 Mapped READONLY Pagefile section, shared commit 0x50
89520b18 4 960 960 0 Mapped READWRITE Pagefile section, shared commit 0x1
89981558 6 970 9af 0 Mapped READWRITE Pagefile section, shared commit 0x10
899b5630 5 9b0 9bd 0 Mapped READWRITE Pagefile section, shared commit 0xe
899ad850 7 9c0 abf 123 Private READWRITE
899b5a30 6 ad0 b4f 0 Mapped READWRITE Pagefile section, shared commit 0x7
89546d90 7 b50 bcf 0 Mapped READWRITE Pagefile section, shared commit 0x2
899ba9e0 1 1000 1012 3 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\notepad.exe
89527d30 7 58fb0 59179 9 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\AppPatch\AcGenral.dll
89519c60 8 5adc0 5adf6 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\uxtheme.dll
89527c90 6 5cc30 5cc55 20 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\shimeng.dll
8953a6b0 7 62c20 62c28 1 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\lpk.dll
89522ad8 5 72f70 72f95 3 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\winspool.drv
899b5660 8 73640 7366d 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\MSCTFIME.IME
899b5970 7 73fa0 7400a 16 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\usp10.dll
89518648 8 74680 746cb 3 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\MSCTF.dll
895198f8 6 759d0 75a7e 3 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\userenv.dll
89979c40 7 76300 7631c 1 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\imm32.dll
89a65c70 4 76320 76366 4 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\comdlg32.dll
899adb98 8 76990 76acc 8 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\ole32.dll
899ad7e0 7 76b10 76b39 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\winmm.dll
899adbc8 8 770f0 7717a 4 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\oleaut32.dll
899b6b38 6 77180 77282 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll
899add30 8 77bb0 77bc4 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\msacm32.dll
895180a8 9 77bd0 77bd7 1 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\version.dll
89b08508 7 77be0 77c37 7 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\msvcrt.dll
895232e8 8 77d10 77d9f 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\user32.dll
8996f148 5 77da0 77e48 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\advapi32.dll
899b5690 6 77e50 77ee1 1 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\rpcrt4.dll
89b084d8 8 77ef0 77f38 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\gdi32.dll
89b08478 9 77f40 77fb5 2 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\shlwapi.dll
899b5710 7 77fc0 77fd0 1 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\secur32.dll
899b5a90 3 7c800 7c91d 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\kernel32.dll
899848b0 2 7c920 7c9b2 5 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\ntdll.dll
899b58e0 5 7d590 7dd83 30 Mapped Exe EXECUTE_WRITECOPY \WINDOWS\system32\shell32.dll
899b57c0 4 7f6f0 7f7ef 0 Mapped EXECUTE_READ Pagefile section, shared commit 0x6
89984850 3 7ffa0 7ffd2 0 Mapped READONLY Pagefile section, shared commit 0x33
89983180 4 7ffd4 7ffd4 1 Private READWRITE
899ad870 5 7ffdf 7ffdf 1 Private READWRITE

用!vad指令来查看一波notepad的vad树

89986468 0 290 2d0 0 Mapped READONLY Pagefile section, shared commit 0x41

以这个为例之前看到PrivateMemory为0所以是map

Protection是1所以是READONLY

ImageMap是0所以非镜像文件

!vad这个指令其实就是方便寻找,如何实现也显而易见

windows线性地址管理

windows有俩种申请内存的方式

1.通过VirtualAlloc/VirtualAllocEx申请 Private Memory

2.通过CreateFileMapping映射 Mapped Memory

Private Memory

1
2
3
4
5
6
LPVOID VirtualAlloc{
LPVOID lpAddress, // 要分配的内存区域的地址
DWORD dwSize, // 分配的大小
DWORD flAllocationType, // 分配的类型
DWORD flProtect // 该内存的初始保护属性
};

可能有人会疑惑像malloc这种函数也是申请内存,为什么不在里面。

进程初始化的时候操作系统会用VirtualAlloc/VirtualAllocEx申请一块堆块,malloc只是从那块申请的堆块中拿出一小份

这些知识打过pwn的同学都知道

Mapped Memory

mapped memory主分俩种,共享内存和共享文件

共享内存

也就是映射在同一个物理页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>
#define MapFileName "共享内存"

int main()
{
//内核对象:1、物理页 2、文件
HANDLE g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUFSIZ, (LPCWCHAR)MapFileName);

//将物理页与线性地址进行映射
LPTSTR g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);
*(PDWORD)g_lpBuff = 0x12345678;
printf("%p", g_lpBuff);
return 0;
}

当其他进程需要该内存时用OpenFileMapping即可,MapFileName就是其参数

和之前内核对象的学习很像

共享文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <stdlib.h>

int main()
{
HANDLE g_hFile = CreateFile((LPCWSTR)"NOTEPAD.EXE", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE g_hMapFile = CreateFileMapping(g_hFile, NULL, PAGE_READWRITE, 0, BUFSIZ, NULL);
LPTSTR g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZ);
*(PDWORD)g_lpBuff = 0x12345678;
return 0;
}

共享文件和共享内存区别就在于一个获取句柄,CreateFileMapping时传入即可,这是会给改文件分配一个物理页,但是还不会建立与线性地址的映射关系,到MapViewOfFile时才会建立

镜像文件

说白了就是LoadLibrary

用LoadLibrary加载的都会有写拷贝属性,这样就不会因为修改而影响到其他文件

写拷贝

像一般dll都是多进程共享一个物理页面,如果其中一个进程hook了dll,所有进程都会被影响,所以需要写拷贝

image-20200905120631895

绕过写拷贝只需要把pte的rw位置1,这样就不会触发异常

物理内存管理

因为windows操作系统的限制,xp只能支持4gb内存,即使是29912分页

image-20200905121508613

但是服务器版本就没有限制可以识别到64gb

每个物理页都对应一个结构体

1
2
3
4
5
6
7
nt!_MMPFN
+0x000 u1 : __unnamed
+0x004 PteAddress : Ptr32 _MMPTE
+0x008 u2 : __unnamed
+0x00c u3 : __unnamed
+0x010 OriginalPte : _MMPTE
+0x018 u4 : __unnamed

3、物理页状态
0:MmZeroedPageListHead 零化链表(是系统在空闲的时候进行零化的,不是程序自己清零的那种)
1:MmFreePageListHead 空闲链表(物理页是周转使用的,刚被释放的物理页是没有清0,系统空闲的时候有专门的线程从这个队列摘取物理页,加以清0后再挂入MmZeroedPageListHead)
2:MmStandbyPageListHead 备用链表(当系统内存不够的时候,操作系统会把物理内存中的数据交换到硬盘上,此时页面不是直接挂到空闲链表上去,而是挂到备用链表上,虽然我释放了,但里边的内容还是有意义的)
3:MmModifiedPageListHead
4:MmModifiedNoWritePageListHead
5:MmBadPageListHead 坏链

image-20200905121712705


Windows内存管理
http://www.psbazx.com/2020/08/28/Windows内存管理/
Beitragsautor
皮三宝
Veröffentlicht am
August 27, 2020
Urheberrechtshinweis