SF网游辅助开发之控制实例分析

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

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

SF网游辅助开发之控制实例分析插图

1、搜索游戏窗口

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

HWND *hwndChildAfter;

CPtrList plCore;

hwndChildAfter = new HWND;

*hwndChildAfter = NULL;

do{

hwndChildAfter = ::FindWindowEx(NULL,hwndChildAfter,NULL,"GameName");

plCore.AddTail((void*)hwndChildAfter);

hwndChildAfter = new HWND;

*hwndChildAfter = *(HWND*)plCore.GetTail();

} while ( *hwndChildAfter != 0 );

plCore.RemoveTail();

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

UINT iGameNum = plCore.GetCount();

HWND iGameHwnd[iGameNum]

if(iGameNum)

{

for(UINT i = 0; i < iGameNum; i++){

POSITION pos = plCore.FindIndex(i);

iGameHwnd[iGameNum] = (HWND)plCore.GetAt(pos);

}

}

以上代码将链表中保存的句柄信息保存在数组中以便备用。

2、鼠标操作

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

define POS(x,y) x + y * 0x10000

define SLEEPTIME 100

void ClickLeftMouseButton(HWND hwnd, UINT x, UINT y)

{

int pos = POS(x,y);

::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);

Sleep(SLEEPTIME);

::PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, pos); //Click Left Mouse Button

::PostMessage(hwnd, WM_LBUTTONUP, 0, pos);

}

这段代码定义了一个 POS 宏,用于将坐标值组合到一个 32 位整数中作为 PostMessage 函数的最后一个参数,而 Sleep 函数则起到延迟操作的作用,设定合适的 SLEEPTIME 可以使得函数模拟的鼠标操作更加接近人的手工操作。与此对应的是鼠标右键单击,封装到自定义函数后,代码如下:

void ClickRightMouseButton(HWND hwnd, UINT x, UINT y)

{

int pos = POS(x,y);

::PostMessage(hwnd, WM_MOUSEMOVE, 0, pos);

Sleep(SLEEPTIME);

::PostMessage(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, pos); //Click Right Mouse Button

::PostMessage(hwnd, WM_RBUTTONUP, 0, pos);

}

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、键盘操作

单单只有鼠标的操作肯定是不够的,键盘的操作一般主要用于游戏客户端的快捷键的使用,比如施放技能,吃药等等。下面的代码实现键盘输入英文字符串的功能:

void TypeString(HWND hwnd, char *str)

{

while(*str)

{

::PostMessage(hwnd, WM_CHAR, *str, 0);

str++;

}

::PostMessage(hwnd,WM_KEYDOWN,VK_RETURN,0x00420001);

::PostMessage(hwnd,WM_KEYUP,VK_RETURN,0xC0420001);

}

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