Windows核心编程<读书笔记十四>虚拟内存二 VMQuery程序

来源:互联网 发布:三国志11知乎 编辑:程序博客网 时间:2024/04/28 22:17

【文起】思念亲爱的蟹儿,一直没有忘记自己的梦想,奋斗

程序最后执行的界面如:


思路为:

1、对话框启动时,将系统正在运行的进程名放入下拉菜单中。

所以在OnInitDialog中,调用函数FindProcessRunning

void CVMMapDlg::FindProcessRunning(){BOOL fOk;ToolHelp st_toolhelp;TCHAR szLine[100];//清空Comboxm_pCombox->ResetContent();//创建进程快照,此处调用CToolHelp类,可以参考第四章内容st_toolhelp.CreateSnapshot(TH32CS_SNAPPROCESS,0);PROCESSENTRY32 pe = {sizeof(pe)};for (fOk = st_toolhelp.ProcessFirst(&pe); fOk; fOk = st_toolhelp.ProcessNext(&pe)){_tcscpy(szLine,pe.szExeFile);wsprintf(&szLine[_tcslen(szLine)],_T("   (PID = 0x%08x)"),pe.th32ProcessID);m_pCombox->AddString(szLine);}}

2、当选定一个下拉菜单内容时,我们取出该进程的进程ID,并且调用OnRefresh函数,开始查询该进程的虚拟内存

void CVMMapDlg::OnCbnSelchangeProcess(){// TODO: 在此添加控件通知处理程序代码int nSer;CString cst_process;CString cst_caption = _T("Virtual Memory Map[]");nSer = m_pCombox->GetCurSel();m_pCombox->GetLBText(nSer,cst_process);//取出当前内容CStingToDword(cst_process,&m_dwProcessID);//保存选中进程的进程IDcst_process.Delete(cst_process.Find(' '),cst_process.GetLength());cst_caption.Insert(cst_caption.Find('[') + 1,cst_process);//重新设定对话框captionSetWindowText(cst_caption);//调用函数,开始Query虚拟内存OnRefresh();}

3、在说明核心函数之前,介绍下3个Menu

刷新、显示虚拟内存中块信息、拷贝到剪切板

void CVMMapDlg::OnCopy(){// TODO: 在此添加命令处理程序代码HANDLE hClipData;PTSTR pClipData;int nCount,i;TCHAR szClipData[128 * 1024] = {0};TCHAR szLine[1000] = {0};BOOL fOk;//把信息拷贝到数组中去nCount = m_pList->GetCount();for (i = 0;i < nCount;i++){m_pList->GetText(i,szLine);_tcscat(szClipData,szLine);_tcscat(szClipData,_T("\r\n"));}//打开剪切板并将其清空OpenClipboard();EmptyClipboard();hClipData = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(TCHAR) * (_tcslen(szClipData) + 1));pClipData = (PTSTR)GlobalLock(hClipData);_tcscpy(pClipData,szClipData);//写入剪切板数据#ifdef UNICODEfOk = (hClipData == SetClipboardData(CF_UNICODETEXT,hClipData));#else    fOk = (hClipData == SetClipboardData(CF_TEXT,hClipData));#endifCloseClipboard();if (!fOk){GlobalFree(hClipData);}AfxMessageBox(_T("Copy sucessfully"));}


void CVMMapDlg::OnRefresh(){// TODO: 在此添加命令处理程序代码BOOL fOk = TRUE;PVOID pvAddress = NULL;VMQUERY vMQ;TCHAR szLine[1024] = {0};m_pList->ResetContent();//获取进程句柄HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,m_dwProcessID);if (NULL == hProcess){m_pList->AddString(_T("   "));m_pList->AddString(_T("The process ID identifies a process that is not running"));return;}m_toolhelp.CreateSnapshot(TH32CS_SNAPALL,m_dwProcessID);/************************************************************************1、从地址为0开始Query2、如果返回为TRUE,则写入RgnInfo。再查看是否需要Expand,如果需要,则逐个查询BLK信息************************************************************************/while(fOk){fOk = VMQuery(hProcess,pvAddress,&vMQ);if (fOk){ConstructRgnInfoLine(hProcess,&vMQ,szLine,sizeof(szLine));//自己编写的写入Rgn信息函数m_pList->AddString(szLine);if (m_fExpandRegions){for (DWORD dwBlok = 0;dwBlok < vMQ.dwRgnBlocks;dwBlok++){ConstructBlkInfoLine(hProcess,&vMQ,szLine,sizeof(szLine));//自己编写的写入BLK信息函数m_pList->AddString(szLine);pvAddress = ((PBYTE)pvAddress + vMQ.BlkSize);if (dwBlok < vMQ.dwRgnBlocks - 1){fOk = VMQuery(hProcess,pvAddress,&vMQ);}}}pvAddress = ((PBYTE)vMQ.pvRgnBaseAddress + vMQ.RgnSize);}}CloseHandle(hProcess);}


4、核心函数VMQuery

首先我们定义了一个比MEMORY_BASIC_INFORMATION信息更多的结构

typedef struct{//Region InformationPVOID pvRgnBaseAddress;//虚拟空间的区域地址DWORD dwRgnProtection;//区域空间刚刚被保留时的保护属性SIZE_T RgnSize;       //区域空间的大小DWORD dwRgnStorage;   //该区域空间主要使用的物理存储器的类型DWORD dwRgnBlocks;    //该区域空间包含的地址块的数量DWORD dwRgnGuardBlks; //PAGE_GURARD保护属性打开的块的数量BOOL  fRgnIsAStack;   //是否包含线程堆栈//Block informationPVOID pvBlkBaseAddress; //地址块的基地址DWORD dwBlkProtection;  //地址块的保护属性SIZE_T BlkSize;        //地址块大小DWORD dwBlkStorage;   //地址块的内容}VMQUERY,*PVMQUERY;

BOOL VMQuery(HANDLE hProcess,PVOID pvAddress,PVMQUERY pVMQ){VMQUERY_HELP VMHELP;MEMORY_BASIC_INFORMATION mbi;BOOL fOk;if (0 == gs_dwAllocGran){SYSTEM_INFO sysinfo;GetSystemInfo(&sysinfo);gs_dwAllocGran = sysinfo.dwAllocationGranularity;}ZeroMemory(pVMQ,sizeof(*pVMQ));fOk = (sizeof(mbi) == VirtualQueryEx(hProcess,pvAddress,&mbi,sizeof(mbi)));if (!fOk){return fOk;}//查询Region信息函数,VMHELP也是自己定义的一个结构VMQueryHelp(hProcess,pvAddress,&VMHELP);switch(mbi.State){case MEM_FREE:// 填写Blk信息,FREE状态,BLK值都为空pVMQ->pvBlkBaseAddress = NULL;pVMQ->BlkSize = 0;pVMQ->dwBlkProtection = 0;pVMQ->dwBlkStorage = MEM_FREE;//填写Region信息pVMQ->pvRgnBaseAddress = mbi.BaseAddress;pVMQ->dwRgnProtection = mbi.AllocationProtect;pVMQ->RgnSize = mbi.RegionSize;pVMQ->dwRgnStorage = MEM_FREE;pVMQ->dwRgnBlocks = 0;pVMQ->dwRgnGuardBlks = 0;pVMQ->fRgnIsAStack = FALSE;break;case MEM_RESERVE:// 填写Blk信息pVMQ->pvBlkBaseAddress = mbi.BaseAddress;pVMQ->BlkSize = mbi.RegionSize;pVMQ->dwBlkProtection = mbi.AllocationProtect;pVMQ->dwBlkStorage = MEM_RESERVE;//填写Region信息pVMQ->pvRgnBaseAddress = mbi.AllocationBase;pVMQ->dwRgnProtection = mbi.AllocationProtect;pVMQ->RgnSize = VMHELP.RgnSize;pVMQ->dwRgnStorage = VMHELP.dwRgnStorage;pVMQ->dwRgnBlocks = VMHELP.dwRgnBlocks;pVMQ->dwRgnGuardBlks = VMHELP.dwRgnGuardBlks;pVMQ->fRgnIsAStack = VMHELP.fRgnIsAStack;break;case MEM_COMMIT:// 填写Blk信息pVMQ->pvBlkBaseAddress = mbi.BaseAddress;pVMQ->BlkSize = mbi.RegionSize;pVMQ->dwBlkProtection = mbi.Protect;pVMQ->dwBlkStorage = mbi.Type;//填写Region信息pVMQ->pvRgnBaseAddress = mbi.AllocationBase;pVMQ->dwRgnProtection = mbi.AllocationProtect;pVMQ->RgnSize = VMHELP.RgnSize;pVMQ->dwRgnStorage = VMHELP.dwRgnStorage;pVMQ->dwRgnBlocks = VMHELP.dwRgnBlocks;pVMQ->dwRgnGuardBlks = VMHELP.dwRgnGuardBlks;pVMQ->fRgnIsAStack = VMHELP.fRgnIsAStack;break;default:DebugBreak();break;}return fOk;}

BOOL VMQueryHelp(HANDLE hProcess,PVOID pvAddress,PVMQUERY_HELP pVMQHelp){MEMORY_BASIC_INFORMATION mbi;DWORD dwProtectBlock[4] = {0};BOOL fOk;PVOID pvRgnBaseAddress = NULL;PVOID pvAddressBlk = NULL;if ( NULL == pVMQHelp){return FALSE;}ZeroMemory(pVMQHelp,sizeof(*pVMQHelp));fOk = (sizeof(mbi) == VirtualQueryEx(hProcess,pvAddress,&mbi,sizeof(mbi)));if (!fOk){return fOk;}pvAddressBlk = pvRgnBaseAddress = mbi.AllocationBase;pVMQHelp->dwRgnStorage = mbi.Type;for (;;){//从区域的分配地址开始查找fOk = (sizeof(mbi) == VirtualQueryEx(hProcess,pvAddressBlk,&mbi,sizeof(mbi)));if (!fOk){break;}//是否在同一个Regionif (pvRgnBaseAddress != mbi.AllocationBase){break;}//找到了blk,记录下state,只要保留最后4个即可,//目的是为了后面判断是否进程堆栈准备if (pVMQHelp->dwRgnBlocks < 4){dwProtectBlock[pVMQHelp->dwRgnBlocks] = (MEM_RESERVE == mbi.State) ? 0 :mbi.Protect;}else{MoveMemory(&dwProtectBlock[0],&dwProtectBlock[1],sizeof(dwProtectBlock) - sizeof(DWORD));dwProtectBlock[3] = (MEM_RESERVE == mbi.State) ? 0 :mbi.Protect;}pVMQHelp->dwRgnBlocks++;pVMQHelp->RgnSize += mbi.RegionSize;if (PAGE_GUARD == (mbi.Protect & PAGE_GUARD)){pVMQHelp->dwRgnGuardBlks++;}if (MEM_PRIVATE == pVMQHelp->dwRgnStorage){pVMQHelp->dwRgnStorage = mbi.Type;}pvAddressBlk = (PVOID)((PBYTE)pvAddressBlk + mbi.RegionSize);}//Windows2k:至少有一个保护属性为GUARD的块//Windows9x:至少有个4个块,且最后一个为0,//倒数第二个为RW,倒数第三个为NOACCESS//倒数第四个为0pVMQHelp->fRgnIsAStack = (pVMQHelp->dwRgnGuardBlks > 0) ||((pVMQHelp->dwRgnBlocks > 3) &&(0 == dwProtectBlock[0]) &&(PAGE_NOACCESS == dwProtectBlock[1]) &&(PAGE_READWRITE == dwProtectBlock[2]) &&(0 == dwProtectBlock[3]));return fOk;}
【文尾】如果对您有帮助,请留下对我和蟹儿的祝福。欢迎一起讨论Windows核心编程,第一次看,难免有理解错误和不清楚的地方。

原创粉丝点击