【文起】思念亲爱的蟹儿,一直没有忘记自己的梦想,奋斗
程序最后执行的界面如:
思路为:
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核心编程,第一次看,难免有理解错误和不清楚的地方。