vmquery.c
来自「一本已经绝版的好书」· C语言 代码 · 共 351 行
C
351 行
/************************************************************
Module name: VMQuery.C
Notices: Copyright (c) 1995-1997 Jeffrey Richter
************************************************************/
#include "..\CmnHdr.H" /* See Appendix C. */
#include <windows.h>
#include <windowsx.h>
#include "VMQuery.H"
/////////////////////////////////////////////////////////////
typedef struct {
DWORD dwRgnSize;
DWORD dwRgnStorage; // MEM_*: Free, Image,
// Mapped, Private
DWORD dwRgnBlocks;
DWORD dwRgnGuardBlks; // If > 0, region contains
// thread stack
BOOL fRgnIsAStack; // TRUE if region contains
// thread stack
} VMQUERY_HELP;
// Global-static variable that holds the
// allocation granularity value for this CPU platform. This
// variable is initialized the first time VMQuery is called.
static DWORD gs_dwAllocGran = 0;
/////////////////////////////////////////////////////////////
// When NTBUG_VIRTUALQUERY is defined, the code below
// compensates for a bug in Windows NT's implementation of
// the VirtualQuery function.
#define NTBUG_VIRTUALQUERY
#ifdef NTBUG_VIRTUALQUERY
DWORD NTBug_VirtualQuery (LPVOID lpvAddress,
PMEMORY_BASIC_INFORMATION pmbiBuffer, DWORD cbLength) {
DWORD dwRetVal = VirtualQuery(lpvAddress,
pmbiBuffer, cbLength);
if (dwRetVal == cbLength) {
// If successful, correct the MBI structure's values.
if (((DWORD) pmbiBuffer->AllocationBase % 0x1000)
== 0xFFF) {
// If the AllocationBase member ends with 0xFFF,
// the address is 1 byte off.
pmbiBuffer->AllocationBase = (PVOID)
((PBYTE) pmbiBuffer->AllocationBase + 1);
}
if ((pmbiBuffer->RegionSize % 0x1000) == 0xFFF) {
// If the RegionSize member ends with 0xFFF,
// the size is 1 byte off.
pmbiBuffer->RegionSize++;
}
if ((pmbiBuffer->State != MEM_FREE) &&
(pmbiBuffer->AllocationProtect == 0)) {
// If the region is not free and the
// AllocationProtect member is 0, AllocationProtect
// should be PAGE_READONLY.
pmbiBuffer->AllocationProtect = PAGE_READONLY;
}
}
return(dwRetVal);
}
#define VirtualQuery NTBug_VirtualQuery
#endif
/////////////////////////////////////////////////////////////
// This function iterates through all the blocks in a
// region and initializes a structure with its findings.
static BOOL VMQueryHelp (PVOID pvAddress,
VMQUERY_HELP *pVMQHelp) {
MEMORY_BASIC_INFORMATION MBI;
PVOID pvRgnBaseAddress, pvAddressBlk;
BOOL fOk;
DWORD dwProtectBlock[4] = { 0 };
// 0 = reserved, PAGE_NOACCESS, PAGE_READWRITE
// Zero the contents of the structure.
chINITSTRUCT(*pVMQHelp, FALSE);
// From the passed memory address, obtain the
// base address of the region that contains it.
fOk = (VirtualQuery(pvAddress,
&MBI, sizeof(MBI)) == sizeof(MBI));
if (!fOk) {
// If we can't get any information about the passed
// address, return FALSE, indicating an error.
// GetLastError() will report the actual problem.
return(fOk);
}
// pvRgnBaseAddress identifies the region's
// base address and will never change.
pvRgnBaseAddress = MBI.AllocationBase;
// pvAddress identifies the address of the first block
// and will change as we iterate through the blocks.
pvAddressBlk = pvRgnBaseAddress;
// Save the memory type of the physical storage block.
pVMQHelp->dwRgnStorage = MBI.Type;
for (;;) {
// Get info about the current block.
fOk = VirtualQuery(pvAddressBlk, &MBI, sizeof(MBI));
if (!fOk) {
// Couldn't get the information, end loop.
break;
}
// Check to see whether the block we got info for is
// contained in the requested region.
if (MBI.AllocationBase != pvRgnBaseAddress) {
// Found a block in the next region; end loop.
break;
}
// We have found a block contained
// in the requested region.
// The following if statement is for detecting stacks in
// Windows 95. Windows 95 stacks are in a region wherein
// the last 4 blocks have the following attributes:
// reserved block, PAGE_NOACCESS, PAGE_READWRITE,
// and another reserved block.
if (pVMQHelp->dwRgnBlocks < 4) {
// If this is the 0th through 3rd block, make
// a note of the block's protection in our array.
dwProtectBlock[pVMQHelp->dwRgnBlocks] =
(MBI.State == MEM_RESERVE) ? 0 : MBI.Protect;
} else {
// We have already seen 4 blocks in this region.
// Shift the protection values down in the array.
MoveMemory(&dwProtectBlock[0], &dwProtectBlock[1],
sizeof(dwProtectBlock) - sizeof(DWORD));
// Add the new protection value to the end
// of the array.
dwProtectBlock[3] =
(MBI.State == MEM_RESERVE) ? 0 : MBI.Protect;
}
// Add 1 to the number of blocks in the region.
pVMQHelp->dwRgnBlocks++;
// Add the block's size to the reserved region size.
pVMQHelp->dwRgnSize += MBI.RegionSize;
// If the block has the PAGE_GUARD protection attribute
// flag, add 1 to the number of blocks with this flag.
if (MBI.Protect & PAGE_GUARD) {
pVMQHelp->dwRgnGuardBlks++;
}
// Take a best guess as to the type of physical storage
// committed to the block. This is a guess because some
// blocks can convert from MEM_IMAGE to MEM_PRIVATE or
// from MEM_MAPPED to MEM_PRIVATE; MEM_PRIVATE can
// always be overridden by MEM_IMAGE or MEM_MAPPED.
if (pVMQHelp->dwRgnStorage == MEM_PRIVATE) {
pVMQHelp->dwRgnStorage = MBI.Type;
}
// Get the address of the next block.
pvAddressBlk = (PVOID)
((PBYTE) pvAddressBlk + MBI.RegionSize);
}
// After examining the region, check to see whether it is
// a thread stack.
// Windows NT: Assume a thread stack if the region contains
// at least 1 block with the PAGE_GUARD flag.
// Windows 95: Assume a thread stack if the region contains
// at least 4 blocks wherein the last 4 blocks
// have the following attributes:
// 3rd block from end: reserved
// 2nd block from end: PAGE_NOACCESS
// 1st block from end: PAGE_READWRITE
// block at end: another reserved block.
pVMQHelp->fRgnIsAStack =
(pVMQHelp->dwRgnGuardBlks > 0) ||
((pVMQHelp->dwRgnBlocks >= 4) &&
(dwProtectBlock[0] == 0) &&
(dwProtectBlock[1] == PAGE_NOACCESS) &&
(dwProtectBlock[2] == PAGE_READWRITE) &&
(dwProtectBlock[3] == 0));
// Return that the function completed successfully.
return(TRUE);
}
/////////////////////////////////////////////////////////////
BOOL VMQuery (PVOID pvAddress, PVMQUERY pVMQ) {
MEMORY_BASIC_INFORMATION MBI;
VMQUERY_HELP VMQHelp;
BOOL fOk;
if (gs_dwAllocGran == 0) {
// If this is the very first time a thread in this
// application is calling us, we must obtain the size
// of a page used on this system and save this value
// in a global-static variable.
SYSTEM_INFO SI;
GetSystemInfo(&SI);
gs_dwAllocGran = SI.dwAllocationGranularity;
}
// Zero the contents of the structure.
chINITSTRUCT(*pVMQ, FALSE);
// Get the MEMORY_BASIC_INFORMATION for the passed address.
fOk = VirtualQuery(pvAddress,
&MBI, sizeof(MBI)) == sizeof(MBI);
if (!fOk) {
// If we can't get any information about the passed
// address, return FALSE, indicating an error.
// GetLastError() will report the actual problem.
return(fOk);
}
// The MEMORY_BASIC_INFORMATION structure contains valid
// information. Time to start setting the members
// of our own VMQUERY structure.
// First, fill in the block members. We'll get the
// data for the region containing the block later.
switch (MBI.State) {
case MEM_FREE:
// We have a block of free address space that
// has not been reserved.
pVMQ->pvBlkBaseAddress = NULL;
pVMQ->dwBlkSize = 0;
pVMQ->dwBlkProtection = 0;
pVMQ->dwBlkStorage = MEM_FREE;
break;
case MEM_RESERVE:
// We have a block of reserved address space that
// does NOT have physical storage committed to it.
pVMQ->pvBlkBaseAddress = MBI.BaseAddress;
pVMQ->dwBlkSize = MBI.RegionSize;
// For an uncommitted block, MBI.Protect is invalid.
// So we will show that the reserved block inherits
// the protection attribute of the region in which it
// is contained.
pVMQ->dwBlkProtection = MBI.AllocationProtect;
pVMQ->dwBlkStorage = MEM_RESERVE;
break;
case MEM_COMMIT:
// We have a block of reserved address space that
// DOES have physical storage committed to it.
pVMQ->pvBlkBaseAddress = MBI.BaseAddress;
pVMQ->dwBlkSize = MBI.RegionSize;
pVMQ->dwBlkProtection = MBI.Protect;
pVMQ->dwBlkStorage = MBI.Type;
break;
}
// Second, fill in the region members now that we have
// used the MBI data obtained from the first call to
// VirtualQuery. We might have to call VirtualQuery again
// to obtain complete region information.
switch (MBI.State) {
case MEM_FREE:
// We have a block of address space
// that has not been reserved.
pVMQ->pvRgnBaseAddress = MBI.BaseAddress;
pVMQ->dwRgnProtection = MBI.AllocationProtect;
pVMQ->dwRgnSize = MBI.RegionSize;
pVMQ->dwRgnStorage = MEM_FREE;
pVMQ->dwRgnBlocks = 0;
pVMQ->dwRgnGuardBlks = 0;
pVMQ->fRgnIsAStack = FALSE;
break;
case MEM_RESERVE:
// We have a reserved region that does NOT have
// physical storage committed to it.
pVMQ->pvRgnBaseAddress = MBI.AllocationBase;
pVMQ->dwRgnProtection = MBI.AllocationProtect;
// To get complete information about the region, we
// must iterate through all the region's blocks.
VMQueryHelp(pvAddress, &VMQHelp);
pVMQ->dwRgnSize = VMQHelp.dwRgnSize;
pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
break;
case MEM_COMMIT:
// We have a reserved region that DOES have
// physical storage committed to it.
pVMQ->pvRgnBaseAddress = MBI.AllocationBase;
pVMQ->dwRgnProtection = MBI.AllocationProtect;
// To get complete information on the region, we
// must iterate through all the region's blocks.
VMQueryHelp(pvAddress, &VMQHelp);
pVMQ->dwRgnSize = VMQHelp.dwRgnSize;
pVMQ->dwRgnStorage = VMQHelp.dwRgnStorage;
pVMQ->dwRgnBlocks = VMQHelp.dwRgnBlocks;
pVMQ->dwRgnGuardBlks = VMQHelp.dwRgnGuardBlks;
pVMQ->fRgnIsAStack = VMQHelp.fRgnIsAStack;
break;
}
// Return that the function completed successfully.
return(fOk);
}
//////////////////////// End Of File ////////////////////////
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?