《游戏修改器DIY之二》

类别:编程语言 点击:0 评论:0 推荐:
《游戏修改器DIY之二》                      源码下载   上次我们以一款名叫《潜艇大战》的小游戏作为目标,制作了其相应的修改器,使之成为了不死版的游戏,相信大家在这过程中学到了相关的知识(一年前写的东西了:))。这次我们的目标是《红色警戒2》,制作她的金钱修改器。之所以选择这款游戏作为演示,一方面是出于个人原因:我很喜欢这款游戏;而另一方面则是:这款游戏很具有代表性,相信大多数修改过其金钱数的玩家们都会注意到:她存放金钱的内存地址并不是固定不变的,哪怕重新开始一次任务,她的地址都会改变。与之类似的游戏还有《Mech Commander》等。本篇将教你如何制作此类游戏的修改器。   目标:《红色警戒2》(繁体中文版:1.006)   所需工具:《金山游侠III》、   SOFTICE(版本:4.0.5 Build334+IceDump)、LordPE1.4、   Microsoft Visual C++ (版本:6.0+SP6)   第一部分:获得游戏中关键的数据——这是制作游戏修改器的前提。   首先用《游侠》找到存放金钱数的内存地址(一般情况下会找到三个地址,其中最另类的那个就是我们所需要的):0x68A1B5C,调出SOFTICE,输入下面的命令:bpm 68a1b5c r,回到游戏后SI就产生了中断,你可以看到下面这条指令: 0187:004E2B5A FIADD DWORD PTR [ESI+00000228]   其中ESI的值为0x068A1934,下指令:d esi+228 即得:0x068A1B5C,其中便是当前的金钱数。追溯这段代码可得: 0187:00494664 MOV EDX,[ECX+24] 0187:00494667 LEA EAX,[ECX+24] 0187:0049466A PUSH EAX 0187:0049466B CALL [EDX+18] 0187:0049466E XOR ECX,ECX 0187:00494670 MOV [ESI],EAX   在0187:0049466A处下断点,SI每次中断后,EAX的值始终是:0x068A1934,如此时下指令:d eax+228 同样可得:0x068A1B5C。现在情况很明了:其中0x228是个定值,我们现在不必理会,关键的问题是EAX的值,就像前面说到的那样:她的值并不是固定不变的,哪怕重新开始一次任务她的值都会随之改变。我们需要做的工作就是写一段自己的代码,将EAX的值保存在一个固定的位置,然后从该位置取得结果,再加上0x228即可得到存放金钱数的内存地址了。所以,我们需要找一个可写的空白区,来存放我们自己的代码和EAX的值。   用LordPE查看Game.exe(一定要做好备份!!!用LordPE查看文件后,即使什么也没做,他也会修改我们的文件……),发现.data段符合我们的要求,我选的位置是:0x42ed60(存放EAX的值),和0x42ed80(存放自己的代码),在0x42ed60处写一些字符串,如:vegeta,这样一来,我们可以用s命令快速找到其在内存中的位置,还可以判断该位置是否被程序所用。   重新开始游戏,SI会在0x0049466A处产生中断。在SI中下指令: s ds:400000 l ffffffff 'vegeta' SI提示找到了一个内存地址:018F:0082ED60(0042ED60),这段内存程序并没有占用,现在就可以在0x0082ED80(0042ED80)处写我们自己的代码了。在这之前,我们先修改0x0049466A,让他跳到我们的代码,下指令: a 49466a 输入: jmp 82ed80 //跳到我们的代码处执行 nop //补指令长度 修改后的代码为: 0187:0049466A E911A73900 JMP 0082ED80 0187:0049466F 90 NOP 0187:00494670 8906 MOV [ESI],EAX 现在写入我们的代码: a 82ed80 依次输入: mov dword ptr [82ed60],eax //将EAX的值保存到:0x82ed60 push eax //\ call [edx+18] //恢复被JMP 0082ED80破坏掉的指令 xor ecx,ecx /// jmp 00494670 //返回游戏程序继续执行 修改后的代码为: 0187:0082ED80 A360ED8200 MOV [0082ED60],EAX 0187:0082ED85 50 PUSH EAX 0187:0082ED86 FF5218 CALL [EDX+18] 0187:0082ED89 33C9 XOR ECX,ECX 0187:0082ED8B E9E058C6FF JMP 00494670   检查无误后记下机器码(我习惯用IceDump的抓屏),在0x0082ED85处设断点,F5返回游戏后便会产生中断,此时下指令: d *0082ED60+228   这时你就会看到金钱数了……注意:0x0082ED60可是个定值啊!   第二部分:用VC制作游戏修改器。   本程序每次运行将增加金钱至60000$。   程序源码中的重点部分我已经做了相应的注释,这里要说的是:   1:这段代码同时支持Win9x和NT系统,由于要找到目标进程的ID,所以我枚举了系统中的所有进程,然后根据进程名来确定我们的目标进程,但是,ToolHelp API中的szExeFile在这两种不同的系统中的返回值是有很大差异的:一个带有路径,另一个不带路径(有兴趣的朋友可以参照《如何在NT下获取进程的路径》一文)。所以,在Win9x系统中,本程序需要拷贝到游戏的所在目录中才能正确运行。   2:要先写我们的代码(0x0082ED80),然后再改写要跳转到我们代码中去的代码(0x0049466A)。   3:由于《红色警戒2》在程序切换的过程中会暂停游戏,所以在修改金钱数的地方做了一个延迟:以便用户有足够的时间返回游戏,这样游戏才会执行我们的代码,把金钱的内存地址放到0x0082ED60中去。如果没有这个延迟,游戏还没有将金钱地址放到0x0082ED60,ReadProcessMemory()就去获取金钱地址了,那WriteProcessMemory()也就写错了地方……   4:用Game.exe的备份替换掉修改后的程序,因为在0x0042ED60处我们写了一些字符串。如果不这样做,该修改器第一次运行时则不会正确修改你的金钱。想想为什么会这样?当家庭作业了。   5:最重要的一点!我十分喜欢这个游戏。做这个修改器只是练手,我平时可是不用她的…… ////////////////////////////////////////////////////////////////////////////////////////// /* * --《Red Alert 2》v1.006 繁体中文版金钱修改器Demo-- * 作者:赵春生 * 制作时间:15:30 2005-01-27 * 主页: http://timw.yeah.net http://timw.126.com * 本程序适用于:Win9x/NT * 代码在Win2000P+SP4 + VC6+SP6测试通过 */ #include #include int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HANDLE handle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); PROCESSENTRY32* info=new PROCESSENTRY32; info->dwSize=sizeof(PROCESSENTRY32); BOOL report; DWORD PID; HANDLE hProcess; char *szName="game.exe";//目标进程名 int i=0; //OBJ_INFO unsigned int OBJ_mycode[4]={0x82ED60A3,0x52FF5000,0xE9C93318,0xFFC658E0}; unsigned int OBJ_jumptomycode[2]={0x39A711E9,0x9000}; unsigned int OBJ_money[1]={0xEA60};//60000$ unsigned int OBJ_money_ip[1]={0x0}; unsigned int OBJ_code[1]={0x0}; char OBJ_path[255];//目标所在目录 GetCurrentDirectory(255,OBJ_path);//获取当前目录 strcat(OBJ_path,"\\game.exe");//目标所在目录 report=Process32First(handle,info); while(report) { if((strncmp(strlwr(info->szExeFile), strlwr(szName), strlen(szName)) == 0)||(strncmp(strlwr(info->szExeFile), strlwr(OBJ_path), strlen(OBJ_path)) == 0)) { PID=info->th32ProcessID; //打开游戏进程 hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,PID); ReadProcessMemory(hProcess,(int *)0x0049466A,OBJ_code,1,0); //获取0x0049466A代码:如为修改前的0x50或修改后的0xE9则继续运行, //否则可认定游戏版本不符。 if (OBJ_code[0]==0x50||OBJ_code[0]==0xE9) { //写入代码 WriteProcessMemory(hProcess,(int *)0x0082ED80,OBJ_mycode,16,0); WriteProcessMemory(hProcess,(int *)0x0049466A,OBJ_jumptomycode,6,0); for (i=0;i

本文地址:http://com.8s8s.com/it/it23123.htm