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

文章目录
  1. 1. windows进程空间划分
    1. 1.1. VAD
  2. 2. windows线性地址管理
    1. 2.1. Private Memory
    2. 2.2. Mapped Memory
      1. 2.2.1. 共享内存
      2. 2.2.2. 共享文件
      3. 2.2.3. 镜像文件
        1. 2.2.3.1. 写拷贝
  3. 3. 物理内存管理
|