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