VC++可不可以直接对内存进行修改?

比如 0467A618 内存地址,它的值为5,可以直接对其进行修改吗?

一、结论:
只可以间接修改

二、原因:
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*dwOneGB; dwBase += 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=0; i<(int)4*1024-3; i++)
{
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=0; i<nOrgCnt; i++)
{
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=0; i<(int)4*1024-3; i++)
{
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*dwOneGB; dwBase += 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=0; i<nOrgCnt; i++)
{
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=0; i< g_nListCnt; i++)
{
printf("%08lX \n", g_arList[i]);
}
}

BOOL WriteMemory(DWORD dwAddr, DWORD dwValue)
{
return ::WriteProcessMemory(g_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL);
}

参考资料:人民邮电出版出版、王艳平编著的《Windows程序设计》一书的第二章第五节

温馨提示:内容为网友见解,仅供参考
第1个回答  2010-03-20
可以的,先找到程序的窗口句柄,Findwindow
然后写内存就可以了,WriteProcessMemory。
第2个回答  推荐于2016-02-25
可以,下面给出一个函数。其第一个参数是目标进程ID,第二参数是目标地址,第三个参数是修改后的值。

BOOL 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 dwWriteBytes = 0, dwOldProtect ;
// 修改目标地址的保护方式为可读可写
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 ;
}本回答被提问者采纳
第3个回答  2010-03-20
不可以的~

VC++可不可以直接对内存进行修改?
只可以间接修改二、原因:32位字长的Windows 环境是一个“多任务单用户”操作系统,运行在X86或者兼容CPU的保护模式上,此模式使每个正在运行的程序(准确的叫法是“进程”,即Windows所调度的“任务”)都有自己独立的4GB逻辑内存空间,所谓保护就是每个进程的4GB内存地址逻辑上彼此独立,CPU和Windows保护每个独立进程的4GB逻...

VC++运行结果出现内存不足。。。
1将默认堆栈值设大些,可以设定2g以上。2优化程序,全局变量开数组,到2g左右也是极限了,可以考虑自己管理内存,先保留很大一片内存,分批提交内存,不用的释放掉,这样处理上t的数据都没问题 3设置windows大内存选项,最大3gb 4换成64比特系统 ...

c++中怎么手动扩大栈空间?
如果是系统栈的话 VC++默认的栈空间是1M,有两个方法更改 a. link时用\/STACK指定它的大小,或者在.def中使用STACKSIZE指定它的大小 b. 使用控制台命令“EDITBIN”更改exe的栈空间大小。例如:打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最...

VC++句柄问题
LocalAlloc返回句柄的方式允许对内存进行管理,比如LocalAlloc允许分配“可移动内存”,LocalLock时才会给你返回一片连续的内存,在你Unlock之后,内存可能仍然是连续的,也可能是不连续的,也可能在某个时刻会移到其他地方。下面简单通过一个例子来说明可移动内存的优势,比如你要申请一片很大的连续内存,但此...

VC++具有什么特点呢?
VC++的特点之一在于其强大的调试工具。这些工具提供了详尽的错误信息和调试过程,帮助开发者快速定位和解决程序中的问题。无论是内存泄漏、异常处理还是性能瓶颈,开发者都能借助VC++的调试工具进行精准诊断和优化。另一个显著特点是,VC++与微软视窗操作系统深度集成,使得开发者可以充分利用WindowsAPI提供的...

在VC++如何使控件大小修改为规定的大小?
VC控件有两个函数:MoveWindow和SetWindowPos 都可以改变指定窗口的位置和大小.MoveWindow的函数原型是:BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint ); \/\/这边的nWidth和nHeight的参数设置,可以修改为规定的大小。我更喜欢使用MoveWindow。

关于VC++释放内存的问题。请教了
你这个函数有严重的内存泄漏问题。你在函数里面申请的内存空间,没有使用,也没有释放!你的chr本来是指向你新申请的空间,但是你的chr=b;就改变了chr的指向。所以你申请的空间就泄漏了。

用vc++做好的工程运行时占内存太大,是不是载入的问题啊,如何减小啊?请...
VC里面在编译时提供了两个版本,一个是Debug版本一个是Release版本,两者比较的话后者的运行效率会更高一些,但是相对的就没有了一些VC本身的出错检查和判断。如果你觉得慢的话可以试试后面那个。VS08的修改方法是直接在工具栏上的解决方案配置下拉栏中选择Release。以上仅仅是从工程的角度看,引起内存占用...

如何用c\/c++编一个程序,向某一已知内存地址写入某值
这样就可以往任意内存赋值了。这只是dos。你想破坏windows有点难。lcj513110说的嵌入式系统指的是单片机吧。MOV是汇编语言,可以直接对内存进行操作。VC支持32位的汇编语言和C语言的混合编程。用汇编语言可以更方便地对内存进行读写。我只学过8086和8051的汇编,不能帮你了。你可以查一下有关VC++和32...

如何释放VC++程序调试过程中占用的内存
那不是释放内存的问题,而是你运行的程序是死循环,就是没办法停止,建议你修改程序。还有,在C++中释放内存可以用delete语句,比如我申请了动态存储空间p,“int p;p=new int[10];”最后我想释放内存,就需要添加语句“delete []p”.说多一点,使用doc系统,但程序结束时,系统会自动释放内存的。

相似回答