Jinlong's Blog

一个简易游戏辅助的实现

相信大家都有用过游戏辅助,比如说按键精灵,八门神器等。本文要实现一个简易的qq五子棋辅助,实现用程序自动与网友对弈。先上成果图:
/uploads/gamehelper.jpg
概括来说,实现过程分为3个部分:

  • 辅助程序从qq五子棋游戏中获取相关信息
  • 辅助程序执行相关算法,算出结果
  • 模拟人类操作(比如点击鼠标)把结果反馈给qq五子棋

获取信息

从游戏中获取信息(比如当前所有棋子的位置)有很多方法,其中一种方法是直接读取程序内存里面的相关数据(qq五子棋里面肯定有段内存是存储棋子位置的,极可能是一个数组),比如qq五子棋中棋盘的部分数据如下:
/uploads/memory.jpg
每一个数据占两个字节(short),第一个数据4代表当前总共下了4步棋,后面是棋盘数据,棋盘数据是按棋盘上的一竖列一竖列排列的,比如1代表在棋盘左上角下了第一个棋子,2代表接着在左上角下面下了一个棋子,以此类推。所以以上数据对应的棋盘如下:
/uploads/board.jpg
找到相关的数据容易,用ollydbg动态调试一下很快就出来了。如果数据的地址每次都不变,那么我们可以用以下方法来获取程序的内存数据(一些软件破解的注册机也是这么干的):

1
2
3
4
5
6
7
DWORD processId;
HWND hWnd = FindWindow(NULL, "五子棋"); //首先获取qq五子棋的窗口句柄
if (hWnd == NULL) return 0;
GetWindowThreadProcessId(hWnd, &processId);
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); //打开进程,获取进程句柄
ReadProcessMemory(process, (LPCVOID)(0x1f51c16), buff, size, &readSize); //读取内存
CloseHandle(process);

但可怕的是,游戏里面的数据为了防外挂防辅助等,游戏里面的数据一般都是变址的,也就是每次运行都会不一样,qq五子棋就是这样。所以还要逆向去分析相关的变址算法。这样的话辅助(外挂)的编写成本就高了很多。我们先不用这种方法(读取内存)去获取信息,对于五子棋游戏,先用一种简单粗暴的方法,读取游戏程序窗口上的相关像素,来获取棋子的位置(因为棋子颜色都是黑与白的,所以很容易分辨出整个棋盘的下棋情况)。

1
2
HDC hDC = GetDC(hWnd);
COLORREF color = GetPixel(hDC, x, y);

其中x,y为你要获取的像素在qq五子棋窗口中的坐标。

执行相关算法

在获取了相关的信息之后,接下来的任务就是编写相关的算法来用电脑自动“玩游戏”,相关算法参考我之前的博文。

当然,你也可以直接用一些开源的五子棋引擎,比如yixin。

结果反馈

在用相关算法算出下一步的操作(下一步应该下哪里)之后,辅助应该模拟人类操作来进行“下棋”,这里是简单的鼠标点击操作,也就是向qq五子棋游戏窗口发送鼠标左键按下的消息:

1
SendMessage(hWnd, WM_LBUTTONDOWN, VK_LBUTTON, MAKELPARAM(x, y));

但是,如果这样操作的话,并不能成功模拟人类在qq五子棋上下棋,qq五子棋可能为了防止诸如按键精灵等此类辅助程序加了一些限制,分析后发现要成功“下棋”,还要发送一个在该点上的鼠标移动消息:

1
2
SendMessage(hWnd, WM_MOUSEMOVE, VK_LBUTTON, MAKELPARAM(x, y));
SendMessage(hWnd, WM_LBUTTONDOWN, VK_LBUTTON, MAKELPARAM(x, y));

自此,一个简单的qq五子棋辅助就完成了。

后记

这是一个非常简单的游戏辅助,直接获取窗口像素来获取棋盘信息这种方式会受很多因素的影响,比如说,游戏中对方突然发了一句“快点吧,我等到花儿都谢了”,棋盘左下侧会出现一个蓝色的气泡,这样的话,棋盘那部分像素就变成了蓝色,相应的这会影响我们的辅助运行,当然,这是可以通过修改代码来修复的。
一些比较高级的外挂,一方面他们会通过读取游戏内存来获取相关的游戏数据,另一方面他们会通过分析相关的网络协议,进行抓包改包直接在网络通讯层面来模拟人类操作。每一个比较火的游戏背后一般都会有这样一个庞大的黑色产业链,站在明处的游戏厂商会不断采取相关措施来防外挂,包括一些惩罚机制(封号等),道高一尺魔高一丈,站在暗处的黑客们也会继续优化他们的外挂程序,继续产出和买卖各种各样的外挂和辅助程序。