1 // We have a block contained in the region.
2
3 // The following if statement is for detecting stacks in Windows 98.
4 // A Windows 98 stack region's last 4 blocks look like this:
5 // reserved block, no access block, read-write block, reserved block
6 //哈今天状态不错
7 //Windows98线程堆栈所在内存区域的的特点是最后4个内存块依次为
8 //reserved、PAGE_NOACCESS、PAGE_READWRITE、reserved
9 //dwProtectBlock这个结构的定义就是为了存储最后4个块的页面保护信息
10 //用来判断正在访问的内存区域是不是符合Windows98下的线程堆栈区域的特点
11 //分两步走看代码吧:
12 //这个就是内存区域中的内存块的个数小于4那么dwProtectBlock分配的空间足以存储和进行判断直接存储就可以了
13 if (pVMQHelp->dwRgnBlocks < 4) {
14 // 0th through 3rd block, remember the block's protection
15 dwProtectBlock[pVMQHelp->dwRgnBlocks] =
16 (mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
17 } else {
18 //如果该内存区域中内存块的个数大于4那么我们上面非配的4个存储位置将无法存储全部的内存区块。
19 //幸运的是我们并不关心全部的内存区块(在判断内存区域是否符合Windows98线程堆栈所在内存区域的特点的时候)
20 //我们只关心内存区域中的最后4个内存块,好了不是最后最后4个内存块的内存块可以移出我们的判断结构数组dwProtectBlock了
21 // We've seen 4 blocks in this region.
22 // Shift the protection values down in the array.
23 MoveMemory(&dwProtectBlock[0], &dwProtectBlock[1],
24 sizeof(dwProtectBlock) - sizeof(DWORD));
25
26 // Add the new protection value to the end of the array.
27 //空闲出一个位置供我们存放当前已知的最后一块内存块
28 //这个过程让我想起了一个故事叫黑瞎子掰棒子不过这头熊有点小猛他能留住4个到最后。
29 dwProtectBlock[3] = (mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
30 }
31 //将已知的区域中的最后一内存块更新到pVMQHelp、
32 //内存块数量+1
33 pVMQHelp->dwRgnBlocks++; // Add another block to the region
34 //这个区域的总大小=当前大小+已知的最后一内存块的大小
35 pVMQHelp->RgnSize += mbi.RegionSize; // Add block's size to region size
36
37 // If block has PAGE_GUARD attribute, add 1 to this counter
38 // 这个Windows2000中判断一个区域是不是线程堆栈所在区域的办法
39 //只要区域中有一个内存块的页面保护属性为PAGE_GUARD那么这个区段就是线程堆栈所在的区块了
40 if ((mbi.Protect & PAGE_GUARD) == PAGE_GUARD)
41 pVMQHelp->dwRgnGuardBlks++;
42
43 // Take a best guess as to the type of physical storage committed to the
44 // block. This is a guess because some blocks can convert from MEM_IMAGE
45 // to MEM_PRIVATE or from MEM_MAPPED to MEM_PRIVATE; MEM_PRIVATE can
46 // always be overridden by MEM_IMAGE or MEM_MAPPED.
47 //一些内存块的保护属性能从MEM_IMAGE变为MEM_PRIVATE或从MEM_MAPPED变为MEM_PRIVATE。
48 //MEM_PRIVATE能被MEM_IMAGE or MEM_MAPPED重写
49 //一个对当前内存区域类型的一个猜测首先要明确的是这是在一个循环内部发生的
50 //也就是说dwRgnStorage肯能不只一次的被置为MEM_PRIVATE但是不要紧我们会坚持下去
51 //用整个区域中所有内存块的页面保护属性来测试直到我们把一个页面类型不为MEM_PRIVATE
52 //的内存块的类型赋给区域内存页面类型为止
53 if (pVMQHelp->dwRgnStorage == MEM_PRIVATE)
54 pVMQHelp->dwRgnStorage = mbi.Type;
55 //获取下一个内存块的地址(这个块可能属于现在的区域也有可能是下一个相邻区域的)
56 // Get the address of the next block.
57 pvAddressBlk = (PVOID) ((PBYTE) pvAddressBlk + mbi.RegionSize);
58 }
59
60 // After examining the region, check to see whether it is a thread stack
61 // Windows 2000: Assume stack if region has at least 1 PAGE_GUARD block
62 // Windows 9x: Assume stack if region has at least 4 blocks with
63 // 3rd block from end: reserved
64 // 2nd block from end: PAGE_NOACCESS
65 // 1st block from end: PAGE_READWRITE
66 // block at end: another reserved block.
67 //现在的情况清晰了只要有一个内存块中页面的保护属性为Guard那么这个内存区域就是线程堆栈所在的区域了
68 //或者在Windows98 系统中需要判断该内存区域中最后4个内存块的页面保护类型。
69 pVMQHelp->fRgnIsAStack =
70 (pVMQHelp->dwRgnGuardBlks > 0) ||
71 ((pVMQHelp->dwRgnBlocks >= 4) &&
72 (dwProtectBlock[0] == 0) &&
73 (dwProtectBlock[1] == PAGE_NOACCESS) &&
74 (dwProtectBlock[2] == PAGE_READWRITE) &&
75 (dwProtectBlock[3] == 0));
76
77 return(TRUE);
78}
79
80
81///////////////////////////////////////////////////////////////////////////////
82
83
84BOOL VMQuery(HANDLE hProcess, LPCVOID pvAddress, PVMQUERY pVMQ) {
85
86 if (gs_dwAllocGran == 0) {
87 // Set allocation granularity if this is the first call
88 SYSTEM_INFO sinf;
89 GetSystemInfo(&sinf);
90 gs_dwAllocGran = sinf.dwAllocationGranularity;
91 }
92
93 ZeroMemory(pVMQ, sizeof(*pVMQ));
94
95 // Get the MEMORY_BASIC_INFORMATION for the passed address.
96 MEMORY_BASIC_INFORMATION mbi;
97 BOOL fOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi))
98 == sizeof(mbi));
99
100 if (!fOk)
101 return(fOk); // Bad memory address, return failure
102
103 // The MEMORY_BASIC_INFORMATION structure contains valid information.
104 // Time to start setting the members of our own VMQUERY structure.
105
106 // First, fill in the block members. We'll fill the region members later.
107 switch (mbi.State) {
108 case MEM_FREE: // Free block (not reserved)
109 pVMQ->pvBlkBaseAddress = NULL;
110 pVMQ->BlkSize = 0;
111 pVMQ->dwBlkProtection = 0;
112 pVMQ->dwBlkStorage = MEM_FREE;
113 break;
114
115 case MEM_RESERVE: // Reserved block without committed storage in it.
116 pVMQ->pvBlkBaseAddress = mbi.BaseAddress;
117 pVMQ->BlkSize = mbi.RegionSize;
118
119 // For an uncommitted block, mbi.Protect is invalid. So we will
120 // show that the reserved block inherits the protection attribute
121 // of the region in which it is contained.
122 pVMQ->dwBlkProtection = mbi.AllocationProtect;
123 pVMQ->dwBlkStorage = MEM_RESERVE;
124 break;
125
126 case MEM_COMMIT: // Reserved block with committed storage in it.
127 pVMQ->pvBlkBaseAddress = mbi.BaseAddress;
128 pVMQ->BlkSize = mbi.RegionSize;
129 pVMQ->dwBlkProtection = mbi.Protect;
130 pVMQ->dwBlkStorage = mbi.Type;
131 break;
132
133 default:
134 DebugBreak();
135 break;
136 }
137
138 // Now fill in the region data members.
139 VMQUERY_HELP VMQHelp;
140 switch (mbi.State) {
141 case MEM_FREE: // Free block (not reserved)
142 pVMQ->pvRgnBaseAddress = mbi.BaseAddress;
143 pVMQ->dwRgnProtection = mbi.AllocationProtect;
144 pVMQ->RgnSize = mbi.RegionSize;
145 pVMQ->dwRgnStorage = MEM_FREE;
146 pVMQ->dwRgnBlocks = 0;
147 pVMQ->dwRgnGuardBlks = 0;
148 pVMQ->fRgnIsAStack = FALSE;
149 break;
150
151 case MEM_RESERVE: // Reserved block without committed storage in it.
152 pVMQ->pvRgnBaseAddress = mbi.AllocationBase;
153 pVMQ->dwRgnProtection = mbi.AllocationProtect;
154
155 // Iterate through all blocks to get complete region information.
156 VMQueryHelp(hProcess, pvAddress, &VMQHelp);
157
158 pVMQ->RgnSize = VMQHelp.RgnSize;
159 pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
160 pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
161 pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
162 pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
163 break;
164
165 case MEM_COMMIT: // Reserved block with committed storage in it.
166 pVMQ->pvRgnBaseAddress = mbi.AllocationBase;
167 pVMQ->dwRgnProtection = mbi.AllocationProtect;
168
169 // Iterate through all blocks to get complete region information.
170 VMQueryHelp(hProcess, pvAddress, &VMQHelp);
171
172 pVMQ->RgnSize = VMQHelp.RgnSize;
173 pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
174 pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
175 pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
176 pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
177 break;
178
179 default:
180 DebugBreak();
181 break;
182 }
183
184 return(fOk);
185}
186
187
188//////////////////////////////// End of File //////////////////////////////////
2
3 // The following if statement is for detecting stacks in Windows 98.
4 // A Windows 98 stack region's last 4 blocks look like this:
5 // reserved block, no access block, read-write block, reserved block
6 //哈今天状态不错
7 //Windows98线程堆栈所在内存区域的的特点是最后4个内存块依次为
8 //reserved、PAGE_NOACCESS、PAGE_READWRITE、reserved
9 //dwProtectBlock这个结构的定义就是为了存储最后4个块的页面保护信息
10 //用来判断正在访问的内存区域是不是符合Windows98下的线程堆栈区域的特点
11 //分两步走看代码吧:
12 //这个就是内存区域中的内存块的个数小于4那么dwProtectBlock分配的空间足以存储和进行判断直接存储就可以了
13 if (pVMQHelp->dwRgnBlocks < 4) {
14 // 0th through 3rd block, remember the block's protection
15 dwProtectBlock[pVMQHelp->dwRgnBlocks] =
16 (mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
17 } else {
18 //如果该内存区域中内存块的个数大于4那么我们上面非配的4个存储位置将无法存储全部的内存区块。
19 //幸运的是我们并不关心全部的内存区块(在判断内存区域是否符合Windows98线程堆栈所在内存区域的特点的时候)
20 //我们只关心内存区域中的最后4个内存块,好了不是最后最后4个内存块的内存块可以移出我们的判断结构数组dwProtectBlock了
21 // We've seen 4 blocks in this region.
22 // Shift the protection values down in the array.
23 MoveMemory(&dwProtectBlock[0], &dwProtectBlock[1],
24 sizeof(dwProtectBlock) - sizeof(DWORD));
25
26 // Add the new protection value to the end of the array.
27 //空闲出一个位置供我们存放当前已知的最后一块内存块
28 //这个过程让我想起了一个故事叫黑瞎子掰棒子不过这头熊有点小猛他能留住4个到最后。
29 dwProtectBlock[3] = (mbi.State == MEM_RESERVE) ? 0 : mbi.Protect;
30 }
31 //将已知的区域中的最后一内存块更新到pVMQHelp、
32 //内存块数量+1
33 pVMQHelp->dwRgnBlocks++; // Add another block to the region
34 //这个区域的总大小=当前大小+已知的最后一内存块的大小
35 pVMQHelp->RgnSize += mbi.RegionSize; // Add block's size to region size
36
37 // If block has PAGE_GUARD attribute, add 1 to this counter
38 // 这个Windows2000中判断一个区域是不是线程堆栈所在区域的办法
39 //只要区域中有一个内存块的页面保护属性为PAGE_GUARD那么这个区段就是线程堆栈所在的区块了
40 if ((mbi.Protect & PAGE_GUARD) == PAGE_GUARD)
41 pVMQHelp->dwRgnGuardBlks++;
42
43 // Take a best guess as to the type of physical storage committed to the
44 // block. This is a guess because some blocks can convert from MEM_IMAGE
45 // to MEM_PRIVATE or from MEM_MAPPED to MEM_PRIVATE; MEM_PRIVATE can
46 // always be overridden by MEM_IMAGE or MEM_MAPPED.
47 //一些内存块的保护属性能从MEM_IMAGE变为MEM_PRIVATE或从MEM_MAPPED变为MEM_PRIVATE。
48 //MEM_PRIVATE能被MEM_IMAGE or MEM_MAPPED重写
49 //一个对当前内存区域类型的一个猜测首先要明确的是这是在一个循环内部发生的
50 //也就是说dwRgnStorage肯能不只一次的被置为MEM_PRIVATE但是不要紧我们会坚持下去
51 //用整个区域中所有内存块的页面保护属性来测试直到我们把一个页面类型不为MEM_PRIVATE
52 //的内存块的类型赋给区域内存页面类型为止
53 if (pVMQHelp->dwRgnStorage == MEM_PRIVATE)
54 pVMQHelp->dwRgnStorage = mbi.Type;
55 //获取下一个内存块的地址(这个块可能属于现在的区域也有可能是下一个相邻区域的)
56 // Get the address of the next block.
57 pvAddressBlk = (PVOID) ((PBYTE) pvAddressBlk + mbi.RegionSize);
58 }
59
60 // After examining the region, check to see whether it is a thread stack
61 // Windows 2000: Assume stack if region has at least 1 PAGE_GUARD block
62 // Windows 9x: Assume stack if region has at least 4 blocks with
63 // 3rd block from end: reserved
64 // 2nd block from end: PAGE_NOACCESS
65 // 1st block from end: PAGE_READWRITE
66 // block at end: another reserved block.
67 //现在的情况清晰了只要有一个内存块中页面的保护属性为Guard那么这个内存区域就是线程堆栈所在的区域了
68 //或者在Windows98 系统中需要判断该内存区域中最后4个内存块的页面保护类型。
69 pVMQHelp->fRgnIsAStack =
70 (pVMQHelp->dwRgnGuardBlks > 0) ||
71 ((pVMQHelp->dwRgnBlocks >= 4) &&
72 (dwProtectBlock[0] == 0) &&
73 (dwProtectBlock[1] == PAGE_NOACCESS) &&
74 (dwProtectBlock[2] == PAGE_READWRITE) &&
75 (dwProtectBlock[3] == 0));
76
77 return(TRUE);
78}
79
80
81///////////////////////////////////////////////////////////////////////////////
82
83
84BOOL VMQuery(HANDLE hProcess, LPCVOID pvAddress, PVMQUERY pVMQ) {
85
86 if (gs_dwAllocGran == 0) {
87 // Set allocation granularity if this is the first call
88 SYSTEM_INFO sinf;
89 GetSystemInfo(&sinf);
90 gs_dwAllocGran = sinf.dwAllocationGranularity;
91 }
92
93 ZeroMemory(pVMQ, sizeof(*pVMQ));
94
95 // Get the MEMORY_BASIC_INFORMATION for the passed address.
96 MEMORY_BASIC_INFORMATION mbi;
97 BOOL fOk = (VirtualQueryEx(hProcess, pvAddress, &mbi, sizeof(mbi))
98 == sizeof(mbi));
99
100 if (!fOk)
101 return(fOk); // Bad memory address, return failure
102
103 // The MEMORY_BASIC_INFORMATION structure contains valid information.
104 // Time to start setting the members of our own VMQUERY structure.
105
106 // First, fill in the block members. We'll fill the region members later.
107 switch (mbi.State) {
108 case MEM_FREE: // Free block (not reserved)
109 pVMQ->pvBlkBaseAddress = NULL;
110 pVMQ->BlkSize = 0;
111 pVMQ->dwBlkProtection = 0;
112 pVMQ->dwBlkStorage = MEM_FREE;
113 break;
114
115 case MEM_RESERVE: // Reserved block without committed storage in it.
116 pVMQ->pvBlkBaseAddress = mbi.BaseAddress;
117 pVMQ->BlkSize = mbi.RegionSize;
118
119 // For an uncommitted block, mbi.Protect is invalid. So we will
120 // show that the reserved block inherits the protection attribute
121 // of the region in which it is contained.
122 pVMQ->dwBlkProtection = mbi.AllocationProtect;
123 pVMQ->dwBlkStorage = MEM_RESERVE;
124 break;
125
126 case MEM_COMMIT: // Reserved block with committed storage in it.
127 pVMQ->pvBlkBaseAddress = mbi.BaseAddress;
128 pVMQ->BlkSize = mbi.RegionSize;
129 pVMQ->dwBlkProtection = mbi.Protect;
130 pVMQ->dwBlkStorage = mbi.Type;
131 break;
132
133 default:
134 DebugBreak();
135 break;
136 }
137
138 // Now fill in the region data members.
139 VMQUERY_HELP VMQHelp;
140 switch (mbi.State) {
141 case MEM_FREE: // Free block (not reserved)
142 pVMQ->pvRgnBaseAddress = mbi.BaseAddress;
143 pVMQ->dwRgnProtection = mbi.AllocationProtect;
144 pVMQ->RgnSize = mbi.RegionSize;
145 pVMQ->dwRgnStorage = MEM_FREE;
146 pVMQ->dwRgnBlocks = 0;
147 pVMQ->dwRgnGuardBlks = 0;
148 pVMQ->fRgnIsAStack = FALSE;
149 break;
150
151 case MEM_RESERVE: // Reserved block without committed storage in it.
152 pVMQ->pvRgnBaseAddress = mbi.AllocationBase;
153 pVMQ->dwRgnProtection = mbi.AllocationProtect;
154
155 // Iterate through all blocks to get complete region information.
156 VMQueryHelp(hProcess, pvAddress, &VMQHelp);
157
158 pVMQ->RgnSize = VMQHelp.RgnSize;
159 pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
160 pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
161 pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
162 pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
163 break;
164
165 case MEM_COMMIT: // Reserved block with committed storage in it.
166 pVMQ->pvRgnBaseAddress = mbi.AllocationBase;
167 pVMQ->dwRgnProtection = mbi.AllocationProtect;
168
169 // Iterate through all blocks to get complete region information.
170 VMQueryHelp(hProcess, pvAddress, &VMQHelp);
171
172 pVMQ->RgnSize = VMQHelp.RgnSize;
173 pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
174 pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
175 pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
176 pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
177 break;
178
179 default:
180 DebugBreak();
181 break;
182 }
183
184 return(fOk);
185}
186
187
188//////////////////////////////// End of File //////////////////////////////////