查看虚拟内存信息

以前介绍过 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;
}

发表评论