以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- 游戏外挂的编写原理 (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=70388) |
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:04:00 AM -- 游戏外挂的编写原理 一、 前言
所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作、修
戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将。虽然,现
身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧。
不管游戏外挂程序是不是“合法”身份,但是它却是具有一定的技术含量的,在这
技术,如拦截Sock技术、拦截API技术、模拟键盘与鼠标技术、直接修改程序内存技术
中使用的技术进行全面剖析。
二、认识外挂
游戏外挂的历史可以追溯到单机版游戏时代,只不过当时它使用了另一个更通俗易
以在游戏中追踪锁定游戏主人公的各项能力数值。这样玩家在游戏中可以达到主角不掉
等目的。这样降低了游戏的难度,使得玩家更容易通关。
随着网络游戏的时代的来临,游戏外挂在原有的功能之上进行了新的发展,它变得
,操作更加简单,以至有些游戏的外挂已经成为一个体系,比如《石器时代》,外挂品
自动行走、自动练级、自动补血、加速、不遇敌、原地遇敌、快速增加经验值、按键精
游戏外挂的设计主要是针对于某个游戏开发的,我们可以根据它针对的游戏的类型
。
一类是将游戏中大量繁琐和无聊的攻击动作使用外挂自动完成,以帮助玩家轻松搞
玩家的经验值。比如在《龙族》中有一种工作的设定,玩家的工作等级越高,就可以驾
等级却不是一件有趣的事情,毋宁说是重复枯燥的机械劳动。如果你想做法师用的杖,
砍树的方法很简单,在一棵大树前不停的点鼠标就可以了,每10000的经验升一级。这
点击鼠标,这种无聊的事情通过"按键精灵"就可以解决。外挂的"按键精灵"功能可以让
作。
另一类是由外挂程序产生欺骗性的网络游戏封包,并将这些封包发送到网络游戏服
服务器进行游戏数值的修改,达到修改角色能力数值的目的。这类外挂程序针对性很
游戏某个版本来做的,因为每个网络游戏服务器与客户端交流的数据包各不相同,外挂
服务器的数据包进行分析,才能产生服务器识别的数据包。这类外挂程序也是当前最流
另外,现在很多外挂程序功能强大,不仅实现了自动动作代理和封包功能,而且还
序的数据进行修改,以达到欺骗网络游戏服务器的目的。我相信,随着网络游戏商家的
将会产生更多更优秀的技术,让我们期待着看场技术大战吧......
三、外挂技术综述
可以将开发游戏外挂程序的过程大体上划分为两个部分:
前期部分工作是对外挂的主体游戏进行分析,不同类型的外挂分析主体游戏的内容
的外挂类型中的第一类时,其分析过程常是针对游戏的场景中的攻击对象的位置和分布
动进行攻击以及位置移动。如外挂为外挂类型中的第二类时,其分析过程常是针对游戏
据的结构、内容以及加密算法的分析。因网络游戏公司一般都不会公布其游戏产品的通
算法的信息,所以对于开发第二类外挂成功的关键在于是否能正确分析游戏包数据的结
可以使用一些工具辅助分析,但是这还是一种坚苦而复杂的工作。
后期部分工作主要是根据前期对游戏的分析结果,使用大量的程序开发技术编写外
修改。如外挂程序为第一类外挂时,通常会使用到鼠标模拟技术来实现游戏角色的自动
来实现游戏角色的自动攻击。如外挂程序为第二类外挂时,通常会使用到挡截Sock和挡
务器传来的网络数据包并将数据包修改后封包后传给游戏服务器。另外,还有许多外挂
据修改技术以及游戏加速技术。
本文主要是针对开发游戏外挂程序后期使用的程序开发技术进行探讨,重点介绍的
的程序开发技术:
● 动作模拟技术:主要包括键盘模拟技术和鼠标模拟技术。
● 封包技术:主要包括挡截Sock技术和挡截API技术。
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:04:00 AM -- 四、动作模拟技术
我们在前面介绍过,几乎所有的游戏都有大量繁琐和无聊的攻击动作以增加玩家的
,这些好像已经成为了角色游戏的代名词。现在,外挂可以帮助玩家从这些繁琐而无聊
戏情节的进展。外挂程序为了实现自动角色位置移动和自动攻击等功能,需要使用到键
下面我们将重点介绍这些技术并编写一个简单的实例帮助读者理解动作模拟技术的实现
1. 鼠标模拟技术
那么,我们如何实现在没有玩家的参与下角色也可以自动行走呢。其实实现这个并不
可以搞定,让我们先来认识认识这些API函数。
(1) 模拟鼠标动作API函数mouse_event,它可以实现模拟鼠标按下和放开等动作。
VOID mouse_event(
其中,dwFlags表示了各种各样的鼠标动作和点击活动,它的常用取值如下:
MOUSEEVENTF_MOVE 表示模拟鼠标移动事件。
MOUSEEVENTF_LEFTDOWN 表示模拟按下鼠标左键。
MOUSEEVENTF_LEFTUP 表示模拟放开鼠标左键。
MOUSEEVENTF_RIGHTDOWN 表示模拟按下鼠标右键。
MOUSEEVENTF_RIGHTUP 表示模拟放开鼠标右键。
MOUSEEVENTF_MIDDLEDOWN 表示模拟按下鼠标中键。
MOUSEEVENTF_MIDDLEUP 表示模拟放开鼠标中键。
(2)、设置和获取当前鼠标位置的API函数。获取当前鼠标位置使用GetCursorPos()
SetCursorPos()函数。
BOOL GetCursorPos(
通常游戏角色的行走都是通过鼠标移动至目的地,然后按一下鼠标的按钮就搞定
函数来模拟角色行走过程。
CPoint oldPoint,newPoint;
2. 键盘模拟技术
在很多游戏中,不仅提供了鼠标的操作,而且还提供了键盘的操作,在对攻击对象
。为了使这些攻击过程能够自动进行,外挂程序需要使用键盘模拟技术。像鼠标模拟技
一系列API函数来完成对键盘动作的模拟。
模拟键盘动作API函数keydb_event,它可以模拟对键盘上的某个或某些键进行按下
VOID keybd_event(
其中,bVk表示虚拟键值,其实它是一个BYTE类型值的宏,其取值范围为1-254。有
关键字“Virtual-Key Codes”查找相关资料。bScan表示当键盘上某键被按下和放开
,我们可以MapVirtualKey()函数在虚拟键值与扫描码之间进行转换。dwFlags表示各种
值:KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP。
下面我们使用一段代码实现在游戏中按下Shift+R快捷键对攻击对象进行攻击。
keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),0,0); //按下CTRL
3. 激活外挂
上面介绍的鼠标和键盘模拟技术实现了对游戏角色的动作部分的模拟,但要想外挂
其与游戏的场景窗口联系起来或者使用一个激活键,就象按键精灵的那个激活键一样。
举窗口,也可以用Findwindow函数来查找特定的窗口。另外还有一个FindWindowEx函数
戏切换场景的时候我们可以用FindWindowEx来确定一些当前窗口的特征,从而判断是否
比如可以GetWindowInfo来确定一些东西,比如当查找不到某个按钮的时候就说明游戏
用激活键进行关联,需要使用Hook技术开发一个全局键盘钩子,在这里就不具体介绍全
的实例中我们将会使用到全局钩子,到时将学习到全局钩子的相关知识。
4. 实例实现
通过上面的学习,我们已经基本具备了编写动作式游戏外挂的能力了。下面我们将
现自动移动画笔字光标的位置并写下一个红色的“R”字。以这个实例为基础,加入相
一个完整的游戏外挂。这里作者不想使用某个游戏作为例子来开发外挂(因没有游戏商
趣的话可以找一个游戏试试,最好仅做测试技术用。
首先,我们需要编写一个全局钩子,使用它来激活外挂,激活键为F10。创建全局
(1).选择MFC AppWizard(DLL)创建项目ActiveKey,并选择MFC Extension DLL
(2).插入新文件ActiveKey.h,在其中输入如下代码:
#ifndef _KEYDLL_H
class AFX_EXT_CLASS CKeyHook:public CObject
(3).在ActiveKey.cpp文件中加入声明"#include ActiveKey.h"。
(4).在ActiveKey.cpp文件中加入共享数据段,代码如下:
//Shared data section
(5).在ActiveKey.def文件中设置共享数据段属性,代码如下:
SETCTIONS
(6).在ActiveKey.cpp文件中加入CkeyHook类的实现代码和钩子函数代码:
//键盘钩子处理函数。
CKeyHook::CKeyHook(){}
(7).修改DllMain函数,代码如下:
extern "C" int APIENTRY
if (dwReason == DLL_PROCESS_ATTACH)
(8).编译项目ActiveKey,生成ActiveKey.DLL和ActiveKey.lib。
接着,我们还需要创建一个外壳程序将全局钩子安装了Windows系统中,这个外壳
(1).创建一个对话框模式的应用程序,项目名为Simulate。
(2).在主对话框中加入一个按钮,使用ClassWizard为其创建CLICK事件。
(3).将ActiveKey项目Debug目录下的ActiveKey.DLL和ActiveKey.lib拷贝到
(4).从“工程”菜单中选择“设置”,弹出Project Setting对话框,选择Link标
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:05:00 AM -- (5).将ActiveKey项目中的ActiveKey.h头文件加入到Simulate项目中,并在
ActiveKey.h。
(6).在按钮单击事件函数输入如下代码:
void CSimulateDlg::OnButton1()
}
(7).编译项目,并运行程序,单击按钮激活外挂。
(8).启动画笔程序,选择文本工具并将笔的颜色设置为红色,将鼠标放在任意位置
动鼠标并写下一个红色的大写R。图一展示了按F10键前的画笔程序的状态,图二展示了
通过对动作模拟技术的介绍,我们对游戏外挂有了一定程度上的认识,也学会了使
动作模拟型游戏外挂的制作。这种动作模拟型游戏外挂有一定的局限性,它仅仅只能解
么有规律、繁琐而无聊的游戏动作。但是,随着网络游戏的盛行和复杂度的增加,很多
时反馈回服务器,通过服务器对这些动作信息进行有效认证后,再向客户端发送下一步
技术将失去原有的效应。为了更好地“外挂”这些游戏,游戏外挂程序也进行了升级换
界面层的模拟推进到数据通讯层,通过封包技术在客户端挡截游戏服务器发送来的游戏
改数据包;同时还需按照游戏数据包结构创建数据包,再模拟客户端发送给游戏服务
的过程。
封包的技术是实现第二类游戏外挂的最核心的技术。封包技术涉及的知识很广泛,
WinSock、挡截API函数、挡截消息、VxD驱动程序等。在此我们也不可能在此文中将所
故选择两种在游戏外挂程序中最常用的两种方法:挡截WinSock和挡截API函数。
1. 挡截WinSock
众所周知,Winsock是Windows网络编程接口,它工作于Windows应用层,它提供与
输编程接口。在Windows系统中,使用WinSock接口为应用程序提供基于TCP/IP协议的网
Wsock32.DLL动态链接库提供的函数库来完成的。
由上说明可知,任何Windows基于TCP/IP的应用程序都必须通过WinSock接口访问网
外。由此我们可以想象一下,如果我们可以控制WinSock接口的话,那么控制游戏客户
将易如反掌。按着这个思路,下面的工作就是如何完成控制WinSock接口了。由上面的
由一个动态链接库提供的一系列函数,由这些函数实现对网络的访问。有了这层的认
制作一个类似的动态链接库来代替原WinSock接口库,在其中实现WinSock32.dll中实现
的参数个数和顺序、返回值类型都应与原库相同。在这个自制作的动态库中,可以对我
收等函数)进行挡截,放入外挂控制代码,最后还继续调用原WinSock库中提供的相应
络数据包的挡截、修改和发送等封包功能。
下面重点介绍创建挡截WinSock外挂程序的基本步骤:
(1) 创建DLL项目,选择Win32 Dynamic-Link Library,再选择An empty DLL
(2) 新建文件wsock32.h,按如下步骤输入代码:
① 加入相关变量声明:
HMODULE hModule=NULL; //模块句柄
② 定义指向原WinSock库中的所有函数地址的指针变量,因WinSock库共提供70多
择几个常用的函数列出,有关这些库函数的说明可参考MSDN相关内容。
//定义指向原WinSock库函数地址的指针变量。
(3) 新建wsock32.cpp文件,按如下步骤输入代码:
① 加入相关头文件声明:
#include <windows.h>
② 添加DllMain函数,在此函数中首先需要加载原WinSock库,并获取此库中所有
BOOL WINAPI DllMain (HANDLE hInst,ULONG ul_reason_for_call,LPVOID
③ 定义库输出函数,在此可以对我们感兴趣的函数中添加外挂控制代码,在所有
WinSock库的同名函数。部分输出函数定义代码如下:
//库输出函数定义。
(4)、新建wsock32.def配置文件,在其中加入所有库输出函数的声明,部分声明代
LIBRARY "wsock32"
......其它输出函数声明代码略。
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:06:00 AM -- (5)、从“工程”菜单中选择“设置”,弹出Project Setting对话框,选择Link标
(6)、编译项目,产生wsock32.dll库文件。
(7)、将系统目录下原wsock32.dll库文件拷贝到被外挂程序的目录下,并将其改名
wsock32.dll文件同样拷贝到被外挂程序的目录下。重新启动游戏程序,此时游戏程序
wsock32.dll文件,再通过该库文件间接调用原WinSock接口函数来实现访问网络。上面
实现过程,至于如何加入外挂控制代码,还需要外挂开发人员对游戏数据包结构、内
(这个过程将是一个艰辛的过程),再生成外挂控制代码。关于数据包分析方法和技
感兴趣可以到网上查查相关资料。
2.挡截API
挡截API技术与挡截WinSock技术在原理上很相似,但是前者比后者提供了更强大的
WinSock接口函数,而挡截API可以实现对应用程序调用的包括WinSock API函数在内的
外挂程序仅打算对WinSock的函数进行挡截的话,您可以只选择使用上小节介绍的挡截
序在功能上的扩展,它们不仅仅只提供对数据包的挡截,而且还对游戏程序中使用的
挡截,以使外挂的功能更加强大。例如,可以通过挡截相关API函数以实现对非中文游
可以使您的外挂程序无所不能了。
挡截API技术的原理核心也是使用我们自己的函数来替换掉Windows或其它DLL库提
原理相似吧。但是,其实现过程却比挡截WinSock要复杂的多,如像实现挡截Winsock过
有的库文件都写一个模拟库有点不大可能,就只说Windows API就有上千个,还有很多
以写一个模拟库代替的方式不大现实,故我们必须另谋良方。
挡截API的最终目标是使用自定义的函数代替原函数。那么,我们首先应该知道应
调用原函数。接下来,需要将应用程序中调用该原函数的指令代码进行修改,使它将调
义的函数地址。这样,外挂程序才能完全控制应用程序调用的API函数,至于在其中如
了。最后还有一个重要的问题要解决,如何将我们自定义的用来代替原API函数的函数
址空间中,因在Windows系统中应用程序仅只能访问到本进程地址空间内的代码和数
综上所述,要实现挡截API函数,至少需要解决如下三个问题:
● 如何定位游戏程序中调用API函数指令代码?
● 如何修改游戏程序中调用API函数指令代码?
● 如何将外挂代码(自定义的替换函数代码)注入到游戏程序进程地址空间?
下面我们逐一介绍这几个问题的解决方法:
(1) 、定位调用API函数指令代码
我们知道,在汇编语言中使用CALL指令来调用函数或过程的,它是通过指令参数中
数代码的。那么,我们如果能寻找到程序代码中所有调用被挡截的API函数的CALL指令
地址参数修改为替代函数的地址。虽然这是一个可行的方案,但是实现起来会很繁琐,
系统中所使用的可执行文件(PE格式)采用了输入地址表机制,将所有在程序调用的
址表中,而在程序代码CALL指令中使用的地址不是API函数的地址,而是输入地址表中
序代码中调用的API函数被代替掉,只用将输入地址表中该API函数的地址项内容修改即
机制,还需要了解一下PE格式文件结构,其中图三列出了PE格式文件的大致结构。
PE格式文件一开始是一段DOS程序,当你的程序在不支持Windows的环境中运行时,
cannot be run in DOS mode”这样的警告语句,接着这个DOS文件头,就开始真正的PE
“IMAGE_NT_HEADER”的数据,其中是许多关于整个PE文件的消息,在这段数据的尾端
据表,通过它能快速定位一些PE文件中段(section)的地址。在这段数据之后,则是
的列表,其中的每一项都详细描述了后面一个段的相关信息。接着它就是PE文件中最主
据和资源等等信息就分别存放在这些段中。
在所有的这些段里,有一个被称为“.idata”的段(输入数据段)值得我们去注
入地址表(IAT,Import Address Table)的数据列表。每个用隐式方式加载的API所在
同时一个API的地址也与IAT中一项相对应。当一个应用程序加载到内存中后,针对每一
下的汇编指令:
JMP DWORD PTR [XXXXXXXX]
或
CALL DWORD PTR [XXXXXXXX]
其中,[XXXXXXXX]表示指向了输入地址表中一个项,其内容是一个DWORD,而正是
的真正地址。因此我们要想拦截一个API的调用,只要简单的把那个DWORD改为我们自己
(2) 、修改调用API函数代码
从上面对PE文件格式的分析可知,修改调用API函数代码其实是修改被调用API函数
于Windows系统对应用程序指令代码地址空间的严密保护机制,使得修改程序指令代码
编写VxD进入Ring0。在这里,我为大家介绍一种较为方便的方法修改进程内存,它仅需
数,下面我首先来学会一下这几个API函数:
DWORD VirtualQuery(
该函数用于查询关于本进程内虚拟地址页的信息。其中,lpAddress表示被查询页
保存查询页信息的缓冲;dwLength表示缓冲区大小。返回值为实际缓冲大小。
BOOL VirtualProtect(
该函数用于改变本进程内虚拟地址页的保护属性。其中,lpAddress表示被改变保
页区域大小;flNewProtect表示新的保护属性,可取值为PAGE_READONLY、
lpflOldProtect表示用于保存改变前的保护属性。如果函数调用成功返回“T”,否则
有了这两个API函数,我们就可以随心所欲的修改进程内存了。首先,调用
页信息,再根据此信息调用VirtualProtect()函数改变这些页的保护属性为
任意修改进程内存数据了。下面一段代码演示了如何将进程虚拟地址为0x0040106c处的
BYTE* pData = 0x0040106c; |
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:06:00 AM -- (3)、注入外挂代码进入被挂游戏进程中
完成了定位和修改程序中调用API函数代码后,我们就可以随意设计自定义的API函
后,还需要将这些代码注入到被外挂游戏程序进程内存空间中,不然游戏进程根本不会
法有很多,如利用全局钩子注入、利用注册表注入挡截User32库中的API函数、利用
NT/2000)、利用BHO注入等。因为我们在动作模拟技术一节已经接触过全局钩子,我相
全局钩子的制作过程,所以我们在后面的实例中,将继续利用这个全局钩子。至于其它
参阅MSDN有关内容。
有了以上理论基础,我们下面就开始制作一个挡截MessageBoxA和recv函数的实
以此实例为框架,加入相应的替代函数和处理代码即可。此实例的开发过程如下:
(1) 打开前面创建的ActiveKey项目。
(2) 在ActiveKey.h文件中加入HOOKAPI结构,此结构用来存储被挡截API函数名
址。
typedef struct tag_HOOKAPI
(3) 打开ActiveKey.cpp文件,首先加入一个函数,用于定位输入库在输入数据段
extern "C" __declspec(dllexport)PIMAGE_IMPORT_DESCRIPTOR
>e_lfanew));
return NULL;
(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Virtu
再加入一个函数,用来定位被挡截API函数的IAT项并修改其内容为替代函数地址。
extern "C" __declspec(dllexport)
>OriginalFirstThunk));
>FirstThunk));
>u1.AddressOfData));
&mbi_thunk.Protect);
&dwOldProtect);
(4) 定义替代函数,此实例中只给MessageBoxA和recv两个API进行挡截。代码如下
static int WINAPI MessageBoxA1 (HWND hWnd , LPCTSTR lpText, LPCTSTR
(5) 在KeyboardProc函数中加入激活挡截API代码,在if( wParam == 0X79 )语句
......
|
-- 作者:卷积内核 -- 发布时间:12/12/2008 10:07:00 AM -- (6) 在ActiveKey.cpp中加入头文件声明 "#include "wsock32.h"。 从“工程”菜单中选择“设置”,弹出Project Setting对话框,选择Link标签,在“对象/库模块”中输入Ws2_32..lib。
(7) 重新编译ActiveKey项目,产生ActiveKey.dll文件,将其拷贝到Simulate.exe
六、结束语
除了以上介绍的几种游戏外挂程序常用的技术以外,在一些外挂程序中还使用了游戏数据修改技术、游戏加速技术等。在这篇文章里,就不逐一介绍了。 |
-- 作者:gtict -- 发布时间:12/31/2008 12:48:00 PM -- 能不能上传几个实例.... |
-- 作者:gtict -- 发布时间:12/31/2008 1:29:00 PM -- 谢谢了,刚做出一个 哈哈~ |
-- 作者:liuyuanyang -- 发布时间:1/16/2009 7:34:00 PM -- 非常感谢~~ 说Lua是一门写游戏脚本很好的语言 所以鄙人开了一论坛~~~ 新论坛开张啦~~ 欢迎大家来光临~~~ 纯技术交流社区~~~ Lua PHP Linux C C++ …… 欢迎各位大侠小虾来捧场~~~~~ |
-- 作者:秋十三 -- 发布时间:1/21/2009 12:02:00 AM -- 哦 版主好强啊 我顶 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
109.375ms |