版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WUDAIJUN/article/details/8721916
本实例通过对进程内存的查询和修改来实现简单内存修改器功能
实现也比较简单:
点击选择打开进程列表 选择目标进程:
选择进程后,输入查找值,点击首次查找:
在出现的一系列满足条件地址中,如果无法识别要修改的地址,则可以在目标值变化后,跟踪查询该值。如在Mine.exe中,等剩余雷提示到39时,再输入39,点击累计查询:
此时出现唯一确定的地址值。选中该地址值,输入修改值,即可完成修改,之后将扫雷最小最大化一次(重绘),即可看到修改值:
实现也比较简单:
- 在用户选择进程后,用VirtualQueryEx查询目标进程区域块信息,并将所有区域块信息放入一个链表list<MEMORY_BASIC_INFORMATION> m_listMbi中。
BOOL CVMHelp::GetVMInfoList(DWORD dwProcessId)
{
m_listMbi.clear();
//打开目标进程
HANDLE hProcess = INVALID_HANDLE_VALUE;
if (dwProcessId != GetCurrentProcessId())
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId);
if (hProcess == NULL)
return FALSE;
}
//查询区域块
MEMORY_BASIC_INFORMATION mbi;
DWORD size = sizeof(mbi);
DWORD dwCurAddr = (DWORD)m_sysInfo.lpMinimumApplicationAddress;
for (; dwCurAddr<(DWORD)m_sysInfo.lpMaximumApplicationAddress; )
{
VirtualQueryEx(hProcess, (LPCVOID)dwCurAddr, &mbi, size);
m_listMbi.push_back(mbi);
dwCurAddr += mbi.RegionSize;
}
CloseHandle(hProcess);
return TRUE;
}
- 在用户点击首次查找时,在m_listMbi中的每一个为提交状态(MEM_COMMIT)的区域块中用ReadProcessMemory不断读出一页数据,并在该页数据中逐个查找该DWORD值,如果找到,则将该地址加入另一个list<DWORD> m_listAddr中。
//第一次搜索 在m_listMbi中进行
UINT CVMHelp::VM_FirstSearch(DWORD dwProcessId, DWORD dwValue)
{
//必要清空和检测
if (m_listMbi.empty())
return -1;
m_listAddr.clear();
//打开目标进程
HANDLE hProcess = INVALID_HANDLE_VALUE;
if(dwProcessId != GetCurrentProcessId())
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId);
if(NULL == hProcess)
return -1;
}
//遍历m_listMbi 地址空间区域信息列表
PBYTE pPageBuf = new BYTE[m_sysInfo.dwPageSize];
list<MEMORY_BASIC_INFORMATION>::iterator iter = m_listMbi.begin();
for (; iter!=m_listMbi.end(); iter++)
{
//只检测提交状态的区域
if (iter->State != MEM_COMMIT)
continue;
DWORD dwReadBytes, dwSize=0;
LPVOID lpAddr;
//不断从区域中读取一页数据
while(dwSize < iter->RegionSize)
{
lpAddr = (LPVOID)((DWORD)iter->BaseAddress+dwSize);
if (FALSE == ReadProcessMemory(hProcess, lpAddr, pPageBuf, m_sysInfo.dwPageSize, &dwReadBytes))
{
dwSize += m_sysInfo.dwPageSize;
continue;
}
//对该页数据进行逐个分析比较 如果等于目标值 则存入m_listAddr
for (int i=0; i<=m_sysInfo.dwPageSize-3; i++)
{
if (*(DWORD*)(pPageBuf+i) == dwValue)
m_listAddr.push_back((DWORD)lpAddr+i);
}
dwSize += m_sysInfo.dwPageSize;
}
if(m_listAddr.size() > MAX_ADDR_NUM)
break;
}
CloseHandle(hProcess);
delete []pPageBuf;
return m_listAddr.size();
}
- 如果用户点击累计查找,那么查找将在m_listAddr中进行,用ReadProcessMemory读出sizeof(DWORD)字节,将不等于新查询值的地址给删掉。累计查找可以进行多次。
//累计查找 在m_listAddr中进行
UINT CVMHelp::VM_ReSearch(DWORD dwProcessId, DWORD dwValue)
{
if(m_listAddr.empty())
return -1;
//打开目标进程
HANDLE hProcess = INVALID_HANDLE_VALUE;
if (dwProcessId != GetCurrentProcessId())
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId);
if(hProcess == NULL)
return -1;
}
//遍历m_listAddr:之前搜索匹配地址表
DWORD dwReadBytes, dwCurValue;
list<DWORD>::iterator iterTemp, iter = m_listAddr.begin();
for (; iter!=m_listAddr.end();)
{
ReadProcessMemory(hProcess, (LPVOID)*iter, &dwCurValue, sizeof(DWORD), &dwReadBytes);
iterTemp = iter++;
if (dwCurValue != dwValue) //移除不再与目标值相等的地址
m_listAddr.erase(iterTemp);
}
CloseHandle(hProcess);
return m_listAddr.size();
}
- 当用户点击修改时,用VirtualProtectEx修改目标进程该地址处的读写权限,用WriteProcessMemory修改该地址上的值,最后再用VirtualProtectEx恢复原来的读写保护。
//修改目标地址值
BOOL CVMHelp::VM_Modify(DWORD dwProcessId, DWORD dwTagAddr, DWORD dwValue)
{
HANDLE hProcess = INVALID_HANDLE_VALUE;
if (dwProcessId != GetCurrentProcessId())
{
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if(hProcess == NULL)
return FALSE;
}
DWORD dwOldProtect;
DWORD dwWriteBytes;
//修改虚拟地址读写权限
VirtualProtectEx(hProcess, (LPVOID)dwTagAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
//写入数据
WriteProcessMemory(hProcess, (LPVOID)dwTagAddr, &dwValue, sizeof(DWORD), &dwWriteBytes);
//改回该地址保护方式
VirtualProtectEx(hProcess, (LPVOID)dwTagAddr, sizeof(DWORD), dwOldProtect, NULL);
CloseHandle(hProcess);
return TRUE;
}
源代码
下载地址:http://download.csdn.net/detail/wudaijun/5189295