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

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

程序最后执行的界面如:


思路为:

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

所以在OnInitDialog中,调用函数FindProcessRunning

void CVMMapDlg::FindProcessRunning()
{
	BOOL fOk;
	ToolHelp st_toolhelp;
	TCHAR szLine[100];


	//清空Combox
	m_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);//保存选中进程的进程ID
	cst_process.Delete(cst_process.Find(' '),cst_process.GetLength());


	cst_caption.Insert(cst_caption.Find('[') + 1,cst_process);

	//重新设定对话框caption
	SetWindowText(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 UNICODE
	fOk = (hClipData == SetClipboardData(CF_UNICODETEXT,hClipData));
#else
    fOk = (hClipData == SetClipboardData(CF_TEXT,hClipData));
#endif
	CloseClipboard();
	
	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开始Query
	2、如果返回为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 Information
	PVOID pvRgnBaseAddress;//虚拟空间的区域地址
	DWORD dwRgnProtection;//区域空间刚刚被保留时的保护属性
	SIZE_T RgnSize;       //区域空间的大小
	DWORD dwRgnStorage;   //该区域空间主要使用的物理存储器的类型
	DWORD dwRgnBlocks;    //该区域空间包含的地址块的数量
	DWORD dwRgnGuardBlks; //PAGE_GURARD保护属性打开的块的数量
	BOOL  fRgnIsAStack;   //是否包含线程堆栈
	//Block information
	PVOID 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;
		}

		//是否在同一个Region
		if (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
	//倒数第四个为0
	pVMQHelp->fRgnIsAStack = 
		(pVMQHelp->dwRgnGuardBlks > 0) ||
		((pVMQHelp->dwRgnBlocks > 3) &&
		(0 == dwProtectBlock[0]) &&
		(PAGE_NOACCESS == dwProtectBlock[1]) &&
		(PAGE_READWRITE == dwProtectBlock[2]) &&
		(0 == dwProtectBlock[3]));
	
	return fOk;
}
【文尾】如果对您有帮助,请留下对我和蟹儿的祝福。欢迎一起讨论Windows核心编程,第一次看,难免有理解错误和不清楚的地方。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值