zoukankan      html  css  js  c++  java
  • 逆向工程第006篇:简易游戏辅助的实现

    前言

    从本文开始,我会为大家介绍游戏辅助工具的实现,涉及到逆向以及Windows程序设计等知识。本文所研究的游戏选自于【日】爱甲健二编著的《有趣的二进制》,本文中游戏介绍部分的内容,也是源于该书。

    射击游戏规则介绍

     我们首先来看一下本次的示例游戏,运行shooting文件夹中的shooting.exe即可:

    这个游戏的规则如下:

           ● 空格键:射击

           ←键:向左移动

           ● →键:向右移动

           ● ↑键:填充能量(以当前得分为上限)

           ● ↓键:时间停止(消费能量)

    用左右键移动,用空格键射击,这些操作和一般的射击游戏一模一样。通过按上下键可以使用能够让时间停止的特殊能力。其中↑键用来填充能量,↓键则用来消费能量并让时间停止。能量的上限是当前得分,因此随着游戏的进行,能够填充的能量也会增加。击中敌人可以增加得分,被敌人击中则减少得分。得分越高,敌人越强,子弹的追踪性能也会提高。

    大家可以先玩玩看,一般来说能玩到500~1000分,不过,当超过1000分之后,游戏的难度就会大大增加,要想达到2000分可以说是相当困难的。

     

    修改内存数据就能得高分

    得2000分虽然难,但其实我们只要修改内存中的数据就可以轻松实现了。为了修改内存数据,我们这里要用到编写游戏辅助最常用的一款工具“Cheat Engine” 。在运行游戏的同时,打开“Cheat Engine”,然后从进程列表中选择shooting.exe:

    接下来我们尝试让分数“SCORE”发生变化,比如击中对手一次,我们的分数就会变成“29”,此时将29输入“Cheat Engine”中Value下面的输入条内,点击“New Scan”:

    可以看到这里找到了1290条结果,但究竟哪个才是我们要找的“SCORE”呢?目前还不好判断,因此我们需要再让分数发生变化,比如再击中对手一次。此时我们的分数变成了58分,回到CE,将刚才的 29修改为58,然后点击“Next Scan”,此时就只剩下一个结果了:

    我们可以先记住它的地址(Address),即0x0019FD48,一会编程需要用到。这里我们可以直接通过CE修改分数,也就是双击这个结果,它会显示在CE下方的列表框中,然后双击下面列表框中Value下面的58,在新弹出的对话框中进行修改:

    将其修改成2000,点击OK即可。此时回到游戏,我们就可以发现分数已经变成2000了。

     

    编写游戏辅助

    利用上述方法可以对游戏的内存进行修改,但是每次仅能修改一处数值,并且重启游戏以后,还需要重新将CE与游戏挂载,重新搜索内存数据,这就很不方便了,因此我们这里研究一下如何编写一个简易的游戏辅助,这样每当我们想修改的时候,只要运行游戏辅助就可以了,并且还能按照自己的喜好进行编辑和修改。

    本程序在Visual Studio 2013环境中编程实现,使用C++语言。首先启动VS2013,我们新建一个工程文件:

    这里我们选择的是Win32控制台应用,注意在创建设置对话框里面,我们选择创建一个空的工程:

    创建成功以后,我们为这个工程新增一个cpp文件,在VS窗口的右侧找到Solution Explorer,右键点击Source Files,选择添加一个新的项目:

    接下来选择添加cpp文件即可:

    cpp文件创建成功以后,就需要编写代码了。对于本程序,修改分数为2000的完整代码如下:

    #include <stdio.h>
    #include <windows.h>
    int main() {
    	DWORD Pid;
    	HANDLE hProcess = 0;
    	DWORD Address = 0x0019FD48;
    	DWORD Score = 2000;
    	DWORD result;
    	HWND hWnd = FindWindow(NULL, L"shooting");
    	if (hWnd != 0) {
    		GetWindowThreadProcessId(hWnd, &Pid);
    		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
    		if (hProcess == 0) {
    			printf("Open process failed.");
    			return 0;
    		}
    		result = WriteProcessMemory(hProcess, (LPVOID)Address, &Score, 4, 0);
    		if (result == 0) {
    			printf("Modify failed.");
    		} else {
    			printf("Modify Success.");
    		}
    	} else {
    		printf("Failed");
    	}
    	return 0;
    }

    对于上述程序,有两个地方的数据需要说明一下。首先是调用FindWindow函数获取窗口句柄时,最后一个参数是窗口的名称。当然,我们启动游戏后,是可以在游戏窗口的左上角看到游戏窗口名称叫做“shooting”的。但实际上,为了严谨起见,我们一般是使用一款名为Spy++的工具来获取窗口名称的。该工具已经被集成到了我们的VS开发环境里面,只要选择菜单栏中的TOOLS,就可以找到Spy++了:

    我们选择菜单栏中的“Search”,再点击“Find Window”,就会弹出名为“Window Search”的对话框。我们将对话框中的Finder Tool后面的准心拖到游戏窗口里面,这样该工具就能够帮我们识别到窗口的真实标题内容了,即Caption的值:

    我们把这个值当作FindWindow函数的最后一个参数即可。

    第二个需要说明的地方是程序开始位置的Address值,这个值在程序中是0x0019FD48,也就是我们之前使用CE所发现的用于保存分数的地址。不同版本的游戏的这个值往往是不一样的,因此为了严谨起见,就如同我们刚才获取窗口名称一样,每次都应该使用CE确认一下这个地址到底是多少。

    编译通过后运行游戏,再运行本程序,就可以发现分数被修改为2000了。

     

    其它有意思的修改

    当我们把分数修改为2000以后,可以发现游戏难度呈几何级提升,一方面是对手的子弹有了跟踪的效果,我们很难躲避;另一方面是对手本体在躲避我方的子弹方面更加地智能,我们很难击中对手。针对于这两种情况,我们可以使用一些简单的小技巧来攻克。

    首先是对手子弹的跟踪效果。我们这里不妨把自己设置成“无敌”的模式。当然,“无敌”可以考虑通过修改源代码实现,但是换一个角度来看这个问题,对手之所以会击中我们,就是由于绿色子弹的存在,而这个绿色子弹其实就是一个图片文件,位于shooting文件夹,文件名是EShot.png,那么我们不妨将这个文件删掉。再次回到游戏后就能发现,对手只会左右移动,不会发射子弹了,于是“无敌”功能实现。

    可现在尽管无敌了,但我们还是很难击中对手,因此不妨使用同样的思维,在我们的黄色子弹上面做文章。使用画图软件对Shot.png进行编辑,比如将其拉伸变宽,然后保存,再进入游戏就能发现我们的子弹宽了很多:

    如此一来,即便对方身手再好,也不可能躲避掉我们的子弹了。

  • 相关阅读:
    Blob对象转File对象
    TCP的三次握手 与 四次挥手
    HTTP协议 与 TCP协议 的区别
    tcp四次挥手
    tcp协议
    tcp的三次握手
    关于HTTP协议 && TCP协议的一些理解
    Javascript数组中常用的排序法 ——冒泡排序法和选择排序法以及快速排序法
    如何用Bat批处理自制自解压文件
    [SQL]查询所有数据库、表名、表字段总结
  • 原文地址:https://www.cnblogs.com/csnd/p/11785697.html
Copyright © 2011-2022 走看看