只可以间接修改
二、原因:
32位字长的Windows 环境是一个“多任务单用户” *** 作系统,运行在X86或者兼容CPU的保护模式上,此模式使每个正在运行的程序(准确的叫法是“进程”,即Windows所调度的“任务”)都有自己独立的4GB逻辑内存空间,所谓保护就是每个进程的4GB内存地址逻辑上彼此独立,CPU和Windows保护每个扮轮悉独立进程的4GB逻辑内存空间不被其他用户进程直接修改。
而且4GB中只有2GB属于本进程专有地址,另外2GB属于Windows系统保护的系统内存空间,受windows系统严格保护,不允许用户进程直接读写只能通过“内核对象”间接访问。
所以您通过某个软件看到了内存地址0x0467A618的桐让内容并试图用自编的VC程序修改时,实际上只能修改自编VC程序运行实例(即“进程”)的同编号进程地址的内容,而不能修改原来的那个进程的内存地址内容。
三、解决方案:
1)思路:
a.启动您希望修改其内容的进程,记下您希望修改的地址的内容;
b.编写一个VC程序,先按照进程名字获取进程ID,然后搜索这个ID的进程中,非系统内存区域中匹配这个内容的内存地址(厅乎注意:从Windows 2000/XP开始的版本,系统保留区域为64K~2GB,2GB以上的才是用户进程内存区域)
c.找到内容匹配的内存地址后,将其修改为你希望的值。
2)具体编程方法:
a.建立一个名字为MemRepair的VC工程(选择32位控制台工程,使用预编译头)
b.陆续加入以下三个文件:
MemRepair.h MemRepair.cpp MainProg.cpp,分别键入以下源代码:
/*(完整VC工程源代码,已经在WinXP+VC2008Express环境调试通过)*/
/* *************** 新文件 ********************* */
/* ******************************************** */
//StdAfx.h
#if !defined(AFX_STDAFX_H__7438D592_DA27_443E_824E_D280AF259D3F__INCLUDED_)
#define AFX_STDAFX_H__7438D592_DA27_443E_824E_D280AF259D3F__INCLUDED_
#if _MSC_VER >1000
#pragma once
#endif // _MSC_VER >1000
// TODO: reference additional headers your program requires here
#include "MemRepair.h"
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__7438D592_DA27_443E_824E_D280AF259D3F__INCLUDED_)
/* **************新文件**************** */
/* ************************************ */
//MemRepair.h
#ifndef __MEMFINDER_H__
#define __MEMFINDER_H__
#include <windows.h>
class CMemFinder
{
public:
CMemFinder(DWORD dwProcessId)
virtual ~CMemFinder()
// 属性
public:
BOOL IsFirst() const { return m_bFirst}
BOOL IsValid() const { return m_hProcess != NULL}
int GetListCount() const { return m_nListCnt}
DWORD operator [](int nIndex) { return m_arList[nIndex]}
// *** 作
virtual BOOL FindFirst(DWORD dwValue)
virtual BOOL FindNext(DWORD dwValue)
virtual BOOL WriteMemory(DWORD dwAddr, DWORD dwValue)
// 实现
protected:
virtual BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue)
DWORD m_arList[1024]// 地址列表
int m_nListCnt // 有效地址的个数
HANDLE m_hProcess// 目标进程句柄
BOOL m_bFirst // 是不是第一次搜索
}
#endif // __MEMFINDER_H__
/* ************** 新文件 ************** */
/* ************************************ */
//MemRepair.cpp
#include "MemRepair.h"
#include "StdAfx.h"
CMemFinder::CMemFinder(DWORD dwProcessId)
{
m_nListCnt = 0
m_bFirst = TRUE
m_hProcess = ::OpenProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, dwProcessId)
}
CMemFinder::~CMemFinder()
{
if(m_hProcess != NULL)
::CloseHandle(m_hProcess)
}
BOOL CMemFinder::FindFirst(DWORD dwValue)
{
const DWORD dwOneGB = 1024*1024*1024// 1GB
const DWORD dwOnePage = 4*1024 // 4KB
if(m_hProcess == NULL)
return FALSE
// 查看 *** 作系统类型,以决定开始地址
DWORD dwBase
OSVERSIONINFO vi = { sizeof(vi) }
::GetVersionEx(&vi)
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
dwBase = 4*1024*1024 // Windows 98系列,4MB
else
dwBase = 640*1024 // Windows NT系列,64KB
// 在开始地址到2GB的地址空间进行查找
for(dwBase <2*dwOneGBdwBase += dwOnePage)
{
// 比较1页大小的内存
CompareAPage(dwBase, dwValue)
}
m_bFirst = FALSE
return TRUE
}
BOOL CMemFinder::CompareAPage(DWORD dwBaseAddr, DWORD dwValue)
{
// 读取1页内存
BYTE arBytes[4096]
if(!::ReadProcessMemory(m_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL))
return FALSE// 此页不可读
// 在这1页内存中查找
DWORD* pdw
for(int i=0i<(int)4*1024-3i++)
{
pdw = (DWORD*)&arBytes[i]
if(pdw[0] == dwValue) // 等于要查找的值?
{
if(m_nListCnt >= 1024)
return FALSE
// 添加到全局变量中
m_arList[m_nListCnt++] = dwBaseAddr + i
}
}
return TRUE
}
BOOL CMemFinder::FindNext(DWORD dwValue)
{
// 保存m_arList数组中有效地址的个数,初始化新的m_nListCnt值
int nOrgCnt = m_nListCnt
m_nListCnt = 0
// 在m_arList数组记录的地址处查找
BOOL bRet = FALSE// 假设失败
DWORD dwReadValue
for(int i=0i<nOrgCnti++)
{
if(::ReadProcessMemory(m_hProcess, (LPVOID)m_arList[i], &dwReadValue, sizeof(DWORD), NULL))
{
if(dwReadValue == dwValue)
{
m_arList[m_nListCnt++] = m_arList[i]
bRet = TRUE
}
}
}
return bRet
}
BOOL CMemFinder::WriteMemory(DWORD dwAddr, DWORD dwValue)
{
return ::WriteProcessMemory(m_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL)
}
/* ************** 新文件 ************** */
/* ************************************ */
//主程序mainprog.cpp
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include <iostream>
using namespace std
BOOL FindFirst(DWORD dwValue)// 在目标进程空间进行第一次查找
BOOL FindNext(DWORD dwValue)// 在目标进程地址空间进行第2、3、4……次查找
DWORD g_arList[1024] // 地址列表
int g_nListCnt // 有效地址的个数
HANDLE g_hProcess // 目标进程句柄
//////////////////////
BOOL WriteMemory(DWORD dwAddr, DWORD dwValue)
void ShowList()
int main(int argc, char* argv[])
{
// 启动02testor进程
char szFileName[] = "..\\02testor\\debug\\02testor.exe"
STARTUPINFO si = { sizeof(si) }
PROCESS_INFORMATION pi
::CreateProcess(NULL, szFileName, NULL, NULL, FALSE,
CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)
// 关闭线程句柄,既然我们不使用它
::CloseHandle(pi.hThread)
g_hProcess = pi.hProcess
// 输入要修改的值
int iVal
printf(" Input val = ")
scanf("%d", &iVal)
// 进行第一次查找
FindFirst(iVal)
// 打印出搜索的结果
ShowList()
while(g_nListCnt >1)
{
printf(" Input val = ")
scanf("%d", &iVal)
// 进行下次搜索
FindNext(iVal)
// 显示搜索结果
ShowList()
}
// 取得新值
printf(" New value = ")
scanf("%d", &iVal)
// 写入新值
if(WriteMemory(g_arList[0], iVal))
printf(" Write data success \n")
::CloseHandle(g_hProcess)
return 0
}
BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue)
{
// 读取1页内存
BYTE arBytes[4096]
if(!::ReadProcessMemory(g_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL))
return FALSE// 此页不可读
// 在这1页内存中查找
DWORD* pdw
for(int i=0i<(int)4*1024-3i++)
{
pdw = (DWORD*)&arBytes[i]
if(pdw[0] == dwValue) // 等于要查找的值?
{
if(g_nListCnt >= 1024)
return FALSE
// 添加到全局变量中
g_arList[g_nListCnt++] = dwBaseAddr + i
}
}
return TRUE
}
BOOL FindFirst(DWORD dwValue)
{
const DWORD dwOneGB = 1024*1024*1024// 1GB
const DWORD dwOnePage = 4*1024 // 4KB
if(g_hProcess == NULL)
return FALSE
// 查看 *** 作系统类型,以决定开始地址
DWORD dwBase
OSVERSIONINFO vi = { sizeof(vi) }
::GetVersionEx(&vi)
if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
dwBase = 4*1024*1024 // Windows 98系列,4MB
else
dwBase = 640*1024 // Windows NT系列,64KB
// 在开始地址到2GB的地址空间进行查找
for(dwBase <2*dwOneGBdwBase += dwOnePage)
{
// 比较1页大小的内存
CompareAPage(dwBase, dwValue)
}
return TRUE
}
BOOL FindNext(DWORD dwValue)
{
// 保存m_arList数组中有效地址的个数,初始化新的m_nListCnt值
int nOrgCnt = g_nListCnt
g_nListCnt = 0
// 在m_arList数组记录的地址处查找
BOOL bRet = FALSE// 假设失败
DWORD dwReadValue
for(int i=0i<nOrgCnti++)
{
if(::ReadProcessMemory(g_hProcess, (LPVOID)g_arList[i], &dwReadValue, sizeof(DWORD), NULL))
{
if(dwReadValue == dwValue)
{
g_arList[g_nListCnt++] = g_arList[i]
bRet = TRUE
}
}
}
return bRet
}
// 打印出搜索到的地址
void ShowList()
{
for(int i=0i<g_nListCnti++)
{
printf("%08lX \n", g_arList[i])
}
}
BOOL WriteMemory(DWORD dwAddr, DWORD dwValue)
{
return ::WriteProcessMemory(g_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL)
}
在dos时代可以定义指针*p
更改p为你想要的内存地址。
(注意,其实大多时候这个地址都是偏移地址(见汇编))
你再改动*p值就能更改这个地址对物乱应数据
如果你一定要方问任意内存地址
请用asm语句调用汇编语句,更改段地址
而在windows时拆胡代,访问任意地址已经是不可以旅蚂拦了,windows不访问硬件地址(为了安全),比哪不能访问显卡地址。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)