以前介绍过 VMMap 工具是可以查看一个进程中的虚拟内存信息的,其内部的实现原理就是调用 VirtualQueryEx 函数(支持查看其他进程)得到一个进程的虚拟内存信息。根据学习的视频我也自己实现了一下,但我们用到的是 VirtualQuery 来查看自身进程的内容。

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <atlstr.h>

CString FormatMemInfo(MEMORY_BASIC_INFORMATION &mi)
{
CString strAllocProtect;
if (mi.AllocationProtect & PAGE_NOACCESS) // 0x0001
{
strAllocProtect = _T("N ");
}
if (mi.AllocationProtect & PAGE_READONLY) // 0x0002
{
strAllocProtect = _T("R ");
}
else if (mi.AllocationProtect & PAGE_READWRITE) // 0x0004
{
strAllocProtect = _T("RW ");
}
else if (mi.AllocationProtect & PAGE_WRITECOPY) // 0x0008
{
strAllocProtect = _T("WC ");
}
else if (mi.AllocationProtect & PAGE_EXECUTE) // 0x0010
{
strAllocProtect = _T("E ");
}
else if (mi.AllocationProtect & PAGE_EXECUTE_READ) // 0x0020
{
strAllocProtect = _T("ER ");
}
else if (mi.AllocationProtect & PAGE_EXECUTE_READWRITE) // 0x0040
{
strAllocProtect = _T("ERW");
}
else if (mi.AllocationProtect & PAGE_EXECUTE_WRITECOPY) // 0x0080
{
strAllocProtect = _T("EWC");
}
if (mi.AllocationProtect & PAGE_GUARD) // 0x0100
{
strAllocProtect += _T("+Guard");
}
if (mi.AllocationProtect & PAGE_NOCACHE) // 0x0200
{
strAllocProtect += _T("+NoCache");
}
CString strState;
if (mi.State == MEM_COMMIT)
{
strState = _T("Commit ");
}
else if (mi.State == MEM_FREE)
{
strState = _T("Free ");
}
else if (mi.State == MEM_RESERVE)
{
strState = _T("Reserve");
}
else
{
strState = _T("Damned ");
}
CString strProtect;
if (mi.Protect & PAGE_NOACCESS)
{
strProtect = _T("N ");
}
else if (mi.Protect & PAGE_READONLY)
{
strProtect = _T("R ");
}
else if (mi.Protect & PAGE_READWRITE)
{
strProtect = _T("RW ");
}
else if (mi.Protect & PAGE_WRITECOPY)
{
strProtect = _T("WC ");
}
else if (mi.Protect & PAGE_EXECUTE)
{
strProtect = _T("E ");
}
else if (mi.Protect & PAGE_EXECUTE_READ)
{
strProtect = _T("ER ");
}
else if (mi.Protect & PAGE_EXECUTE_READWRITE)
{
strProtect = _T("ERW");
}
else if (mi.Protect & PAGE_EXECUTE_WRITECOPY)
{
strProtect = _T("EWC");
}
else if (mi.Protect & PAGE_GUARD)
{
strProtect += _T("+Guard");
}
else if (mi.Protect & PAGE_NOCACHE)
{
strProtect += _T("+NoCache");
}

CString strType;
if (mi.Type == MEM_IMAGE)
{
strType = _T("Image ");
}
else if (mi.Type == MEM_MAPPED)
{
strType = _T("Mapped ");
}
else if (mi.Type == MEM_PRIVATE)
{
strType = _T("Private");
}
else
{
strType = _T("- ");
}

CString strRet;
strRet.Format(_T("%8X %8X %8X %10uKB %12s %7s %8s %7s"), mi.BaseAddress, mi.AllocationBase
, (DWORD)mi.AllocationBase + (DWORD)mi.RegionSize
, (DWORD)mi.RegionSize / 1024
, strAllocProtect, strState, strProtect, strType);

return strRet;
}

int _tmain()
{
SYSTEM_INFO info;
GetSystemInfo(&info);

// 用户进程空间的最低地址和最高地址(跳过了64K的NULL区)
VOID* pLowerBound = (VOID*)info.lpMinimumApplicationAddress;
VOID* pUpperBound = (VOID*)info.lpMaximumApplicationAddress;

MEMORY_BASIC_INFORMATION mi;
VOID* pPtr = pLowerBound;
VOID* pOldPtr = pPtr;

_putts(_T("BaseAddress AllocBase EndAddress SIZE AllocProtect State CurProtect TYPE"));

// 不超过最高地址就一直循环
while (pPtr <= pUpperBound)
{
// 查询存放到 mi 结构体中
if (VirtualQuery((void*)pPtr, &mi, sizeof(mi)) == 0)
{
break;
}

// 打印信息
_putts(FormatMemInfo(mi));

// 记录本次指针指向
pOldPtr = pPtr;
// 让指针向后移,BaseAddress是本次的基础地址,RegionSize是本次的内存块大小
pPtr = (BYTE*)mi.BaseAddress + mi.RegionSize;

// 判断移动后的是不是和移动前相等
if (pPtr <= pOldPtr)
{
printf("mi.BaseAddress = %X, mi.RegionSize = %X\n",
mi.BaseAddress, mi.RegionSize);
break;
}
}

_tsystem(_T("pause"));
return 0;
}