还没学MFC ,那就用控制台界面将就一下吧,一个游戏内存修改器。
先贴下代码:
#include
<
stdio.h
>
#include < windows.h >
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()
{
// 启动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 " );
::CloseHandle(g_hProcess);
return 0 ;
}
BOOL CompareAPage(DWORD dwBaseAddr,DWORD dwValue)
{
// 读取1页内存
BYTE arBytes[ 4096 ];
if ( ! ::ReadProcessMemory(g_hProcess,(LPCVOID)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 ;
const DWORD dwOnePage = 4 * 1024 ;
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 ;
else
dwBase = 640 * 1024 ;
// 在开始地址到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))
return FALSE;
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 " ,g_arList[i]);
}
}
// 写内存
BOOL WriteMemory(DWORD dwAddr,DWORD dwValue)
{
return (::WriteProcessMemory(g_hProcess,(LPVOID)dwAddr, & dwValue, sizeof (DWORD),NULL));
}
#include < windows.h >
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()
{
// 启动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 " );
::CloseHandle(g_hProcess);
return 0 ;
}
BOOL CompareAPage(DWORD dwBaseAddr,DWORD dwValue)
{
// 读取1页内存
BYTE arBytes[ 4096 ];
if ( ! ::ReadProcessMemory(g_hProcess,(LPCVOID)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 ;
const DWORD dwOnePage = 4 * 1024 ;
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 ;
else
dwBase = 640 * 1024 ;
// 在开始地址到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))
return FALSE;
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 " ,g_arList[i]);
}
}
// 写内存
BOOL WriteMemory(DWORD dwAddr,DWORD dwValue)
{
return (::WriteProcessMemory(g_hProcess,(LPVOID)dwAddr, & dwValue, sizeof (DWORD),NULL));
}
几个注意的地方:
1.代码中出现的 (LPVOID)dwBaseAddr 指的是 (void*)dwBaseAddr 把地址dwBaseAddr做为空类型的指针,指针的值是 dwBaseAddr 地址的值。
2.代码中有这么一段:
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;
}
}
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;
}
}
这里i为什么小于4×1024-3呢? 由 pdw=(DWORD*)&arBytes[i] 由左右相等原则 有 *pdw=*&arBytes[i] 因为他们都是DWORD型的,占四个字节,所以i最多取到4×1024-4,此时=*&arBytes[i]占据的字节号为4×1024-4,4×1024-3,4×1024-2,4×1024-1。
附上测试例程:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/7ff8d92cded7e0ce15e7ca1acc870052.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)