制作一个简单的游戏修改器
发布时间:2010/8/3 10:54:57 来源:城市学习网 编辑:ziteng
一、制作背景和原理:
在平时玩游戏的过程中,大家肯定会接触过形形色色的修改,特别是看到一些高手出的某某全能修,x项修改器,煞是羡慕,其实制作这样写一个这样的修改器一点也不神秘, 好了,请各位看官一同随我去揭开修改器之谜......“修改器”程序的就是修改我们想要数据的地址里面的数值,这句话比较拗口,但是这是“修改器”程序的关键。下面就以时兴的Normal tanks(坦克大战)为例,和大家讨论怎样去DIY一个游戏修改器请大家移步且随我步骤慢慢来。
二、找到我们想要的内存地址:
这是很关键的一步, 给大家介绍一款优秀的内存编辑工具)。
在游戏中按热Ctrl+Tab返回桌面,在Quick Memory Editor中点击Add Task 。
搜索炮弹的数量,当前游戏中是50,在Search value中填入50,然后点击Search,搜索速度很快,这会出来很结果,然后回到游戏里,随便放几炮,当前炮弹数量变为了47,然后返回桌面,在Quick
Memory Editor中的Search value中填入47,点击Search, 这时候出来了几个结果,结果还是不是很精确。返回游戏,再随便放几炮,当前炮弹数量变成了43,再在Quick Memory
Editor搜索43,这时候出来了仅一个结果,这就是我们需要的内存地址了,记下来004C9C84,等会儿我们要用到。
三、介绍两个关键 API函数ReadProcessMemory()和 WriteProcessMemory():
详细的注释我表明在函数里
①BOOL ReadProcessMemory(
HANDLE hProcess, // 目标进程句柄
LPCVOID lpBaseAddress, // 读取数据的起始地址
LPVOID lpBuffer, // 存放数据的缓存区地址
DWORD nSize, // 要读取的字节数
LPDWORD lpNumberOfBytesRead ); // 实际读取的数据大小地址
ReadProcessMemory()用于读取游戏进程中制定的内存数据; 在实际操作中,我们用它来读取存放炮弹数量地址中的数据。
②BOOL WriteProcessMemory(
HANDLE hProcess, // 目标进程句柄
LPVOID lpBaseAddress, // 进程的起始地址
LPVOID lpBuffer, // 数据内容
DWORD nSize, // 需要写入的字节数
LPDWORD lpNumberOfBytesWritten); // 实际写入的数据大小的地址
WriteProcessMemory()和上面的ReadProcessMemory()用法一样,在实际操作中,我们用它来修改存放炮弹数量地址中的数据。
四、编程实现游戏修改(完整代码):
#include <windows.h>
HINSTANCE g_hInst;
HWND g_hWnd;
char szAppName[]="TankFix"; //The name of the exe
char szTitle[]="坦克大战修改";
DWORD addr=0x004C9C84; //存放炮弹数量的内存地址
DWORD pid; //坦克大战的PID
int val=1000; //炮弹要修改的数量
//-------------------------------------------------------------------------------------------------
// WndProc- 窗口函数
//-------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd,UINT message, WPARAM wParam, LPARAM lParam)
{
// int wmId,wmEvent;
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_TIMER:
{
HWND hw=FindWindow(NULL,"Normal-tanks"); //FindWindow()得到坦克大战程序的句柄
HANDLE hProcess; //定义坦克大战的进程句柄
if (hw!=0)
{
SetForegroundWindow(hw); //使我们的坦克大战设置为当前窗口
GetWindowThreadProcessId(hw,&pid); //得到游戏的PID号
hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); //打开进程PROCESS_ALL_ACCESS参数,制定进程可读可写
WriteProcessMemory(hProcess,(LPVOID)addr,&val,4,0); //向坦克大战进程内存中写入数据
}
else
MessageBox(g_hWnd,"游戏还没有运行吧!","提示信息",MB_OK|MB_ICONINFORMATION);
}
default:
return (DefWindowProc(hWnd,message,wParam,lParam));
}
return 0;
} [NextPage] //-------------------------------------------------------------------------------------------------
// InitApplication-注册窗口类
//-------------------------------------------------------------------------------------------------
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASSEX winclass;
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WndProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hInstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground =(HBRUSH) GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = "WINCLASS1";
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
return (RegisterClassEx(&winclass));
}
//-------------------------------------------------------------------------------------------------
// InitInstance-产生窗口,显示以及更新窗口
//-------------------------------------------------------------------------------------------------
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
g_hInst=hInstance;
g_hWnd=CreateWindowEx(NULL,
"WINCLASS1",
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(!g_hWnd)
{
return FALSE;
}
ShowWindow(g_hWnd,nCmdShow);
UpdateWindow(g_hWnd);
return TRUE;
}
int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
MSG msg;
UNREFERENCED_PARAMETER(lpCmdLine);
if (!hPrevInstance)
{
if (!InitApplication(hInstance))
{
return (FALSE);
}
}
if (!InitInstance(hInstance,nCmdShow))
{
return FALSE;
}
SetTimer(g_hWnd,1,150,NULL);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}
五、总结
利用我们再学校学习的C/C++对付平时的一些应用时足够的,只要我们打开思路,我们就能做出一些“高手”才能做的东西,这也是我们成长成为高手必经之路。有什么问题,欢迎大家及时与我讨论。