Bacysoft.cn

标题: 网游辅助(外挂)程序开发教程及实例分析04 - 游戏控制 [打印本页]

作者: bacy001    时间: 2014-9-3 22:25
标题: 网游辅助(外挂)程序开发教程及实例分析04 - 游戏控制
本帖最后由 bacy001 于 2016-6-24 15:30 编辑

关键字:网游辅助(外挂) VS2010 MFC 鼠标键盘消息 游戏控制

前面我们分别介绍了 WinPcap 编程接口以及封包数据分析的基本方法,对于我们的网游辅助(外挂)程序来说,实现以上内容,相当于给我们的程序安装上了眼睛和耳朵,使得它有能力对游戏中产生的数据做出反应,而这些反应具体来说就是实现对游戏人物的控制。这部分的内容其实按键精灵已经做得很不错了,而我们将要采用的方法也基本相同,无非就是通过发送鼠标和键盘消息来实现对游戏人物的控制!唯一不同的地方在于,我们能够实现针对具体游戏窗口发送,而按键精灵需要收费插件才能提供此功能!否则就只能将消息发送给获得焦点的窗口(本质上是将消息发送给了 Windows 桌面)。

1、搜索游戏窗口
Windows 系统是消息驱动的系统,任何一个操作都会触发一系列的消息,每一个窗口程序都有一个消息处理函数用于处理这些消息!使用一个程序去控制另外一个程序,最简单也是最安全的方法,就是发送消息给被控程序。要实现这个功能,第一步是要知道被控程序的主窗口句柄!Windows API 提供了一个函数可以用来完成这个工作,代码如下:
  1.         HWND *hwndChildAfter;
  2.         CPtrList plCore;

  3.         hwndChildAfter = new HWND;
  4.         *hwndChildAfter = NULL;

  5.         do{
  6.                 *hwndChildAfter = ::FindWindowEx(NULL,*hwndChildAfter,NULL,"GameName");
  7.                 plCore.AddTail((void*)hwndChildAfter);
  8.                 hwndChildAfter = new HWND;
  9.                 *hwndChildAfter = *(HWND*)plCore.GetTail();
  10.         } while ( *hwndChildAfter != 0 );

  11.         plCore.RemoveTail();
复制代码
函数 FindWindowEx 用于通过窗口名称来获取窗口的句柄,以上代码将搜索系统中正在运行的名称为 “GameName” 的窗口,并将获得的窗口句柄保存在链表类 plCore 中,如果同时打开了多个窗口,那么每个窗口的句柄信息将依次保存在 plCore 指向的链表结构中。FindWindowEx 是标准 Windows API,CPtrList 是标准 MFC 类,详细信息,请访问 MSDN。
  1. UINT iGameNum = plCore.GetCount();
  2. HWND iGameHwnd[iGameNum]

  3. if(iGameNum)
  4. {
  5.         for(UINT i = 0; i < iGameNum; i++){
  6.                 POSITION pos = plCore.FindIndex(i);
  7.                 iGameHwnd[iGameNum] = *(HWND*)plCore.GetAt(pos);
  8.         }
  9. }
复制代码
以上代码将链表中保存的句柄信息保存在数组中以便备用。

2、鼠标操作
一般游戏中的鼠标操作无非是:鼠标左键单击、右键单击、移动等等,某些游戏还支持双击操作。以鼠标左键单击为例,一次完整的鼠标左键单击操作可以分解成如下三个独立的消息,按照时间顺序依次是:WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP,发送消息则使用 :ostMessage 函数,具体代码如下:
  1. #define POS(x,y) x + y * 0x10000
  2. #define SLEEPTIME 100

  3. void ClickLeftMouseButton(HWND hwnd, UINT x, UINT y)
  4. {
  5.         int pos = POS(x,y);
  6.         ::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);
  7.         Sleep(SLEEPTIME);
  8.         ::PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, pos);        //Click Left Mouse Button
  9.         ::PostMessage(hwnd, WM_LBUTTONUP, 0, pos);

  10. }
复制代码
这段代码定义了一个 POS 宏,用于将坐标值组合到一个 32 位整数中作为 PostMessage 函数的最后一个参数,而 Sleep 函数则起到延迟操作的作用,设定合适的 SLEEPTIME 可以使得函数模拟的鼠标操作更加接近人的手工操作。与此对应的是鼠标右键单击,封装到自定义函数后,代码如下:
  1. void ClickRightMouseButton(HWND hwnd, UINT x, UINT y)
  2. {
  3.         int pos = POS(x,y);
  4.         ::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);
  5.         Sleep(SLEEPTIME);
  6.         ::PostMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, pos);        //Click Right Mouse Button
  7.         ::PostMessage(hwnd, WM_RBUTTONUP, 0, pos);

  8. }
复制代码
3、窗口坐标系统
鼠标操作中有一个非常重要的参数,就是坐标,如果给的坐标不对,就无法准确打开游戏菜单,拾取道具等等。那么如何确定有效的坐标参数呢?有一个简便的方法就是使用QQ的窗口截图 + Windows 自带的画笔程序。以 Windows 自带的扫雷程序为例,步骤如下:
1)运行扫雷程序,使用QQ的截图功能将整个窗口截图;
2)将截图粘帖到画图程序中,将鼠标移动到扫雷游戏界面的左上角(见下图中粉红色的点),注意这里说的是游戏界面,而不是窗口!

3)上图中粉红色的点就是游戏窗口中的坐标原点,也就是(0, 0),而上图右下角的坐标(3, 29)是包含了窗口边框的宽度的。因此我们要确认游戏界面上某个点的坐标时,只需要将鼠标移动到指定的位置上,然后将画图软件右下角显示的坐标减去(3, 29)即可获得该位置在游戏界面上的真实坐标,也就是我们鼠标消息中准确的坐标值。
例如:要确定扫雷游戏界面上黄色笑脸按钮的坐标,则首先在画笔程序中找到按钮中间的某个点的坐标(256, 79),然后减去(3, 29),得到(256 - 3 = 253, 79 - 29 = 50),然后调用函数:ClickLeftMouseButton(hwnd, 253, 50); 就能实现模拟鼠标点击扫雷窗口上黄色笑脸图标了,其中 hwnd 是扫雷程序的窗口句柄。

4、键盘操作
单单只有鼠标的操作肯定是不够的,键盘的操作一般主要用于游戏客户端的快捷键的使用,比如施放技能,吃药等等。下面的代码实现键盘输入英文字符串的功能:
  1. void TypeString(HWND hwnd, char *str)
  2. {
  3.         while(*str)
  4.         {
  5.                 ::PostMessage(hwnd, WM_CHAR, *str, 0);
  6.                 str++;
  7.         }
  8.         ::PostMessage(hwnd,WM_KEYDOWN,VK_RETURN,0x00420001);
  9.         ::PostMessage(hwnd,WM_KEYUP,VK_RETURN,0xC0420001);

  10. }
复制代码
可以看到,输入英文字符可以使用 WM_CHAR 消息,而输入回车这样的控制符,则需要使用 WM_KEYDOWN 与 WM_KEYUP ,这有点类似鼠标的单击操作。如果要发送功能键比如F1~F12,只需要修改上述代码中 VK_RETURN 的部分,更详细的信息请参考 MSDN。

如果希望输入中文,使用系统剪贴板是比较方便的,在这里就不做介绍了!





欢迎光临 Bacysoft.cn (http://bacysoft.cn/) Powered by Discuz! X3.3