虚拟内存遍历 VMView

来源:互联网 发布:苹果手机安装不了淘宝 编辑:程序博客网 时间:2024/04/30 08:57

本代码由15PB创始人A1Pass原创,网络资源稀少,转载请注明出处,尊重作者劳动成果!


VMQuery.h:

#pragma once#include <windows.h>#include <vector>using std::vector;typedef struct _VMQUERYEX{    int    nRgnSize;       // 预定区域大小    DWORD  dwRgnStorage;   // 预划分区域的物理存储器类型(MEM_*: Free, Image, Mapped, Private)    DWORD  dwRgnBlocks;    // 区域中块的数量    DWORD  dwRgnGuardBlks; // 具有PAGE_GUARD保护属性的块的数量,如果>0,则此区域是为线程栈而预定的    BOOL   bRgnIsAStack;   // 此区域是否包含线程栈,是的话则此区域是为线程栈而预定的}VMQUERYEX;typedef struct _VMQUERY{    // 区域信息    PVOID  lpRgnBaseAddress; // 预划分内存区域的起始地址    DWORD  dwRgnProtection;  // 预划分此内存区域时的原始保护属性(PAGE_*)    int    nRgnSize;         // 预划分区域大小    DWORD  dwRgnStorage;     // 预划分区域的物理存储器类型(MEM_*: Free, Image, Mapped, Private)    DWORD  dwRgnBlocks;      // 预划分区域中块的数量    DWORD  dwRgnGuardBlks;   // 具有PAGE_GUARD保护属性的块的数量,如果>0,则此区域是为线程栈而预定的    BOOL   bRgnIsAStack;     // 此区域是否包含线程栈,是的话则此区域是为线程栈而预定的    // 块信息    PVOID  lpBlkBaseAddress; // 内存块的起始地址    DWORD  dwBlkProtection;  // 内存块的保护属性(PAGE_*)    int    nBlkSize;         // 内存块的大小    DWORD  dwBlkStorage;     // 内存块的存储类型(MEM_*: Free, Reserve, Image, Mapped, Private)    // 文本信息    BOOL   bIsExpandInfo;        // 此条信息是否为区域展开后的块信息    WCHAR  szRgnBaseAddress[16]; // [文本]预划分内存区域的起始地址    WCHAR  szRgnProtection[16];  // [文本]原始保护属性    WCHAR  szRgnSize[16];        // [文本]区域大小    WCHAR  szRgnStorage[16];     // [文本]物理存储器类型    WCHAR  szRgnBlocks[8];       // [文本]块的数量    WCHAR  szRgnGuardBlks[8];    // [文本]具有PAGE_GUARD保护属性的块的数量    WCHAR  szBlkBaseAddress[10]; // [文本]内存块的起始地址    WCHAR  szBlkProtection[16];  // [文本]内存块的保护属性    WCHAR  szBlkSize[16];        // [文本]内存块的大小    WCHAR  szBlkStorage[16];     // [文本]内存块的存储类型} VMQUERY, *PVMQUERY;class CVMQuery{public:    CVMQuery();    ~CVMQuery();public:    BOOL GetVMInfo(HANDLE hProcess, LPCVOID lpAddress, PVMQUERY pVMQ);protected:    BOOL GetVMBlockInfo(HANDLE hProcess, LPCVOID lpAddress, VMQUERYEX *pVMBlock);    void GetProtectText(DWORD dwProtect, PTSTR szBuf, int nSize, BOOL bShowFlags);    void GetMemStorageText(DWORD dwStorage, PTSTR szBuf, int nSize);private:    vector<VMQUERY> m_vecVMInfoList;};


VMQuery.cpp:

#include "stdafx.h"#include "VMQuery.h"#include <Strsafe.h>CVMQuery::CVMQuery(){}CVMQuery::~CVMQuery(){}void CVMQuery::GetProtectText(DWORD dwProtect, PTSTR szBuf, int nSize, BOOL bShowFlags){    PCTSTR p = L"[Unknown]";    switch ( dwProtect & ~(PAGE_GUARD|PAGE_NOCACHE|PAGE_WRITECOMBINE) )    {    case PAGE_READONLY:          p = L"[ -R--  ]"; break;    case PAGE_READWRITE:         p = L"[ -RW-  ]"; break;    case PAGE_WRITECOPY:         p = L"[ -RWC  ]"; break;    case PAGE_EXECUTE:           p = L"[ E---  ]"; break;    case PAGE_EXECUTE_READ:      p = L"[ ER--  ]"; break;    case PAGE_EXECUTE_READWRITE: p = L"[ ERW-  ]"; break;    case PAGE_EXECUTE_WRITECOPY: p = L"[ ERWC  ]"; break;    case PAGE_NOACCESS:          p = L"[ ----  ]"; break;    }    StringCchCopy(szBuf, nSize, p);    if (bShowFlags)    {        StringCchCat(szBuf, nSize, L" ");        StringCchCat(szBuf, nSize, (dwProtect&PAGE_GUARD) ? L"G":L"-");        StringCchCat(szBuf, nSize, (dwProtect&PAGE_NOCACHE) ? L"N":L"-");        StringCchCat(szBuf, nSize, (dwProtect&PAGE_WRITECOMBINE) ? L"W":L"-");    }}void CVMQuery::GetMemStorageText(DWORD dwStorage, PTSTR szBuf, int nSize){    PCTSTR p = L"Unknown";    switch (dwStorage)    {    case MEM_FREE:    p = L"Free   "; break; // 闲置:未被预订的区域    case MEM_RESERVE: p = L"Reserve"; break; // 预订:已预订区域    case MEM_IMAGE:   p = L"Image  "; break; // 映像:保存执行映像    case MEM_MAPPED:  p = L"Mapped "; break; // 映射:文件映射区域    case MEM_PRIVATE: p = L"Private"; break; // 私有:数据保存在页交换文件中的区域    }    StringCchCopy(szBuf, nSize, p);}// 将区域内的块信息保存到VMQUERY_HELP中BOOL CVMQuery::GetVMBlockInfo(HANDLE hProcess, LPCVOID lpAddress, VMQUERYEX *pVMBlock){    ZeroMemory(pVMBlock, sizeof(*pVMBlock));    // 1. 获取地址空间中内存地址信息,并将其保存到 MEMORY_BASIC_INFORMATION 结构体中    MEMORY_BASIC_INFORMATION mbiRgn;    if ( !( VirtualQueryEx(hProcess,lpAddress,&mbiRgn,sizeof(mbiRgn)) == sizeof(mbiRgn) ) )        return false; // 错误的内存地址    // 2. 保存基地址与第一个内存块的基址    PVOID pvRgnBaseAddress = mbiRgn.AllocationBase; // 预划分内存区域基址    PVOID pvAddressBlk     = mbiRgn.AllocationBase; // 第一个内存块的基址    // 3. 循环遍历此区域内的内存块,并统计其个数及总大小    MEMORY_BASIC_INFORMATION mbiBlk;    while (true)    {        // 3.1 获取内存块的相关信息        if ( !( VirtualQueryEx(hProcess,pvAddressBlk,&mbiBlk,sizeof(mbiBlk)) == sizeof(mbiBlk) ) )            break;        // 3.2 判断是否需要结束循环,如果此数据块的基址仍等于此内存区域的基址,则代        //     表此数据块是属于此区域内的(继续循环),否则则代表此内存块是其他内存        //     区域的(结束循环)        // 注1:使用MEM_RESERVE方式调用VirtualAlloc即可预定内存区域        // 注2:使用MEM_COMMIT方式调用VirtualAlloc即可分配内存块        if (mbiBlk.AllocationBase != pvRgnBaseAddress)            break;        // 3.3 累加此预划分内存区域内的内存块数量 、预划分域的总大小与具有PAGE_GUARD        //     保护属性的块的数量        pVMBlock->dwRgnBlocks++;                 // 内存块数量加1        pVMBlock->nRgnSize += mbiBlk.RegionSize; // 将此内存块的体积纳入到此内存区域中        if ( (mbiBlk.Protect&PAGE_GUARD)==PAGE_GUARD )             pVMBlock->dwRgnGuardBlks++;      // 统具有PAGE_GUARD保护属性的块的数量        // 3.4 保存此内存块的理存储器类型        // 注1:由于内存块可以从MEM_IMAGE转换到MEM_PRIVATE,或从MEM_MAPPED转换到        //      MEM_PRIVATE,也就是说如果预划分内存区域如果为MEM_PRIVATE的话,那么此        //      内存区域的数据块就可以是任意的内存类型,我们就可以认为在这里取到的内        //      存块的类型信息是有效的,当然,这一切都只是一种合理的猜测,实际上内存        //      块在实际使用时完全有可能并非是我们获取到的类型        if ( MEM_PRIVATE == mbiRgn.Type )            pVMBlock->dwRgnStorage = mbiBlk.Type;        // 3.5 获取下一个内存块的基址        pvAddressBlk = (PVOID)((PBYTE)pvAddressBlk+mbiBlk.RegionSize);    }    // 设置栈标志位    // 注1:具有PAGE_GUARD保护属性的块的数量大于0,则此区域是为线程栈而预定的    pVMBlock->bRgnIsAStack = (pVMBlock->dwRgnGuardBlks > 0);    return(TRUE);}BOOL CVMQuery::GetVMInfo(HANDLE hProcess, LPCVOID lpAddress, PVMQUERY pVMQ){    // 1. 清空结构体    ZeroMemory(pVMQ, sizeof(*pVMQ));    // 2. 获取地址空间中内存地址信息,并将其保存到 MEMORY_BASIC_INFORMATION 结构体中    MEMORY_BASIC_INFORMATION mbi;    if ( !( VirtualQueryEx(hProcess,lpAddress,&mbi,sizeof(mbi)) == sizeof(mbi) ) )        return false;    // 3. 填写区域成员信息    VMQUERYEX VMQHelp;    switch (mbi.State) {    case MEM_FREE:     /** 空闲块(不保留) **********************************/        pVMQ->lpRgnBaseAddress = mbi.BaseAddress;        // 由于空闲块的mbi.Protect是无效的,因此这里将使用此内存块分配时的保护属性        pVMQ->dwRgnProtection  = mbi.AllocationProtect;        pVMQ->nRgnSize         = mbi.RegionSize;        pVMQ->dwRgnStorage     = MEM_FREE;        pVMQ->dwRgnBlocks      = 0;        pVMQ->dwRgnGuardBlks   = 0;        pVMQ->bRgnIsAStack     = FALSE;        break;    case MEM_RESERVE:  /** 在虚拟内存中保留虚拟地址,但并不分配实际物理内存 **/        pVMQ->lpRgnBaseAddress = mbi.AllocationBase;        // 由于未提交块的mbi.Protect是无效的,因此这里将使用此内存块分配时的保护属性        pVMQ->dwRgnProtection  = mbi.AllocationProtect;        // 迭代获取所有块的详细信息                GetVMBlockInfo(hProcess, lpAddress, &VMQHelp);        pVMQ->nRgnSize         = VMQHelp.nRgnSize;        pVMQ->dwRgnStorage     = VMQHelp.dwRgnStorage;        pVMQ->dwRgnBlocks      = VMQHelp.dwRgnBlocks;        pVMQ->dwRgnGuardBlks   = VMQHelp.dwRgnGuardBlks;        pVMQ->bRgnIsAStack     = VMQHelp.bRgnIsAStack;        break;    case MEM_COMMIT:   /** 保留且分配物理地址 ********************************/        pVMQ->lpRgnBaseAddress = mbi.AllocationBase;        pVMQ->dwRgnProtection  = mbi.AllocationProtect;        // 迭代获取所有块的详细信息                  GetVMBlockInfo(hProcess, lpAddress, &VMQHelp);        pVMQ->nRgnSize         = VMQHelp.nRgnSize;        pVMQ->dwRgnStorage     = VMQHelp.dwRgnStorage;        pVMQ->dwRgnBlocks      = VMQHelp.dwRgnBlocks;        pVMQ->dwRgnGuardBlks   = VMQHelp.dwRgnGuardBlks;        pVMQ->bRgnIsAStack     = VMQHelp.bRgnIsAStack;        break;    default:        DebugBreak();        break;    }    // 4. 解析为文本信息    GetProtectText(pVMQ->dwRgnProtection, pVMQ->szRgnProtection, _countof(pVMQ->szRgnProtection), true);    GetMemStorageText(pVMQ->dwRgnStorage, pVMQ->szRgnStorage, _countof(pVMQ->szRgnStorage));    StringCchPrintf(pVMQ->szRgnBaseAddress,_countof(pVMQ->szRgnBaseAddress), L"0x%08x", pVMQ->lpRgnBaseAddress );    StringCchPrintf(pVMQ->szRgnSize,       _countof(pVMQ->szRgnSize),        L"%10d",   pVMQ->nRgnSize );    StringCchPrintf(pVMQ->szRgnBlocks,     _countof(pVMQ->szRgnBlocks),      L"%3d",    pVMQ->dwRgnBlocks );    return true;}


VMView.cpp:

// VMView.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "VMQuery.h"bool ShowVM(DWORD dwProcessId){    CVMQuery objVM;    HANDLE   hProcess  = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);    PVOID    lpAddress = NULL;    VMQUERY  stcVMQ    = {0};    while ( objVM.GetVMInfo(hProcess, lpAddress, &stcVMQ) )    {        wprintf(L"%s %s %s %s %s\n",            stcVMQ.szRgnBaseAddress,            stcVMQ.szRgnStorage,            stcVMQ.szRgnSize,            stcVMQ.szRgnBlocks,            stcVMQ.szRgnProtection);        lpAddress = ((PBYTE)stcVMQ.lpRgnBaseAddress + stcVMQ.nRgnSize);        ZeroMemory(&stcVMQ,sizeof(VMQUERY));    }    CloseHandle(hProcess);    return true;}int _tmain(int argc, _TCHAR* argv[]){    ShowVM( GetCurrentProcessId() );    system("pause");    return 0;}


这段代码没获取块内信息  只获取了块的大小和数量(需要自己拓展获取块信息)


0 0
原创粉丝点击