一、 前言
所谓
游戏外挂,其实是一种
游戏外辅程序,它可以协助玩家自动产生
游戏动作、修改
游戏网络数据包以及修改
游戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将。虽然,现在对
游戏外挂程序的“合法”身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧。
不管
游戏外挂程序是不是“合法”身份,但是它却是具有一定的
技术含量的,在这些小小程序中使用了许多高端
技术,如拦截Sock
技术、拦截API
技术、模拟键盘与鼠标
技术、直接修改程序内存
技术等等。本文将对常见的
游戏外挂中使用的
技术进行全面剖析。
二、认识外挂
游戏外挂的历史可以追溯到单机版
游戏时代,只不过当时它使用了另一个更通俗易懂的名字??
游戏修改器。它可以在
游戏中追踪锁定
游戏主人公的各项能力数值。这样玩家在
游戏中可以达到主角不掉血、不耗费魔法、不消耗金钱等目的。这样降低了
游戏的难度,使得玩家更容易通关。
随着网络
游戏的时代的来临,
游戏外挂在原有的功能之上进行了新的发展,它变得更加多种多样,功能更加强大,操作更加简单,以至有些
游戏的外挂已经成为一个体系,比如《石器时代》,外挂品种达到了几十种,自动战斗、自动行走、自动练级、自动补血、加速、不遇敌、原地遇敌、快速增加经验值、按键精灵……几乎无所不包。
游戏外挂的设计主要是针对于某个
游戏开发的,我们可以根据它针对的
游戏的类型可大致可将外挂分为两种大类。
一类是将
游戏中大量繁琐和无聊的攻击动作使用外挂自动完成,以帮助玩家轻松搞定攻击对象并可以快速的增加玩家的经验值。比如在《龙族》中有一种工作的设定,玩家的工作等级越高,就可以驾驭越好的装备。但是增加工作等级却不是一件有趣的事情,毋宁说是重复枯燥的机械劳动。如果你想做法师用的杖,首先需要做基本工作--?砍树。砍树的方法很简单,在一棵大树前不停的点鼠标就可以了,每10000的经验升一级。这就意味着玩家要在大树前不停的点击鼠标,这种无聊的事情通过"按键精灵"就可以解决。外挂的"按键精灵"功能可以让玩家摆脱无趣的点击鼠标的工作。
另一类是由外挂程序产生欺骗性的网络
游戏封包,并将这些封包发送到网络
游戏服务器,利用这些虚假信息欺骗服务器进行
游戏数值的修改,达到修改角色能力数值的目的。这类外挂程序针对性很强,一般在设计时都是针对某个
游戏某个版本来做的,因为每个网络
游戏服务器与客户端交流的数据包各不相同,外挂程序必须要对欺骗的网络
游戏服务器的数据包进行分析,才能产生服务器识别的数据包。这类外挂程序也是当前最流利的一类
游戏外挂程序。
另外,现在很多外挂程序功能强大,不仅实现了自动动作代理和封包功能,而且还提供了对网络
游戏的客户端程序的数据进行修改,以达到欺骗网络
游戏服务器的目的。我相信,随着网络
游戏商家的反外挂
技术的进展,
游戏外挂将会产生更多更优秀的
技术,让我们期待着看场
技术大战吧......
三、外挂
技术综述
可以将开发
游戏外挂程序的过程大体上划分为两个部分:
前期部分工作是对外挂的主体
游戏进行分析,不同类型的外挂分析主体
游戏的内容也不相同。如外挂为上述谈到的外挂类型中的第一类时,其分析过程常是针对
游戏的场景中的攻击对象的位置和分布情况进行分析,以实现外挂自动进行攻击以及位置移动。如外挂为外挂类型中的第二类时,其分析过程常是针对
游戏服务器与客户端之间通讯包数据的结构、内容以及加密算法的分析。因网络
游戏公司一般都不会公布其
游戏产品的通讯包数据的结构、内容和加密算法的信息,所以对于开发第二类外挂成功的关键在于是否能正确分析
游戏包数据的结构、内容以及加密算法,虽然可以使用一些工具辅助分析,但是这还是一种坚苦而复杂的工作。
后期部分工作主要是根据前期对
游戏的分析结果,使用大量的程序开发
技术编写外挂程序以实现对
游戏的控制或修改。如外挂程序为第一类外挂时,通常会使用到鼠标模拟
技术来实现
游戏角色的自动位置移动,使用键盘模拟
技术来实现
游戏角色的自动攻击。如外挂程序为第二类外挂时,通常会使用到挡截Sock和挡截API函数
技术,以挡截
游戏服务器传来的网络数据包并将数据包修改后封包后传给
游戏服务器。另外,还有许多外挂使用对
游戏客户端程序内存数据修改
技术以及
游戏加速
技术。
本文主要是针对开发
游戏外挂程序后期使用的程序开发
技术进行探讨,重点介绍的如下几种在
游戏外挂中常使用的程序开发
技术:
● 动作模拟
技术:主要包括键盘模拟
技术和鼠标模拟
技术。
● 封包
技术:主要包括挡截Sock
技术和挡截API
技术。
四、动作模拟
技术 我们在前面介绍过,几乎所有的
游戏都有大量繁琐和无聊的攻击动作以增加玩家的功力,还有那些数不完的迷宫,这些好像已经成为了角色
游戏的代名词。现在,外挂可以帮助玩家从这些繁琐而无聊的工作中摆脱出来,专注于
游戏情节的进展。外挂程序为了实现自动角色位置移动和自动攻击等功能,需要使用到键盘模拟
技术和鼠标模拟
技术。下面我们将重点介绍这些
技术并编写一个简单的实例帮助读者理解动作模拟
技术的实现过程。
1. 鼠标模拟
技术 几乎所有的
游戏中都使用了鼠标来改变角色的位置和方向,玩家仅用一个小小的鼠标,就可以使角色畅游天下。那么,我们如何实现在没有玩家的参与下角色也可以自动行走呢。其实实现这个并不难,仅仅几个
Windows API函数就可以搞定,让我们先来认识认识这些API函数。
(1) 模拟鼠标动作API函数mouse_event,它可以实现模拟鼠标按下和放开等动作。
VOID mouse_event(
DWORD dwFlags, // 鼠标动作标识。
DWORD dx, // 鼠标水平方向位置。
DWORD dy, // 鼠标垂直方向位置。
DWORD dwData, // 鼠标轮子转动的数量。
DWORD dwExtraInfo // 一个关联鼠标动作辅加信息。
);
其中,dwFlags表示了各种各样的鼠标动作和点击活动,它的常用取值如下:
MOUSEEVENTF_MOVE 表示模拟鼠标移动事件。
MOUSEEVENTF_LEFTDOWN 表示模拟按下鼠标左键。
MOUSEEVENTF_LEFTUP 表示模拟放开鼠标左键。
MOUSEEVENTF_RIGHTDOWN 表示模拟按下鼠标右键。
MOUSEEVENTF_RIGHTUP 表示模拟放开鼠标右键。
MOUSEEVENTF_MIDDLEDOWN 表示模拟按下鼠标中键。
MOUSEEVENTF_MIDDLEUP 表示模拟放开鼠标中键。
(2)、设置和获取当前鼠标位置的API函数。获取当前鼠标位置使用GetCursorPos()函数,设置当前鼠标位置使用SetCursorPos()函数。
BOOL GetCursorPos(
LPPOINT lpPoint // 返回鼠标的当前位置。
);
BOOL SetCursorPos(
int X, // 鼠标的水平方向位置。
int Y //鼠标的垂直方向位置。
);
通常
游戏角色的行走都是通过鼠标移动至目的地,然后按一下鼠标的按钮就搞定了。下面我们使用上面介绍的API函数来模拟角色行走过程。
CPoint oldPoint,newPoint;
GetCursorPos(&oldPoint); //保存当前鼠标位置。
newPoint.x = oldPoint.x+40;
newPoint.y = oldPoint.y+10;
SetCursorPos(newPoint.x,newPoint.y); //设置目的地位置。
mouse_event(MOUSEEVENTF_RIGHTDOWN,0,0,0,0);//模拟按下鼠标右键。
mouse_event(MOUSEEVENTF_RIGHTUP,0,0,0,0);//模拟放开鼠标右键。
2. 键盘模拟
技术 在很多
游戏中,不仅提供了鼠标的操作,而且还提供了键盘的操作,在对攻击对象进行攻击时还可以使用快捷键。为了使这些攻击过程能够自动进行,外挂程序需要使用键盘模拟
技术。像鼠标模拟
技术一样,
Windows API也提供了一系列API函数来完成对键盘动作的模拟。
模拟键盘动作API函数keydb_event,它可以模拟对键盘上的某个或某些键进行按下或放开的动作。
VOID keybd_event(
BYTE bVk, // 虚拟键值。
BYTE bScan, // 硬件扫描码。
DWORD dwFlags, // 动作标识。
DWORD dwExtraInfo // 与键盘动作关联的辅加信息。
);
其中,bVk表示虚拟键值,其实它是一个BYTE类型值的宏,其取值范围为1-254。有关虚拟键值表请在MSDN上使用关键字“Virtual-Key Codes”查找相关资料。bScan表示当键盘上某键被按下和放开时,键盘系统硬件产生的扫描码,我们可以MapVirtualKey()函数在虚拟键值与扫描码之间进行转换。dwFlags表示各种各样的键盘动作,它有两种取值:KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP。
下面我们使用一段代码实现在
游戏中按下Shift+R快捷键对攻击对象进行攻击。
keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),0,0); //按下CTRL键。
keybd_event(0x52,MapVirtualKey(0x52,0),0,0);//键下R键。
keybd_event(0x52,MapVirtualKey(0x52,0), KEYEVENTF_KEYUP,0);//放开R键。
keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),
KEYEVENTF_KEYUP,0);//放开CTRL键。
3. 激活外挂
上面介绍的鼠标和键盘模拟
技术实现了对
游戏角色的动作部分的模拟,但要想外挂能工作于
游戏之上,还需要将其与
游戏的场景窗口联系起来或者使用一个激活键,就象按键精灵的那个激活键一样。我们可以用GetWindow函数来枚举窗口,也可以用Findwindow函数来查找特定的窗口。另外还有一个FindWindowEx函数可以找到窗口的子窗口,当
游戏切换场景的时候我们可以用FindWindowEx来确定一些当前窗口的特征,从而判断是否还在这个场景,方法很多了,比如可以GetWindowInfo来确定一些东西,比如当查找不到某个按钮的时候就说明
游戏场景已经切换了等等办法。当使用激活键进行关联,需要使用Hook
技术开发一个全局键盘钩子,在这里就不具体介绍全局钩子的开发过程了,在后面的实例中我们将会使用到全局钩子,到时将学习到全局钩子的相关知识。
4. 实例实现
通过上面的学习,我们已经基本具备了编写动作式
游戏外挂的能力了。下面我们将创建一个画笔程序外挂,它实现自动移动画笔字光标的位置并写下一个红色的“R”字。以这个实例为基础,加入相应的
游戏动作规则,就可以实现一个完整的
游戏外挂。这里作者不想使用某个
游戏作为例子来开发外挂(因没有
游戏商家的授权啊!),如读者感兴趣的话可以找一个
游戏试试,最好仅做测试
技术用。
首先,我们需要编写一个全局钩子,使用它来激活外挂,激活键为F10。创建全局钩子步骤如下:
(1).选择MFC AppWizard(DLL)创建项目ActiveKey,并选择MFC Extension DLL(共享MFC拷贝)类型。
(2).插入新文件ActiveKey.h,在其中输入如下代码:
#ifndef _KEYDLL_H
#define _KEYDLL_H
class AFX_EXT_CLASS CKeyHook:public CObject
{
public:
CKeyHook();
~CKeyHook();
HHOOK Start(); //安装钩子
BOOL Stop(); //卸载钩子
};
#endif
(3).在ActiveKey.cpp文件中加入声明"#include ActiveKey.h"。
(4).在ActiveKey.cpp文件中加入共享数据段,代码如下:
//Shared data section
#pragma data_seg("sharedata")
HHOOK glhHook=NULL; //钩子句柄。
HINSTANCE glhInstance=NULL; //DLL实例句柄。
#pragma data_seg()
(5).在ActiveKey.def文件中设置共享数据段属性,代码如下:
SETCTIONS
shareddata READ WRITE SHARED
(6).在ActiveKey.cpp文件中加入CkeyHook类的实现代码和钩子函数代码:
//键盘钩子处理函数。
extern "C" LRESULT WINAPI KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if( nCode >= 0 )
{
if( wParam == 0X79 )//当按下F10键时,激活外挂。
{
//外挂实现代码。
CPoint newPoint,oldPoint;
GetCursorPos(&oldPoint);
newPoint.x = oldPoint.x+40;
newPoint.y = oldPoint.y+10;
SetCursorPos(newPoint.x,newPoint.y);
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);//模拟按下鼠标左键。
mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);//模拟放开鼠标左键。
keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT,0),0,0); //按下SHIFT键。
keybd_event(0x52,MapVirtualKey(0x52,0),0,0);//按下R键。
keybd_event(0x52,MapVirtualKey(0x52,0),KEYEVENTF_KEYUP,0);//放开R键。
keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT,0),KEYEVENTF_KEYUP,0);//放开SHIFT键。
SetCursorPos(oldPoint.x,oldPoint.y);
}
}
return CallNextHookEx(glhHook,nCode,wParam,lParam);
}
CKeyHook::CKeyHook(){}
CKeyHook::~CKeyHook()
{
if( glhHook )
Stop();
}
//安装全局钩子。
HHOOK CKeyHook::Start()
{
glhHook = Set
WindowsHookEx(WH_KEYBOARD,KeyboardProc,glhInstance,0);//设置键盘钩子。
return glhHook;
}
//卸载全局钩子。
BOOL CKeyHook::Stop()
{
BOOL bResult = TRUE;
if( glhHook )
bResult = Unhook
WindowsHookEx(glhHook);//卸载键盘钩子。
return bResult;
}
(7).修改DllMain函数,代码如下:
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
//如果使用lpReserved参数则删除下面这行
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("NOtePadHOOK.DLL Initializing!\n");
//扩展DLL仅初始化一次
if (!AfxInitExtensionModule(ActiveKeyDLL, hInstance))
return 0;
new CDynLinkLibrary(ActiveKeyDLL);
//把DLL加入动态MFC类库中
glhInstance = hInstance;
//插入保存DLL实例句柄
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("NotePadHOOK.DLL Terminating!\n");
//终止这个链接库前调用它
AfxTermExtensionModule(ActiveKeyDLL);
}
return 1;
}
(8).编译项目ActiveKey,生成ActiveKey.DLL和ActiveKey.lib。
接着,我们还需要创建一个外壳程序将全局钩子安装了
Windows系统中,这个外壳程序编写步骤如下:
(1).创建一个对话框模式的应用程序,项目名为Simulate。
(2).在主对话框中加入一个按钮,使用ClassWizard为其创建CLICK事件。
(3).将ActiveKey项目Debug目录下的ActiveKey.DLL和ActiveKey.lib拷贝到Simulate项目目录下。
(4).从“工程”菜单中选择“设置”,弹出Project Setting对话框,选择Link标签,在“对象/库模块”中输入ActiveKey.lib。
(5).将ActiveKey项目中的ActiveKey.h头文件加入到Simulate项目中,并在Stdafx.h中加入#include ActiveKey.h。
(6).在按钮单击事件函数输入如下代码:
void CSimulateDlg::OnButton1()
{
// TODO: Add your control notification handler code here
if( !bSetup )
{
m_hook.Start();//激活全局钩子。
}
else
{
m_hook.Stop();//撤消全局钩子。
}
bSetup = !bSetup;
}
(7).编译项目,并运行程序,单击按钮激活外挂。
(8).启动画笔程序,选择文本工具并将笔的颜色设置为红色,将鼠标放在任意位置后,按F10键,画笔程序自动移动鼠标并写下一个红色的大写R。图一展示了按F10键前的画笔程序的状态,图二展示了按F10键后的画笔程序的状态。
![](http://www.cgfront.com/web/uploads/151.jpg)
图一:按F10前状态(001.jpg)
![](http://www.cgfront.com/web/uploads/152.jpg)
图二:按F10后状态(002.jpg)