﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-★Daniel's Blog★-文章分类-游戏外挂</title><link>http://www.blogjava.net/Daniel2005/category/23822.html</link><description>URL:http://www.blogjava.net/Daniel2005</description><language>zh-cn</language><lastBuildDate>Wed, 04 Jul 2007 11:03:46 GMT</lastBuildDate><pubDate>Wed, 04 Jul 2007 11:03:46 GMT</pubDate><ttl>60</ttl><item><title>讨论VB实现网络游戏外挂的方法</title><link>http://www.blogjava.net/Daniel2005/articles/127885.html</link><dc:creator>泌鲁沙夫</dc:creator><author>泌鲁沙夫</author><pubDate>Tue, 03 Jul 2007 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/Daniel2005/articles/127885.html</guid><wfw:comment>http://www.blogjava.net/Daniel2005/comments/127885.html</wfw:comment><comments>http://www.blogjava.net/Daniel2005/articles/127885.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Daniel2005/comments/commentRss/127885.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Daniel2005/services/trackbacks/127885.html</trackback:ping><description><![CDATA[<p>这段时间似乎很多朋友在问如何用VB做外挂。<br><br>在讨论这个问题前，我们先把外挂分类。<br><br>按是否需要游戏客户端分为 内挂 和 脱机（这是我的称呼，你可以用别的名词称呼）<br>内挂又可以按照修改游戏的方法分成 模拟操作型 、 修改内存型 、 封包型 。<br><br>===================================================<br><br>脱机的不需要特别说明，利用 Mircosoft Winsock Control 6.0 可以实现功能相当强大的脱机客户端，在这方面VB相对于其他编程语言没有明显的劣势，甚至是优势。<br>对于内挂型的~<br><br>一、 模拟按键型<br>因为在VB中嵌入API已经不是什么难事，所以VB6应用程序也可以方便的调用<br>keybd_event<br>mouse_event<br>来实现键盘和鼠标的模拟。在WindowsNT上，这两个函数是不被推荐使用的可以使用SendInput代替~但是SendInput在VB的API浏览器没有包含~<br>二、 修改内存<br><br>修改目标游戏内存，类似于FPE，GM之类的软件，但是修改的目标确是不同，一般上说FPE等单机游戏内存修改器主要是修改数据区内容，而网络游戏修改内存外挂主要是修改程序指令~<br><br>具体要使用到的API是<br>WriteProcessMemory<br>ReadProcessMemoryF<br>OpenProcess<br>CloseHandle<br><br>第一个被调用的API是OpenProcess，第一个参数dwDesiredAccess 使用的常量在VB中是没有声明能够的。在winnt.h（4318）的定义如下<br>#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)<br>用这个值做参数调用OpenProcess得到的操作权将是最大的，同时破坏性也最大，使用不当容易使游戏进程DOWN掉。所以我个人推荐使用：<br>#define PROCESS_VM_READ (0x0010)&nbsp;&nbsp;<br>#define PROCESS_VM_WRITE (0x0020)<br>分别对应ReadProcessMemory/WriteProcessMemory<br><br>第二个参数一般做0 意义是 是否让自进程继承这个句柄<br><br>第三个参数就是目标进程ID，进程ID可以通过FindWindow得到句柄后调GetWindowThreadProcessId得到<br><br><br>打开进程，获得进程句柄后，就可以利用ReadProcessMemory/WriteProcessMemory来读写游戏进程数据了~<br><br>记住使用完成后，及时调用CloseHandle来释放句柄，不然你的程序运行一段时间后就会出错～<br><br>三、 封包型<br><br>封包型也可以分为两种：<br>1）代理型<br>2）hook winsock api型<br><br>第一种主要就是在本机虚拟一个游戏服务器，让游戏的数据包先发给你的程序，有你处理后再发往真实的游戏服务器，这种方法简单灵活，但是，目前绝大多数的网络游戏都对这型外挂有ANTI机制。（一下不知道该用什么词 ：） ）<br><br><br>HOOKAPI型，一直是VB外挂程序的禁区，因为目前所使用的大多数方法，都需要建立一个DLL EJECT到目标进程中，而VB建立的DLL是不能满足要求的~<br><br>下面来说重点吧~（至少我这么认为）<br><br>WIN32API中有这么一套API，叫做调试API.<br><br>先是DebugActiveProcess，<br>BOOL DebugActiveProcess(<br>DWORD dwProcessId&nbsp;&nbsp;&nbsp;// process to be debugged<br>);<br>参数就一个就是目标进程的ID，可以用我前面说的方法来得到。<br><br>当开始调试一个进程后，就可以使用WaitForDebugEvent，<br>BOOL WaitForDebugEvent(<br>LPDEBUG_EVENT lpDebugEvent,&nbsp;&nbsp;// pointer to debug event structure<br>DWORD dwMilliseconds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// milliseconds to wait for event<br>);<br>来等待DEBUG事件了~<br>DEBUG_EVENT的结构定义是这样的：<br>*************************************************************<br>typedef struct _DEBUG_EVENT { // de <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD dwDebugEventCode; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD dwProcessId; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD dwThreadId; <br>&nbsp;&nbsp;&nbsp;&nbsp;union { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXCEPTION_DEBUG_INFO Exception; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CREATE_THREAD_DEBUG_INFO CreateThread; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CREATE_PROCESS_DEBUG_INFO CreateProcessInfo; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXIT_THREAD_DEBUG_INFO ExitThread; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXIT_PROCESS_DEBUG_INFO ExitProcess; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOAD_DLL_DEBUG_INFO LoadDll; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UNLOAD_DLL_DEBUG_INFO UnloadDll; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OUTPUT_DEBUG_STRING_INFO DebugString; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RIP_INFO RipInfo; <br>&nbsp;&nbsp;&nbsp;&nbsp;} u; <br>} DEBUG_EVENT; <br><br>typedef struct _EXCEPTION_RECORD { // exr <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD ExceptionCode; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD ExceptionFlags; <br>&nbsp;&nbsp;&nbsp;&nbsp;struct _EXCEPTION_RECORD *ExceptionRecord; <br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID ExceptionAddress; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD NumberParameters; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD ExceptionInformation［EXCEPTION_MAXIMUM_PARAMETERS］; <br>} EXCEPTION_RECORD; <br><br>typedef struct _EXCEPTION_DEBUG_INFO { // exdi <br>&nbsp;&nbsp;&nbsp;&nbsp;EXCEPTION_RECORD ExceptionRecord; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD dwFirstChance; <br>} EXCEPTION_DEBUG_INFO; <br>*************************************************************<br>在众多事件中，我们关心的只有EXCEPTION_DEBUG_EVENT，当dwDebugEventCode==EXCEPTION_DEBUG_EVENT时，U的结构展开是这样的！<br><br>ExceptionCode表明了DEBUG事件产生的原因；可能的值中，需要我们关心的只有EXCEPTION_BREAKPOINT。<br><br>当目标执行到指令INT3时就会触发上面的EXCEPTION_BREAKPOINT时间，所以，我们大可以在SEND/RECV等API入口处放一个INT3指令，<br>当游戏调用该API时就触发了一个调试事件，进程被挂起，然后通知调试进程，这个时候，我们就可以从游戏程序的堆栈中读取参数，<br>甚至修改~~<br><br>最后，做了一些必要的出来后记得调用ContinueDebugEvent来继续游戏程序的执行~<br></p>
<img src ="http://www.blogjava.net/Daniel2005/aggbug/127885.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Daniel2005/" target="_blank">泌鲁沙夫</a> 2007-07-03 16:36 <a href="http://www.blogjava.net/Daniel2005/articles/127885.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用VB怎样编写游戏外挂 </title><link>http://www.blogjava.net/Daniel2005/articles/127883.html</link><dc:creator>泌鲁沙夫</dc:creator><author>泌鲁沙夫</author><pubDate>Tue, 03 Jul 2007 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/Daniel2005/articles/127883.html</guid><wfw:comment>http://www.blogjava.net/Daniel2005/comments/127883.html</wfw:comment><comments>http://www.blogjava.net/Daniel2005/articles/127883.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Daniel2005/comments/commentRss/127883.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Daniel2005/services/trackbacks/127883.html</trackback:ping><description><![CDATA[一、 前言　　<br><span>&nbsp; 所谓<strong onmouseover='isShowAds = true;isShowAds2 = true;ads.Move(this,"http://rad.17luntan.com/UploadImage/5/633178659760468750.jpg","%u62CD%u62CD%u6380%u8D77%u70B9%u5361%u964D%u4EF7%u98CE%u6F6E%u3002%u81EA%u52A8%u53D1%u8D27%u4EA4%u6613%uFF0C%u65B9%u4FBF%u5FEB%u6377%u3002","48411","游戏","%u6E38%u620F%u70B9%u5361","http%3A//game.paipai.com/sale/auto.shtml%3FADTAG%3D192.1.1", event)' style="FONT-WEIGHT: normal; CURSOR: hand; COLOR: #0000ff; TEXT-DECORATION: underline" onclick='javascript:window.open("http://s2.17luntan.com/ClickPortal/WebClick.aspx?id=48411&amp;k=%u6E38%u620F&amp;siteid=pw8d188b829e5e1930768d2a2dbb1e73c5&amp;url=http%3A//bbs.gingili.cn/simple/index.php%3Ft586.html&amp;gourl=http%3A//game.paipai.com/sale/auto.shtml%3FADTAG%3D192.1.1&amp;parm=DF83958F01AFE9E443649640FCD80070517A1BF0585BB5AB&amp;alliedsiteid=5366");' onmouseout="isShowAds = false;isShowAds2 = false">游戏</strong>外挂，其实是一种游戏外辅程序，它可以协助玩家自动产生游戏动作、修</span><br>改游戏网络数据包以及修改游戏内存数据等，以实现玩家用最少的时间和金钱去完成功力升级和过关斩将。虽然，现在对游戏外挂程序的&#8220;合法&#8221;身份众说纷纭，在这里我不想对此发表任何个人意见，让时间去说明一切吧。　　<br>&nbsp; 不管游戏外挂程序是不是&#8220;合法&#8221;身份，但是它却是具有一定的技术含量的，在这<br><span><span>些小小程序中使用了许多高端技术，如拦截Sock技术、拦截API技术、模拟<strong onmouseover='isShowAds = true;isShowAds2 = true;ads.Move(this,"http://rad.17luntan.com/UploadImage/5/633179327219843750.gif","%u5168%u65B0%u9065%u63A7%u738B%u8D85%u7EA7PC%u65E0%u7EBF%u952E%u76D8%uFF01","50347","键盘","%u952E%u76D8","http%3A//shop.paipai.com/124885451%3FADTAG%3D192.1.1", event)' style="FONT-WEIGHT: normal; CURSOR: hand; COLOR: #0000ff; TEXT-DECORATION: underline" onclick='javascript:window.open("http://s2.17luntan.com/ClickPortal/WebClick.aspx?id=50347&amp;k=%u952E%u76D8&amp;siteid=pw8d188b829e5e1930768d2a2dbb1e73c5&amp;url=http%3A//bbs.gingili.cn/simple/index.php%3Ft586.html&amp;gourl=http%3A//shop.paipai.com/124885451%3FADTAG%3D192.1.1&amp;parm=DF83958F01AFE9E443649640FCD80070517A1BF0585BB5AB&amp;alliedsiteid=5366");' onmouseout="isShowAds = false;isShowAds2 = false">键盘</strong>与</span><strong onmouseover='isShowAds = true;isShowAds2 = true;ads.Move(this,"http://rad.17luntan.com/UploadImage/5/633179324972968750.gif","%u7CBE%u81F4%u7684%u4EFF%u6C34%u6676%u5916%u58F3%uFF0C%u65B0%u9896%u72EC%u7279%u7684%u9020%u578B%uFF01","50281","鼠标","%u9F20%u6807","http%3A//shop.paipai.com/33924562%3FADTAG%3D192.1.1", event)' style="FONT-WEIGHT: normal; CURSOR: hand; COLOR: #0000ff; TEXT-DECORATION: underline" onclick='javascript:window.open("http://s2.17luntan.com/ClickPortal/WebClick.aspx?id=50281&amp;k=%u9F20%u6807&amp;siteid=pw8d188b829e5e1930768d2a2dbb1e73c5&amp;url=http%3A//bbs.gingili.cn/simple/index.php%3Ft586.html&amp;gourl=http%3A//shop.paipai.com/33924562%3FADTAG%3D192.1.1&amp;parm=DF83958F01AFE9E443649640FCD80070517A1BF0585BB5AB&amp;alliedsiteid=5366");' onmouseout="isShowAds = false;isShowAds2 = false">鼠标</strong>技术、直接修改程序内存技术</span><br>等等。本文将对常见的游戏外挂中使用的技术进行全面剖析。<br>　　二、认识外挂<br>　　游戏外挂的历史可以追溯到单机版游戏时代，只不过当时它使用了另一个更通俗易<br>懂的名字??游戏修改器。它可以在游戏中追踪锁定游戏主人公的各项能力数值。这样玩家在游戏中可以达到主角不掉血、不耗费魔法、不消耗金钱等目的。这样降低了游戏的难度，使得玩家更容易通关。<br><span>　　随着<strong onmouseover='isShowAds = true;isShowAds2 = true;ads.Move(this,"http://rad.17luntan.com/UploadImage/5/633178659760468750.jpg","%u62CD%u62CD%u6380%u8D77%u70B9%u5361%u964D%u4EF7%u98CE%u6F6E%u3002%u81EA%u52A8%u53D1%u8D27%u4EA4%u6613%uFF0C%u65B9%u4FBF%u5FEB%u6377%u3002","48444","网络游戏","%u6E38%u620F%u70B9%u5361","http%3A//game.paipai.com/sale/auto.shtml%3FADTAG%3D192.1.1", event)' style="FONT-WEIGHT: normal; CURSOR: hand; COLOR: #0000ff; TEXT-DECORATION: underline" onclick='javascript:window.open("http://s2.17luntan.com/ClickPortal/WebClick.aspx?id=48444&amp;k=%u7F51%u7EDC%u6E38%u620F&amp;siteid=pw8d188b829e5e1930768d2a2dbb1e73c5&amp;url=http%3A//bbs.gingili.cn/simple/index.php%3Ft586.html&amp;gourl=http%3A//game.paipai.com/sale/auto.shtml%3FADTAG%3D192.1.1&amp;parm=DF83958F01AFE9E443649640FCD80070517A1BF0585BB5AB&amp;alliedsiteid=5366");' onmouseout="isShowAds = false;isShowAds2 = false">网络游戏</strong>的时代的来临，游戏外挂在原有的功能之上进行了新的发展，它变得</span><br>更加多种多样，功能更加强大，操作更加简单，以至有些游戏的外挂已经成为一个体系，比如《石器时代》，外挂品种达到了几十种，自动战斗、自动行走、自动练级、自动补血、加速、不遇敌、原地遇敌、快速增加经验值、按键精灵&#8230;&#8230;几乎无所不包。<br>　　游戏外挂的设计主要是针对于某个游戏开发的，我们可以根据它针对的游戏的类型<br>可大致可将外挂分为两种大类。<br>　　一类是将游戏中大量繁琐和无聊的攻击动作使用外挂自动完成，以帮助玩家轻松搞<br>定攻击对象并可以快速的增加玩家的经验值。比如在《龙族》中有一种工作的设定，玩家的工作等级越高，就可以驾驭越好的装备。但是增加工作等级却不是一件有趣的事情，毋宁说是重复枯燥的机械劳动。如果你想做法师用的杖，首先需要做基本工作--?砍树。砍树的方法很简单，在一棵大树前不停的点鼠标就可以了，每10000的经验升一级。这就意味着玩家要在大树前不停的点击鼠标，这种无聊的事情通过"按键精灵"就可以解决。外挂的"按键精灵"功能可以让玩家摆脱无趣的点击鼠标的工作。<br>　　另一类是由外挂程序产生欺骗性的网络游戏封包，并将这些封包发送到网络游戏服<br><span>务器，利用这些虚假信息欺骗<strong onmouseover='isShowAds = true;isShowAds2 = true;ads.Move(this,"","%u5FAE%u8F6F%u670D%u52A1%u5668%u7AEF%u4EA7%u54C1%u5927%u5168%uFF0C%u70B9%u51FB%u83B7%u5F97%u3002","20845","服务器","%u670D%u52A1%u5668","http%3A//go.microsoft.com/%3Flinkid%3D6331218", event)' style="FONT-WEIGHT: normal; CURSOR: hand; COLOR: #0000ff; TEXT-DECORATION: underline" onclick='javascript:window.open("http://s2.17luntan.com/ClickPortal/WebClick.aspx?id=20845&amp;k=%u670D%u52A1%u5668&amp;siteid=pw8d188b829e5e1930768d2a2dbb1e73c5&amp;url=http%3A//bbs.gingili.cn/simple/index.php%3Ft586.html&amp;gourl=http%3A//go.microsoft.com/%3Flinkid%3D6331218&amp;parm=DF83958F01AFE9E443649640FCD80070517A1BF0585BB5AB&amp;alliedsiteid=5366");' onmouseout="isShowAds = false;isShowAds2 = false">服务器</strong>进行游戏数值的修改，达到修改角色能力数值的目的。这类外挂程序针对性很强，一般在设计时都是针对某个游戏某个版本来做的，因为每个网络游戏服务器与客户端交流的数据包各不相同，外挂程序必须要对欺骗的网络游戏服务器的数据包进行分析，才能产生服务器识别的数据包。这类外挂程序也是当前最流利的一类游戏外挂程序。</span><br>　　另外，现在很多外挂程序功能强大，不仅实现了自动动作代理和封包功能，而且还<br>提供了对网络游戏的客户端程序的数据进行修改，以达到欺骗网络游戏服务器的目的。我相信，随着网络游戏商家的反外挂技术的进展，游戏外挂将会产生更多更优秀的技术，让我们期待着看场技术大战吧......　　三、外挂技术综述　　可以将开发游戏外挂程序的过程大体上划分为两个部分：<br>　　前期部分工作是对外挂的主体游戏进行分析，不同类型的外挂分析主体游戏的内容<br>也不相同。如外挂为上述谈到的外挂类型中的第一类时，其分析过程常是针对游戏的场景中的攻击对象的位置和分布情况进行分析，以实现外挂自动进行攻击以及位置移动。如外挂为外挂类型中的第二类时，其分析过程常是针对游戏服务器与客户端之间通讯包数据的结构、内容以及加密算法的分析。因网络游戏公司一般都不会公布其游戏产品的通讯包数据的结构、内容和加密算法的信息，所以对于开发第二类外挂成功的关键在于是否能正确分析游戏包数据的结构、内容以及加密算法，虽然<br>可以使用一些工具辅助分析，但是这还是一种坚苦而复杂的工作。<br>　　后期部分工作主要是根据前期对游戏的分析结果，使用大量的程序开发技术编写外<br>挂程序以实现对游戏的控制或修改。如外挂程序为第一类外挂时，通常会使用到鼠标模拟技术来实现游戏角色的自动位置移动，使用键盘模拟技术来实现游戏角色的自动攻击。如外挂程序为第二类外挂时，通常会使用到挡截Sock和挡截API函数技术，以挡截游戏服务器传来的网络数据包并将数据包修改后封包后传给游戏服务器。另外，还有许多外挂使用对游戏客户端程序内存数<br>据修改技术以及游戏加速技术。<br>　　本文主要是针对开发游戏外挂程序后期使用的程序开发技术进行探讨，重点介绍的<br>如下几种在游戏外挂中常使用的程序开发技术：<br>　　● 动作模拟技术：主要包括键盘模拟技术和鼠标模拟技术。<br>　　● 封包技术：主要包括挡截Sock技术和挡截API技术。<br><br>　　四、动作模拟技术<br>　　我们在前面介绍过，几乎所有的游戏都有大量繁琐和无聊的攻击动作以增加玩家的<br>功力，还有那些数不完的迷宫，这些好像已经成为了角色游戏的代名词。现在，外挂可以帮助玩家从这些繁琐而无聊的工作中摆脱出来，专注于游戏情节的进展。外挂程序为了实现自动角色位置移动和自动攻击等功能，需要使用到键盘模拟技术和鼠标模拟技术。<br>&nbsp; 下面我们将重点介绍这些技术并编写一个简单的实例帮助读者理解动作模拟技术的实现<br>过程。<br>　　１． 鼠标模拟技术<br>　　<br>　　几乎所有的游戏中都使用了鼠标来改变角色的位置和方向，玩家仅用一个小小的鼠<br>标，就可以使角色畅游天下。<br>那么，我们如何实现在没有玩家的参与下角色也可以自动行走呢。其实实现这个并不<br>难，仅仅几个Windows API函数就可以搞定，让我们先来认识认识这些API函数。<br>　　(1) 模拟鼠标动作API函数mouse_event，它可以实现模拟鼠标按下和放开等动作。　　　　VOID mouse_event(<br>　　　　　　DWORD dwFlags, // 鼠标动作标识。<br>　　　　　　DWORD dx, // 鼠标水平方向位置。<br>　　　　　　DWORD dy, // 鼠标垂直方向位置。<br>　　　　　　DWORD dwData, // 鼠标轮子转动的数量。<br>　　　　　　DWORD dwExtraInfo // 一个关联鼠标动作辅加信息。<br>　　　　);<br>　　其中，dwFlags表示了各种各样的鼠标动作和点击活动，它的常用取值如下：　　　MOUSEEVENTF_MOVE　表示模拟鼠标移动事件。<br>　　　MOUSEEVENTF_LEFTDOWN 表示模拟按下鼠标左键。<br>　　　MOUSEEVENTF_LEFTUP 表示模拟放开鼠标左键。<br>　　　MOUSEEVENTF_RIGHTDOWN 表示模拟按下鼠标右键。　　　MOUSEEVENTF_RIGHTUP 表示模拟放开鼠标右键。<br>　　　MOUSEEVENTF_MIDDLEDOWN 表示模拟按下鼠标中键。<br>　　　MOUSEEVENTF_MIDDLEUP 表示模拟放开鼠标中键。<br>　　　(2)、设置和获取当前鼠标位置的API函数。获取当前鼠标位置使用GetCursorPos()<br>函数，设置当前鼠标位置使用SetCursorPos()函数。<br>　　　　BOOL GetCursorPos(<br>　　　　　LPPOINT　lpPoint // 返回鼠标的当前位置。<br>　　　　);<br>　　　　BOOL SetCursorPos(<br>　　　　int X, // 鼠标的水平方向位置。<br>　　　　　　int Y //鼠标的垂直方向位置。<br>　　　　);<br>　　　通常游戏角色的行走都是通过鼠标移动至目的地，然后按一下鼠标的按钮就搞定<br>了。下面我们使用上面介绍的API函数来模拟角色行走过程。<br>　　　CPoint oldPoint,newPoint;<br>　　　GetCursorPos(&amp;oldPoint); //保存当前鼠标位置。<br>　　　newPoint.x = oldPoint.x+40;<br>　　　newPoint.y = oldPoint.y+10;<br>　　　SetCursorPos(newPoint.x,newPoint.y); //设置目的地位置。<br>　　　mouse_event(MOUSEEVENTF_RIGHTDOWN,0,0,0,0);//模拟按下鼠标右键。<br>　　　mouse_event(MOUSEEVENTF_RIGHTUP,0,0,0,0);//模拟放开鼠标右键。<br>　　　2． 键盘模拟技术<br>　　　在很多游戏中，不仅提供了鼠标的操作，而且还提供了键盘的操作，在对攻击对象<br>进行攻击时还可以使用快捷键。为了使这些攻击过程能够自动进行，外挂程序需要使用键盘模拟技术。像鼠标模拟技术一样，Windows API也提供了一系列API函数来完成对键盘动作的模拟。<br>　　　模拟键盘动作API函数keydb_event，它可以模拟对键盘上的某个或某些键进行按下<br>或放开的动作。<br>　　　VOID keybd_event(<br>　　　　　BYTE bVk, // 虚拟键值。<br>　　　　　BYTE bScan, // 硬件扫描码。<br>　　　　　DWORD dwFlags, // 动作标识。<br>　　　　　DWORD dwExtraInfo // 与键盘动作关联的辅加信息。<br>　　　);<br>　　　其中，bVk表示虚拟键值，其实它是一个BYTE类型值的宏，其取值范围为1-254。有关虚拟键值表请在MSDN上使用关键字&#8220;Virtual-Key Codes&#8221;查找相关资料。bScan表示当键盘上某键被按下和放开时，键盘系统硬件产生的扫描码，我们可以MapVirtualKey()函数在虚拟键值与扫描码之间进行转换。dwFlags表示各种各样的键盘动作，它有两种取值：KEYEVENTF_EXTENDEDKEY和KEYEVENTF_KEYUP。<br>　　　下面我们使用一段代码实现在游戏中按下Shift+R快捷键对攻击对象进行攻击。　　　keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),0,0); //按下CTRL键。<br>　　　keybd_event(0x52,MapVirtualKey(0x52,0),0,0);//键下R键。<br>　　　keybd_event(0x52,MapVirtualKey(0x52,0), KEYEVENTF_KEYUP,0);//放开R键。<br>　　　keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),<br>　　　KEYEVENTF_KEYUP,0);//放开CTRL键。<br>　　　3． 激活外挂<br>　　　上面介绍的鼠标和键盘模拟技术实现了对游戏角色的动作部分的模拟，但要想外挂<br>能工作于游戏之上，还需要将其与游戏的场景窗口联系起来或者使用一个激活键，就象按键精灵的那个激活键一样。<br>　　我们可以用GetWindow函数来枚举窗口，也可以用Findwindow函数来查找特定的窗口。另外还有一个FindWindowEx函数可以找到窗口的子窗口，当游戏切换场景的时候我们可以用FindWindowEx来确定一些当前窗口的特征，从而判断是否还在这个场景，方法很多了，比如可以GetWindowInfo来确定一些东西，比如当查找不到某个按钮的时候就说明游戏场景已经切换了等等办法。当使用激活键进行关联，需要使用Hook技术开发一个全局键盘钩子，在这里就不具体介绍全<br>局钩子的开发过程了，在后面的实例中我们将会使用到全局钩子，到时将学习到全局钩子的相关知识。<br>　　4． 实例实现<br>　　通过上面的学习，我们已经基本具备了编写动作式游戏外挂的能力了。下面我们将<br>创建一个画笔程序外挂，它实现自动移动画笔字光标的位置并写下一个红色的&#8220;R&#8221;字。以这个实例为基础，加入相应的游戏动作规则，就可以实现一个完整的游戏外挂。这里作者不想使用某个游戏作为例子来开发外挂（因没有游戏商家的授权啊！），如读者感兴趣的话可以找一个游戏试试，最好仅做测试技术用。<br>　　首先，我们需要编写一个全局钩子，使用它来激活外挂，激活键为F10。创建全局<br>钩子步骤如下：<br>　　(1)．选择MFC AppWizard(DLL)创建项目ActiveKey，并选择MFC Extension DLL<br>（共享MFC拷贝）类型。<br>　　(2).插入新文件ActiveKey.h，在其中输入如下代码：<br>　　　#ifndef _KEYDLL_H<br>　　　#define _KEYDLL_H<br>　　　class AFX_EXT_CLASS CKeyHook:public CObject<br>　　　{<br>　　　　public:<br>　CKeyHook();<br>　~CKeyHook();<br>　HHOOK Start();　//安装钩子<br>　BOOL Stop(); //卸载钩子<br>　　　};<br>　　　#endif<br>　　(3).在ActiveKey.cpp文件中加入声明＂#include ActiveKey.h＂。<br>　　(4).在ActiveKey.cpp文件中加入共享数据段，代码如下：<br>　　　//Shared data section<br>　　　#pragma data_seg("sharedata")<br>　　　HHOOK glhHook=NULL; //钩子句柄。<br>　　　HINSTANCE glhInstance=NULL; //DLL实例句柄。<br>　　　#pragma data_seg()<br>　　(5).在ActiveKey.def文件中设置共享数据段属性，代码如下：<br>　　　SETCTIONS<br>　　　shareddata READ WRITE SHARED<br>　　(6).在ActiveKey.cpp文件中加入CkeyHook类的实现代码和钩子函数代码：<br>　　　//键盘钩子处理函数。<br>　　　extern "C" LRESULT WINAPI KeyboardProc(int nCode,WPARAM wParam,LPARAM<br>lParam)<br>　　　{<br>　　　if( nCode &gt;= 0 )<br>　　　{<br>　　　if( wParam == 0X79 )//当按下F10键时，激活外挂。<br>　{<br>　　//外挂实现代码。<br>CPoint newPoint,oldPoint;<br>　　 GetCursorPos(&amp;oldPoint);<br>　　 newPoint.x = oldPoint.x+40;<br>　　 newPoint.y = oldPoint.y+10;<br>　　 SetCursorPos(newPoint.x,newPoint.y);<br>　　 mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);//模拟按下鼠标左键。<br>　　mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);//模拟放开鼠标左键。<br>　　keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT,0),0,0); //按下SHIFT键。<br>　　keybd_event(0x52,MapVirtualKey(0x52,0),0,0);//按下R键。<br>　　keybd_event(0x52,MapVirtualKey(0x52,0),KEYEVENTF_KEYUP,0);//放开R键。<br>　　keybd_event(VK_SHIFT,MapVirtualKey(VK_SHIFT,0),KEYEVENTF_KEYUP,0);//放开<br>SHIFT键。<br>　　　　　　SetCursorPos(oldPoint.x,oldPoint.y);<br>　}<br>　　　}<br>　　　return CallNextHookEx(glhHook,nCode,wParam,lParam);<br>　　　}　　　CKeyHook::CKeyHook(){}<br>　　　CKeyHook::~CKeyHook()<br>　　　{　<br>　　　if( glhHook )<br>Stop();<br>　　　}<br>　　　//安装全局钩子。<br>　　　HHOOK CKeyHook::Start()<br>　　　{<br>glhHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,glhInstance,0);//设置键<br>盘钩子。<br>return glhHook;<br>}<br>　　　//卸载全局钩子。<br>　　　BOOL CKeyHook::Stop()<br>　　　{<br>　　　BOOL bResult = TRUE;<br>　if( glhHook )<br>　　　bResult = UnhookWindowsHookEx(glhHook);//卸载键盘钩子。<br>　　　return bResult;<br>　　　}　　(7).修改DllMain函数，代码如下：　　　extern "C" int APIENTRY<br>　　　DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)<br>　　　{<br>//如果使用lpReserved参数则删除下面这行<br>UNREFERENCED_PARAMETER(lpReserved);if (dwReason == DLL_PROCESS_ATTACH)<br>{<br>　　TRACE0("NOtePadHOOK.DLL Initializing!\n");<br>　　 //扩展DLL仅初始化一次<br>　　if (!AfxInitExtensionModule(ActiveKeyDLL, hInstance))<br>return 0;<br>　　new CDynLinkLibrary(ActiveKeyDLL);<br>　　　　　　//把DLL加入动态MFC类库中<br>　　glhInstance = hInstance;<br>　　//插入保存DLL实例句柄<br>}<br>else if (dwReason == DLL_PROCESS_DETACH)<br>{<br>　　TRACE0("NotePadHOOK.DLL Terminating!\n");<br>　　//终止这个链接库前调用它<br>　　AfxTermExtensionModule(ActiveKeyDLL);<br>}<br>return 1;<br>　　　}<br>　　(8).编译项目ActiveKey，生成ActiveKey.DLL和ActiveKey.lib。<br>　　接着，我们还需要创建一个外壳程序将全局钩子安装了Windows系统中，这个外壳<br>程序编写步骤如下：<br>　　(1).创建一个对话框模式的应用程序，项目名为Simulate。<br>　　(2).在主对话框中加入一个按钮，使用ClassWizard为其创建CLICK事件。<br>　　(3).将ActiveKey项目Debug目录下的ActiveKey.DLL和ActiveKey.lib拷贝到<br>Simulate项目目录下。<br>　　(4).从&#8220;工程&#8221;菜单中选择&#8220;设置&#8221;，弹出Project Setting对话框，选择Link标<br>签，在&#8220;对象/库模块&#8221;中输入ActiveKey.lib。<br><br><br>(5).将ActiveKey项目中的ActiveKey.h头文件加入到Simulate项目中，并在<br>Stdafx.h中加入#includeActiveKey.h。　　(6).在按钮单击事件函数输入如下代码：　　　void CSimulateDlg::OnButton1()<br>　　　{<br>// TODO: Add your control notification handler code here<br>if( !bSetup )<br>{<br>m_hook.Start();//激活全局钩子。<br>}<br>else<br>{<br>m_hook.Stop();//撤消全局钩子。<br>}<br>bSetup = !bSetup;　　　}　　(7).编译项目，并运行程序，单击按钮激活外挂。　　(8).启动画笔程序，选择文本工具并将笔的颜色设置为红色，将鼠标放在任意位置<br>后，按F10键，画笔程序自动移动鼠标并写下一个红色的大写R。图一展示了按F10键前的画笔程序的状态，图二展示了<br>按F10键后的画笔程序的状态。<br>图一：按F10前状态(001.jpg)<br>图二：按F10后状态(002.jpg)<br>五、封包技术　　通过对动作模拟技术的介绍，我们对游戏外挂有了一定程度上的认识，也学会了使<br>用动作模拟技术来实现简单的<br>动作模拟型游戏外挂的制作。这种动作模拟型游戏外挂有一定的局限性，它仅仅只能解<br>决使用计算机代替人力完成那<br>么有规律、繁琐而无聊的游戏动作。但是，随着网络游戏的盛行和复杂度的增加，很多<br>游戏要求将客户端动作信息及<br>时反馈回服务器，通过服务器对这些动作信息进行有效认证后，再向客户端发送下一步<br>游戏动作信息，这样动作模拟<br>技术将失去原有的效应。为了更好地&#8220;外挂&#8221;这些游戏，游戏外挂程序也进行了升级换<br>代，它们将以前针对游戏用户界面层的模拟推进到数据通讯层，通过封包技术在客户端挡截游戏服务器发送来的游戏<br>控制数据包，分析数据包并修<br>改数据包；同时还需按照游戏数据包结构创建数据包，再模拟客户端发送给游戏服务<br>器，这个过程其实就是一个封包<br>的过程。<br>　　封包的技术是实现第二类游戏外挂的最核心的技术。封包技术涉及的知识很广泛，<br>实现方法也很多，如挡截<br>WinSock、挡截API函数、挡截消息、VxD驱动程序等。在此我们也不可能在此文中将所<br>有的封包技术都进行详细介绍，故选择两种在游戏外挂程序中最常用的两种方法：挡截WinSock和挡截API函数。　　1． 挡截WinSock　　众所周知，Winsock是Windows网络编程接口，它工作于Windows应用层，它提供与<br>底层传输协议无关的高层数据传输编程接口。在Windows系统中，使用WinSock接口为应用程序提供基于TCP/IP协议的网<br>络访问服务，这些服务是由Wsock32.DLL动态链接库提供的函数库来完成的。　　由上说明可知，任何Windows基于TCP/IP的应用程序都必须通过WinSock接口访问网<br>络，当然网络游戏程序也不例外。由此我们可以想象一下，如果我们可以控制WinSock接口的话，那么控制游戏客户<br>端程序与服务器之间的数据包也将易如反掌。按着这个思路，下面的工作就是如何完成控制WinSock接口了。由上面的<br>介绍可知，WinSock接口其实是由一个动态链接库提供的一系列函数，由这些函数实现对网络的访问。有了这层的认<br>识，问题就好办多了，我们可以<br>制作一个类似的动态链接库来代替原WinSock接口库，在其中实现WinSock32.dll中实现<br>的所有函数，并保证所有函数的参数个数和顺序、返回值类型都应与原库相同。在这个自制作的动态库中，可以对我<br>们感兴趣的函数（如发送、接<br>收等函数）进行挡截，放入外挂控制代码，最后还继续调用原WinSock库中提供的相应<br>功能函数，这样就可以实现对网络数据包的挡截、修改和发送等封包功能。<br>　　下面重点介绍创建挡截WinSock外挂程序的基本步骤：　　(1) 创建DLL项目，选择Win32 Dynamic-Link Library，再选择An empty DLL<br>project。　　(2) 新建文件wsock32.h，按如下步骤输入代码：　　① 加入相关变量声明：　　　HMODULE hModule=NULL; //模块句柄<br>　　　char buffer[1000]; //缓冲区<br>　　　FARPROC proc; //函数入口指针　　② 定义指向原WinSock库中的所有函数地址的指针变量，因WinSock库共提供70多<br>个函数，限于篇幅，在此就只选择几个常用的函数列出，有关这些库函数的说明可参考MSDN相关内容。　　　//定义指向原WinSock库函数地址的指针变量。<br>　　　SOCKET (__stdcall *socket1)(int ,int,int);//创建Sock函数。<br>　　　int　(__stdcall *WSAStartup1)(WORD,LPWSADATA);//初始化WinSock库函数。<br>　　　int　(__stdcall *WSACleanup1)();//清除WinSock库函数。<br>　　　int (__stdcall *recv1)(SOCKET ,char FAR * ,int ,int );//接收数据函数。<br>　　　int (__stdcall *send1)(SOCKET ,const char * ,int ,int);//发送数据函<br>数。<br>　　　int (__stdcall *connect1)(SOCKET,const struct sockaddr *,int);//创建连<br>接函数。<br>　　　int (__stdcall *bind1)(SOCKET ,const struct sockaddr *,int );//绑定函<br>数。<br>　　　......其它函数地址指针的定义略。　　(3) 新建wsock32.cpp文件，按如下步骤输入代码：　　① 加入相关头文件声明：　　　#include &lt;windows.h&gt;<br>　　　#include &lt;stdio.h&gt;<br>　　　#include "wsock32.h"　　② 添加DllMain函数，在此函数中首先需要加载原WinSock库，并获取此库中所有<br>函数的地址。代码如下：　　　BOOL WINAPI DllMain (HANDLE hInst,ULONG ul_reason_for_call,LPVOID<br>lpReserved)<br>　　　{<br>　　　　if(hModule==NULL){<br>　　　　　//加载原WinSock库，原WinSock库已复制为wsock32.001。<br>　　　hModule=LoadLibrary("wsock32.001");<br>　　}<br>　　　　else return 1;<br>//获取原WinSock库中的所有函数的地址并保存，下面仅列出部分代码。<br>if(hModule!=NULL){<br>　　　　　//获取原WinSock库初始化函数的地址，并保存到WSAStartup1中。<br>proc=GetProcAddress(hModule,"WSAStartup");<br>　　　WSAStartup1=(int (_stdcall *)(WORD,LPWSADATA))proc;<br>　　　　　//获取原WinSock库消除函数的地址，并保存到WSACleanup1中。<br>　　　　proc=GetProcAddress(hModule i,"WSACleanup");<br>　　　　WSACleanup1=(int (_stdcall *)())proc;<br>　　　　　//获取原创建Sock函数的地址，并保存到socket1中。<br>　　　　proc=GetProcAddress(hModule,"socket");<br>　　　　　socket1=(SOCKET (_stdcall *)(int ,int,int))proc;<br>　　　　　//获取原创建连接函数的地址，并保存到connect1中。<br>　　　　　proc=GetProcAddress(hModule,"connect");<br>　　　　　connect1=(int (_stdcall *)(SOCKET ,const struct sockaddr<br>*,int ))proc;<br>　　　　　//获取原发送函数的地址，并保存到send1中。<br>　　　　　proc=GetProcAddress(hModule,"send");<br>　　　　　send1=(int (_stdcall *)(SOCKET ,const char * ,int ,int ))proc;<br>　　　　　//获取原接收函数的地址，并保存到recv1中。<br>　　　　　proc=GetProcAddress(hModule,"recv");<br>　　　　　recv1=(int (_stdcall *)(SOCKET ,char FAR * ,int ,int ))proc;<br>　　　　　......其它获取函数地址代码略。<br>　　　}<br>　　　else return 0;<br>　　　return 1;<br>}　　③ 定义库输出函数，在此可以对我们感兴趣的函数中添加外挂控制代码，在所有<br>的输出函数的最后一步都调用原WinSock库的同名函数。部分输出函数定义代码如下：//库输出函数定义。<br>//WinSock初始化函数。<br>　　　　int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA<br>lpWSAData)<br>　　　　{<br>　　　　　//调用原WinSock库初始化函数<br>　　　　　return WSAStartup1(wVersionRequired,lpWSAData);<br>　　　　}<br>　　　　//WinSock结束清除函数。<br>　　　　int PASCAL FAR WSACleanup(void)<br>　　　　{<br>　　　　　return WSACleanup1(); //调用原WinSock库结束清除函数。<br>　　　　}<br>　　　　//创建Socket函数。<br>　　　　SOCKET PASCAL FAR socket (int af, int type, int protocol)<br>　　　　{<br>　　　　　//调用原WinSock库创建Socket函数。<br>　　　　　return socket1(af,type,protocol);<br>　　　　}<br>　　　　//发送数据包函数<br>　　　　int PASCAL FAR send(SOCKET s,const char * buf,int len,int flags)<br>　　　　{<br>　　　//在此可以对发送的缓冲buf的内容进行修改，以实现欺骗服务器。<br>　　　外挂代码......<br>　　　//调用原WinSock库发送数据包函数。<br>　　　　　return send1(s,buf,len,flags);<br>　　　　}<br>//接收数据包函数。<br>　　　　int PASCAL FAR recv(SOCKET s, char FAR * buf, int len, int flags)<br>　　　　{<br>　　　//在此可以挡截到服务器端发送到客户端的数据包，先将其保存到buffer中。<br>　　　strcpy(buffer,buf);<br>　　　//对buffer数据包数据进行分析后，对其按照玩家的指令进行相关修改。<br>　　　外挂代码......<br>　　　//最后调用原WinSock中的接收数据包函数。<br>　　　　　return recv1(s, buffer, len, flags);<br>　　　　　}<br>　　　　.......其它函数定义代码略。　　(4)、新建wsock32.def配置文件，在其中加入所有库输出函数的声明，部分声明代<br>码如下：　　　LIBRARY "wsock32"<br>　　　EXPORTS<br>　　　　WSAStartup @1<br>　　　WSACleanup @2<br>　　　　recv @3<br>　　　　send @4<br>　　　　socket @5<br>　　　bind @6<br>　　　closesocket @7<br>　　　connect @8　　　......其它输出函数声明代码略。<br><br><br><br>(5)、从&#8220;工程&#8221;菜单中选择&#8220;设置&#8221;，弹出Project Setting对话框，选择Link标<br>签，在&#8220;对象/库模块&#8221;中输入Ws2_32.lib。　　(6)、编译项目，产生wsock32.dll库文件。　　(7)、将系统目录下原wsock32.dll库文件拷贝到被外挂程序的目录下，并将其改名<br>为wsock.001；再将上面产生的wsock32.dll文件同样拷贝到被外挂程序的目录下。重新启动游戏程序，此时游戏程序<br>将先加载我们自己制作的wsock32.dll文件，再通过该库文件间接调用原WinSock接口函数来实现访问网络。上面<br>我们仅仅介绍了挡载WinSock的实现过程，至于如何加入外挂控制代码，还需要外挂开发人员对游戏数据包结构、内<br>容、加密算法等方面的仔细分析<br>（这个过程将是一个艰辛的过程），再生成外挂控制代码。关于数据包分析方法和技<br>巧，不是本文讲解的范围，如您<br>感兴趣可以到网上查查相关资料。<br>2.挡截API　　挡截API技术与挡截WinSock技术在原理上很相似，但是前者比后者提供了更强大的<br>功能。挡截WinSock仅只能挡截WinSock接口函数，而挡截API可以实现对应用程序调用的包括WinSock API函数在内的<br>所有API函数的挡截。如果您的外挂程序仅打算对WinSock的函数进行挡截的话，您可以只选择使用上小节介绍的挡截<br>WinSock技术。随着大量外挂程序在功能上的扩展，它们不仅仅只提供对数据包的挡截，而且还对游戏程序中使用的<br>Windows API或其它DLL库函数的挡截，以使外挂的功能更加强大。例如，可以通过挡截相关API函数以实现对非中文游<br>戏的汉化功能，有了这个利器，可以使您的外挂程序无所不能了。<br>　　挡截API技术的原理核心也是使用我们自己的函数来替换掉Windows或其它DLL库提<br>供的函数，有点同挡截WinSock原理相似吧。但是，其实现过程却比挡截WinSock要复杂的多，如像实现挡截Winsock过<br>程一样，将应用程序调用的所有的库文件都写一个模拟库有点不大可能，就只说Windows API就有上千个，还有很多<br>库提供的函数结构并未公开，所以写一个模拟库代替的方式不大现实，故我们必须另谋良方。<br>　　挡截API的最终目标是使用自定义的函数代替原函数。那么，我们首先应该知道应<br>用程序何时、何地、用何种方式调用原函数。接下来，需要将应用程序中调用该原函数的指令代码进行修改，使它将调<br>用函数的指针指向我们自己定<br>义的函数地址。这样，外挂程序才能完全控制应用程序调用的API函数，至于在其中如<br>何加入外挂代码，就应需求而异了。最后还有一个重要的问题要解决，如何将我们自定义的用来代替原API函数的函数<br>代码注入被外挂游戏程序进行地址空间中，因在Windows系统中应用程序仅只能访问到本进程地址空间内的代码和数<br>据。　　综上所述，要实现挡截API函数，至少需要解决如下三个问题：　　● 如何定位游戏程序中调用API函数指令代码？　　● 如何修改游戏程序中调用API函数指令代码？　　● 如何将外挂代码（自定义的替换函数代码）注入到游戏程序进程地址空间？　　下面我们逐一介绍这几个问题的解决方法：<br>　　(1) 、定位调用API函数指令代码　　我们知道，在汇编语言中使用CALL指令来调用函数或过程的，它是通过指令参数中<br>的函数地址而定位到相应的函数代码的。那么，我们如果能寻找到程序代码中所有调用被挡截的API函数的CALL指令<br>的话，就可以将该指令中的函数地址参数修改为替代函数的地址。虽然这是一个可行的方案，但是实现起来会很繁琐，<br>也不稳健。庆幸的是，Windows系统中所使用的可执行文件（PE格式）采用了输入地址表机制，将所有在程序调用的<br>API函数的地址信息存放在输入地址表中，而在程序代码CALL指令中使用的地址不是API函数的地址，而是输入地址表中<br>该API函数的地址项，如想使程序代码中调用的API函数被代替掉，只用将输入地址表中该API函数的地址项内容修改即<br>可。具体理解输入地址表运行机制，还需要了解一下PE格式文件结构，其中图三列出了PE格式文件的大致结构。<br>　　图三：PE格式大致结构图(003.jpg)　　PE格式文件一开始是一段DOS程序，当你的程序在不支持Windows的环境中运行时，<br>它就会显示&#8220;This Programcannot be run in DOS mode&#8221;这样的警告语句，接着这个DOS文件头，就开始真正的PE<br>文件内容了。首先是一段称为&#8220;IMAGE_NT_HEADER&#8221;的数据，其中是许多关于整个PE文件的消息，在这段数据的尾端<br>是一个称为Data Directory的数据表，通过它能快速定位一些PE文件中段（section）的地址。在这段数据之后，则是<br>一个&#8220;IMAGE_SECTION_HEADER&#8221;的列表，其中的每一项都详细描述了后面一个段的相关信息。接着它就是PE文件中最主<br>要的段数据了，执行代码、数据和资源等等信息就分别存放在这些段中。<br>　　在所有的这些段里，有一个被称为&#8220;.idata&#8221;的段（输入数据段）值得我们去注<br>意，该段中包含着一些被称为输入地址表（IAT，Import Address Table）的数据列表。每个用隐式方式加载的API所在<br>的DLL都有一个IAT与之对应，同时一个API的地址也与IAT中一项相对应。当一个应用程序加载到内存中后，针对每一<br>个API函数调用，相应的产生如下的汇编指令：<br>　　JMP DWORD PTR [XXXXXXXX]　　或　　CALL DWORD PTR [XXXXXXXX]　　其中，[XXXXXXXX]表示指向了输入地址表中一个项，其内容是一个DWORD，而正是<br>这个DWORD才是API函数在内存中的真正地址。因此我们要想拦截一个API的调用，只要简单的把那个DWORD改为我们自己<br>的函数的地址。　　(2) 、修改调用API函数代码　　从上面对PE文件格式的分析可知，修改调用API函数代码其实是修改被调用API函数<br>在输入地址表中IAT项内容。由于Windows系统对应用程序指令代码地址空间的严密保护机制，使得修改程序指令代码<br>非常困难，以至于许多高手为之编写VxD进入Ring0。在这里，我为大家介绍一种较为方便的方法修改进程内存，它仅需<br>要调用几个Windows核心API函数，下面我首先来学会一下这几个API函数：　　　DWORD VirtualQuery(<br>　　　LPCVOID lpAddress, // address of region<br>　　　PMEMORY_BASIC_INFORMATION lpBuffer, // information buffer<br>　　　DWORD dwLength // size of buffer<br>　　　);　　该函数用于查询关于本进程内虚拟地址页的信息。其中，lpAddress表示被查询页<br>的区域地址；lpBuffer表示用于保存查询页信息的缓冲；dwLength表示缓冲区大小。返回值为实际缓冲大小。　　　BOOL VirtualProtect(<br>　　　LPVOID lpAddress, // region of committed pages<br>　　　SIZE_T dwSize, // size of the region<br>　　　DWORD flNewProtect, // desired access protection<br>　　　PDWORD lpflOldProtect // old protection<br>　　　);　　该函数用于改变本进程内虚拟地址页的保护属性。其中，lpAddress表示被改变保<br>护属性页区域地址；dwSize表示页区域大小；flNewProtect表示新的保护属性，可取值为PAGE_READONLY、<br>PAGE_READWRITE、PAGE_EXECUTE等；lpflOldProtect表示用于保存改变前的保护属性。如果函数调用成功返回&#8220;T&#8221;，否则<br>返回&#8220;F&#8221;。　　有了这两个API函数，我们就可以随心所欲的修改进程内存了。首先，调用<br>VirtualQuery()函数查询被修改内存的页信息，再根据此信息调用VirtualProtect()函数改变这些页的保护属性为<br>PAGE_READWRITE，有了这个权限您就可以任意修改进程内存数据了。下面一段代码演示了如何将进程虚拟地址为0x0040106c处的<br>字节清零。　　　BYTE* pData = 0x0040106c;<br>　　　MEMORY_BASIC_INFORMATION mbi_thunk;<br>　　　//查询页信息。<br>　　　VirtualQuery(pData, &amp;mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));<br>　　　//改变页保护属性为读写。<br>　　　VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,<br>　　　PAGE_READWRITE, &amp;mbi_thunk.Protect);<br>　　　//清零。<br>　　　*pData = 0x00;<br>　　　//恢复页的原保护属性。<br>　　　DWORD dwOldProtect;<br>　　　VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,<br>　　　mbi_thunk.Protect, &amp;dwOldProtect);<br>(3)、注入外挂代码进入被挂游戏进程中　　完成了定位和修改程序中调用API函数代码后，我们就可以随意设计自定义的API函<br>数的替代函数了。做完这一切后，还需要将这些代码注入到被外挂游戏程序进程内存空间中，不然游戏进程根本不会<br>访问到替代函数代码。注入方<br>法有很多，如利用全局钩子注入、利用注册表注入挡截User32库中的API函数、利用<br>CreateRemoteThread注入（仅限于NT/2000）、利用BHO注入等。因为我们在动作模拟技术一节已经接触过全局钩子，我相<br>信聪明的读者已经完全掌握了全局钩子的制作过程，所以我们在后面的实例中，将继续利用这个全局钩子。至于其它<br>几种注入方法，如果感兴趣可<br>参阅MSDN有关内容。　　有了以上理论基础，我们下面就开始制作一个挡截MessageBoxA和recv函数的实<br>例，在开发游戏外挂程序 时，可以此实例为框架，加入相应的替代函数和处理代码即可。此实例的开发过程如下：<br>　　(1) 打开前面创建的ActiveKey项目。　　(2) 在ActiveKey.h文件中加入HOOKAPI结构，此结构用来存储被挡截API函数名<br>称、原API函数地址和替代函数地址。<br>　　　typedef struct tag_HOOKAPI<br>　　　{<br>　　　LPCSTR szFunc;//被HOOK的API函数名称。<br>　　　PROC pNewProc;//替代函数地址。<br>　　　PROC pOldProc;//原API函数地址。<br>　　　}HOOKAPI, *LPHOOKAPI;　　(3) 打开ActiveKey.cpp文件，首先加入一个函数，用于定位输入库在输入数据段<br>中的IAT地址。代码如下：　　　extern "C" __declspec(dllexport)PIMAGE_IMPORT_DESCRIPTOR<br>　　　LocationIAT(HMODULE hModule, LPCSTR szImportMod)<br>　　　//其中，hModule为进程模块句柄；szImportMod为输入库名称。<br>　　　{<br>　　　//检查是否为DOS程序，如是返回NULL，因DOS程序没有IAT。<br>　　　PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule;<br>　　　if(pDOSHeader-&gt;e_magic != IMAGE_DOS_SIGNATURE) return NULL;<br>　　　　//检查是否为NT标志，否则返回NULL。<br>　　　　PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader+<br>(DWORD)(pDOSHeader-&gt;e_lfanew));<br>　　　　if(pNTHeader-&gt;Signature != IMAGE_NT_SIGNATURE) return NULL;<br>　　　　//没有IAT表则返回NULL。<br>　　　　<br>if(pNTHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Vir<br>tualAddress == 0)return NULL;<br>　　　　//定位第一个IAT位置。<br>　　　　PIMAGE_IMPORT_DESCRIPTOR pImportDesc =<br>(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDOSHeader + (DWORD)(pNTHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Virtu<br>alAddress));<br>　　　　//根据输入库名称循环检查所有的IAT，如匹配则返回该IAT地址，否则检测下<br>一个IAT。<br>　　　　while (pImportDesc-&gt;Name)<br>　　　　{<br>　　　　　//获取该IAT描述的输入库名称。<br>　　　PSTR szCurrMod = (PSTR)((DWORD)pDOSHeader +<br>(DWORD)(pImportDesc-&gt;Name));<br>　　　if (stricmp(szCurrMod, szImportMod) == 0) break;<br>　　　pImportDesc++;<br>　　　　}<br>　　　　if(pImportDesc-&gt;Name == NULL) return NULL;<br>　　　return pImportDesc;<br>　　　}　　再加入一个函数，用来定位被挡截API函数的IAT项并修改其内容为替代函数地址。<br>代码如下：　　　extern "C" __declspec(dllexport)<br>　　　HookAPIByName( HMODULE hModule, LPCSTR szImportMod, LPHOOKAPI<br>pHookApi)<br>　　　//其中，hModule为进程模块句柄；szImportMod为输入库名称；pHookAPI为<br>HOOKAPI结构指针。<br>　　　{<br>　　　　//定位szImportMod输入库在输入数据段中的IAT地址。<br>　　　　PIMAGE_IMPORT_DESCRIPTOR pImportDesc = LocationIAT(hModule,<br>szImportMod);<br>　　if (pImportDesc == NULL) return FALSE;<br>　　　　//第一个Thunk地址。<br>　　　　PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule +<br>(DWORD)(pImportDesc-&gt;OriginalFirstThunk));<br>　　 //第一个IAT项的Thunk地址。<br>　　　　PIMAGE_THUNK_DATA pRealThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule +<br>(DWORD)(pImportDesc-&gt;FirstThunk));<br>　　　　//循环查找被截API函数的IAT项，并使用替代函数地址修改其值。<br>　　　while(pOrigThunk-&gt;u1.Function)<br>{<br>　//检测此Thunk是否为IAT项。<br>if((pOrigThunk-&gt;u1.Ordinal &amp; IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)<br>{<br>　 //获取此IAT项所描述的函数名称。<br>　PIMAGE_IMPORT_BY_NAME pByName<br>=(PIMAGE_IMPORT_BY_NAME)((DWORD)hModule+(DWORD)(pOrigThunk-&gt;u1.AddressOfData));<br>　if(pByName-&gt;Name[0] == \0) return FALSE;<br>　　//检测是否为挡截函数。<br>if(strcmpi(pHookApi-&gt;szFunc, (char*)pByName-&gt;Name) == 0)<br>　 {<br>　　　　　　　MEMORY_BASIC_INFORMATION mbi_thunk;<br>　　　　　　　//查询修改页的信息。<br>　　　　　　　VirtualQuery(pRealThunk, &amp;mbi_thunk,<br>sizeof(MEMORY_BASIC_INFORMATION));<br>//改变修改页保护属性为PAGE_READWRITE。<br>　　　　　　　VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,<br>PAGE_READWRITE,&amp;mbi_thunk.Protect);<br>//保存原来的API函数地址。<br>　　　 　　if(pHookApi-&gt;pOldProc == NULL)<br>pHookApi-&gt;pOldProc = (PROC)pRealThunk-&gt;u1.Function;<br>　 //修改API函数IAT项内容为替代函数地址。<br>pRealThunk-&gt;u1.Function = (PDWORD)pHookApi-&gt;pNewProc;<br>//恢复修改页保护属性。<br>DWORD dwOldProtect;<br>　　　　　　　VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,<br>mbi_thunk.Protect,&amp;dwOldProtect);<br>　　　　　 }<br>}<br>　 pOrigThunk++;<br>　 pRealThunk++;<br>}<br>　　SetLastError(ERROR_SUCCESS); //设置错误为ERROR_SUCCESS，表示成功。<br>　　return TRUE;<br>　　　}　　(4) 定义替代函数，此实例中只给MessageBoxA和recv两个API进行挡截。代码如下<br>：　　　static int WINAPI MessageBoxA1 (HWND hWnd , LPCTSTR lpText, LPCTSTR<br>lpCaption, UINT uType)<br>　　　{<br>　　　　//过滤掉原MessageBoxA的正文和标题内容，只显示如下内容。<br>return MessageBox(hWnd, "Hook API OK!", "Hook API", uType);<br>　　　}<br>　　　static int WINAPI recv1(SOCKET s, char FAR *buf, int len, int flags )<br>　　　{<br>　　　//此处可以挡截游戏服务器发送来的网络数据包，可以加入分析和处理数据代<br>码。<br>　　　return recv(s,buf,len,flags);<br>　　　}　　(5) 在KeyboardProc函数中加入激活挡截API代码，在if( wParam == 0X79 )语句<br>中后面加入如下else if语句：　　　......<br>　　　//当激活F11键时，启动挡截API函数功能。<br>　　　else if( wParam == 0x7A )<br>　　　{<br>　　　　HOOKAPI api[2];<br>api[0].szFunc ="MessageBoxA";//设置被挡截函数的名称。<br>api[0].pNewProc = (PROC)MessageBoxA1;//设置替代函数的地址。<br>api[1].szFunc ="recv";//设置被挡截函数的名称。<br>api[1].pNewProc = (PROC)recv1; //设置替代函数的地址。<br>//设置挡截User32.dll库中的MessageBoxA函数。<br>HookAPIByName(GetModuleHandle(NULL),"User32.dll",&amp;api[0]);<br>//设置挡截Wsock32.dll库中的recv函数。<br>HookAPIByName(GetModuleHandle(NULL),"Wsock32.dll",&amp;api[1]);<br>　　　}<br>　　　<br>(6) 在ActiveKey.cpp中加入头文件声明 "#include "wsock32.h"。 从&#8220;工程&#8221;菜单中选择&#8220;设置&#8221;，弹出Project Setting对话框，选择Link标签，在&#8220;对象/库模块&#8221;中输入Ws2_32..lib。　　(7) 重新编译ActiveKey项目，产生ActiveKey.dll文件，将其拷贝到Simulate.exe<br>目录下。运行Simulate.exe并启动全局钩子。激活任意应用程序，按F11键后，运行此程序中可能调用MessageBoxA函数的操作，看看信息框是不是有所变化。同样，如此程序正在接收网络数据包，就可以实现封包功能了。　　六、结束语<br>　　除了以上介绍的几种游戏外挂程序常用的技术以外，在一些外挂程序中还使用了游戏数据修改技术、游戏加速技术等。在这篇文章里，就不逐一介绍了。 
<img src ="http://www.blogjava.net/Daniel2005/aggbug/127883.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Daniel2005/" target="_blank">泌鲁沙夫</a> 2007-07-03 16:31 <a href="http://www.blogjava.net/Daniel2005/articles/127883.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>教你如何编写游戏外挂</title><link>http://www.blogjava.net/Daniel2005/articles/127880.html</link><dc:creator>泌鲁沙夫</dc:creator><author>泌鲁沙夫</author><pubDate>Tue, 03 Jul 2007 08:28:00 GMT</pubDate><guid>http://www.blogjava.net/Daniel2005/articles/127880.html</guid><wfw:comment>http://www.blogjava.net/Daniel2005/comments/127880.html</wfw:comment><comments>http://www.blogjava.net/Daniel2005/articles/127880.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Daniel2005/comments/commentRss/127880.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Daniel2005/services/trackbacks/127880.html</trackback:ping><description><![CDATA[今天石器上不去，没法调程序，写篇文章给想学写外挂的朋友参考 <br>一、先说一下写一个外挂需要什么条件 <br>1、熟练的C语言知识 <br>目前的外挂大部分都是用BC或者是vc写的，拥有熟练的C语言知识是写外挂的基本条件 <br>2、具有很强的汇编基础 <br>一般游戏都不可能有原代码的，必须靠反汇编或者跟踪的办法来探索其中的机理 <br>，所以有强的汇编基础也是必不可少的条件 <br>3、熟练掌握跟踪和调试的工具 <br>有了上面2个条件后，掌握一些工具也是很有必要的 <br>跟踪的工具，softice当然是不二之选，至于反汇编的工具，我推荐用IDA PRO <br>这个工具反汇编出来的代码结构清晰，非常好读 <br>如果你不具有上面的条件，还是先把基础打好，再来写外挂吧，一分耕耘，一分收获，天下没有白掉的馅饼的 <br>二、写外挂面临的基本技术问题 <br>1、修改进程的执行代码 <br>要修改进程的执行代码，要先取得进程的ID,如果是由外挂程序启动，返回值里就有进程ID,如果不是的话， <br>需要用findwindow找到窗口句柄，再用GetWindowProcessID取得进程ID,取得进程ID以后，就可以用 <br>writeprocessmemory来修改进程的执行代码了，使程序按照我们的意愿来执行，石器外挂里的不遇敌、寸步遇敌 <br>就是用这样的方法来实现的 <br>2、截获外挂发送和接收的封包 <br>除了通过修改代码来实现的功能以外，很多的功能都是通过修改封包来实现的，要修改封包，首先要能截获它。 <br>第一步是要跟踪出发和收的位置，至于怎么跟踪，我以后会提到，找到位置以后，有2个办法，一是在那个位置加一 <br>个jmp语句，跳到你的处理函数位置，处理完后，再跳回来，这种方法要求比较高，需要处理好很多事情，另一种办法 <br><br>是往那个位置写条能造成例外的指令，比如int 3,然后用DebugActiveProcess调试游戏进程，这样每当游戏执行到那个 <br>位置的时候，就会停下来，到外挂程序里面去，等外挂程序处理完以后，用ContinueDebugEvent 继续运行程序。 <br><br>今天先写这么多，下回将讨论外挂的具体功能该怎么实现 <br>今天来谈谈地址的调查问题，地址调查是写外挂中最艰辛，最富有挑战性的事情，很多朋友问我要外挂的原程序，其实有了外挂原程序，如果你不会调查地址，还是没用的， <br>原程序和地址的关系就象武学中招式与内功的关系，没有内功的招式，只是一个花架子。而内功精深以后，任何普通的招式，都有可能化腐朽为神奇，外挂中的地址分为两类，一类是程序地址，一类是数据地址。象石器中的双石器，真彩，不遇敌，寸步遇敌，发送接收封包等，都属于第一类，而人物坐标，状态等，都属于第二类。对于第一类地址，主要依靠softice来调查地址，对第二类地址，可以用一些游戏工具，比如fpe,game expert,game master等来调查，我一直用game expert,因为我找不到2000下能用的fpe, <br>各位以前用fpe改游戏的时候，没想过他也能用来干这个吧 <br>对于第二类数据的调查方法，大部分人都很熟习了，我就不多说了，现在主要来谈谈第一类数据的详细调查过程，比如我们要调查发送封包的位置，如何着手呢，客户端往服务器要发很多封包，但最简单的办法莫过从说话的封包入手，先说一句很长的话，最好是英文，查起来方便，说完以后，用任意一种办法进入游戏程序的进程空间（比如先用spy查出游戏程序的窗口句柄，再切换到softice打入bmsg 窗口句柄 wm_lbuttondown,这样在游戏程序中一点鼠标就进入了他的进程空间）然后用s命令查出这句话所放的内存地址，记下这个地址，在softice中打入bpm 刚才调查到的地址，这个指令的意思是只要有访问这个内存的动作，立刻中断，然后再切换到游戏，说一句话，你会发现softice自动中断到某一个位置了，从这个位置跟踪下去，发送封包的位置也就不远了。 <br>上面所说的都是针对一个全新的游戏程序而言，如果是一个老的程序，有前辈做了大量的工作，还可以用些别的办法，如反汇编等，来调查。以后游戏版本的更新也是如此，只要把老版本的地址位置附近的代码记下来，去新版本的代码里面search一下，就ok了。 <br>恩，休息一会儿，休息一会儿 <br><br>我主要对外挂的技术进行分析,至于游戏里面的内部结构每个都不一样,这里就不做讲解了,我也没有那么厉害,所有的都知道,呵呵!<br></font>
<p><br>1 首先游戏外挂的原理<br>外挂现在分为好多种,比如模拟键盘的,鼠标的,修改数据包的,还有修改本地内存的,但好像没有修改服务器内存的哦,呵呵!其实修改服务器也是有办法的,只是技术太高一般人没有办法入手而已!(比如请GM去夜总会,送礼,收黑钱等等办法都可以修改服务器数据,哈哈)<br>修改游戏无非是修改一下本地内存的数据,或者截获api函数等等,这里我把所能想到的方法都作一个介绍,希望大家能做出很好的外挂来使游戏厂商更好的完善自己的技术.<br>我见到一片文章是讲魔力宝贝的理论分析,写的不错,大概是那个样子.<br>下来我就讲解一下技术方面的东西,以作引玉之用<br>2 技术分析部分<br>1 模拟键盘或鼠标的响应<br>我们一般使用UINT SendInput(<br>UINT nInputs, // count of input events<br>LPINPUT pInputs, // array of input events<br>int cbSize // size of structure<br>);api函数<br>第一个参数是说明第二个参数的矩阵的维数的,第二个参数包含了响应事件,这个自己填充就可以,最后是这个结构的大小,非常简单,这是最简单的方法模拟键盘鼠标了,呵呵<br>注意:这个函数还有个替代函数: <br>VOID keybd_event(<br>BYTE bVk, // 虚拟键码<br>BYTE bScan, // 扫描码<br>DWORD dwFlags, <br>ULONG_PTR dwExtraInfo // 附加键状态<br>);和<br>VOID mouse_event(<br>DWORD dwFlags, // motion and click options<br>DWORD dx, // horizontal position or change<br>DWORD dy, // vertical position or change<br>DWORD dwData, // wheel movement<br>ULONG_PTR dwExtraInfo // application-defined information<br><font color=#f0f1f3>计算机教程教你如何编写游戏外挂来自www.itwen.com<font color=#f0f1f3>IT WEN计算机教程网</font></font> <br><br>);<br>这两个函数非常简单了,我想那些按键精灵就是用的这个吧,呵呵,上面的是模拟键盘,下面的是模拟鼠标的.<br>这个仅仅是模拟部分,要和游戏联系起来我们还需要找到游戏的窗口才行,或者包含快捷键,就象按键精灵的那个激活键一样,我们可以用GetWindow函数来枚举窗口,也可以用Findwindow函数来查找制定的窗口(注意还有一个FindWindowEx),FindwindowEx可以找到窗口的子窗口,比如按钮,等什么东西.当游戏切换场景的时候我们可以用FindWindowEx来确定一些当前窗口的特征,从而判断是否还在这个场景,方法很多了,比如可以GetWindowInfo来确定一些东西,比如当查找不到某个按钮的时候就说明游戏场景已经切换了,等等办法.有的游戏没有控件在里面,这是对图像做坐标变换的话,这种方法就要受到限制了.这就需要我们用别的办法来辅助分析了.<br>至于快捷键我们要用动态连接库实现了,里面要用到hook技术了,这个也非常简单,大家可能都会了,其实就是一个全局的hook对象然后SetWindowHook就可以了,回调函数都是现成的,而且现在网上的例子多如牛毛,这个实现在外挂中已经很普遍了.如果还有谁不明白,那就去看看msdn查找SetWindowHook就可以了.<br>这个动态连接库的作用很大,不要低估了哦,它可以切入所有的进程空间,也就是可以加载到所有的游戏里面哦,只要用对,你会发现很有用途的!<br>这个需要你复习一下win32编程的基础知识了,呵呵,赶快去看书吧!<br>2截获消息<br>有些游戏的响应机制比较简单,是基于消息的,或者用什么定时器的东西,这个时候你就可以用拦截消息来实现一些有趣的功能了.<br>我们拦截消息使用的也是hook技术,里面包括了键盘消息,鼠标消息,系统消息,日志等,别的对我们没有什么大的用处,我们只用拦截消息的回调函数就可以了,这个不会让我写例子吧,其实这个和上面的一样,都是用SetWindowHook来写的,看看就明白了很简单的.<br>至于拦截了以后做什么就是你的事情了,比如在每个定时器消息里面处理一些我们的数据判断,或者在定时器里面在模拟一次定时器,那么有些数据就会处理两次,呵呵,后果嘛,不一定是好事情哦,呵呵,不过如果数据计算放在客户端的游戏就可以真的改变数据了,呵呵,试试看吧!用途还有很多,自己想也可以想出来的,呵呵!<br>3拦截socket包<br>这个技术难度要比原来的高很多哦,要有思想准备.<br><br>首先我们要替换winSock.dll或者winsock32.dll,我们写的替换函数要和原来的函数一致才行,就是说它的函数输出什么样的,我们也要输出什么样子的函数,而且参数,参数顺序都要一样才行,然后在我们的函数里面调用真正的winSock32.dll里面的函数就可以了<br>首先:我们可以替换动态库到系统路径<br>其次:我们应用程序启动的时候可以加载原有的动态库,用这个函数LoadLibary<br>然后定位函数入口用GetProcAddress函数获得每个真正socket函数的入口地址<br>当游戏进行的时候它会调用我们的动态库,然后从我们的动态库中处理完毕后才跳转到真正动态库的函数地址,这样我们就可以在里面处理自己的数据了,应该是一切数据.呵呵!<br>兴奋吧,拦截了数据包我们还要分析之后才能进行正确的应答,不要以为这样工作就完成了,呵呵!还早呢,等分析完毕以后我们还要仿真应答机制来和服务器通信,一个不小心就会被封号,呵呵,呜~~~~~~~~我就被封了好多啊!<br>分析数据才是工作量的来源呢,游戏每次升级有可能加密方式会有所改变,因此我们写外挂的人都是亡命之徒啊,被人娱乐了还不知道,呵呵!(声明我可没有赚钱,我是免费的)<br>好了,给大家一个不错的起点,这里有完整的替换socket源代码,呵呵!<br>http://www.vchelp.net/vchelp/zsrc/wsock32_sub.zip<br>4截获api<br>上面的技术如果可以灵活运用的话我们就不用截获api函数了,其实这种技术是一种补充技术.比如我们需要截获socket以外的函数作为我们的用途,我们就要用这个技术了,其实我们也可以用它直接拦截在socket中的函数,这样更直接.<br>现在拦截api的教程到处都是,我就不列举了,我用的比较习惯的方法是根据输入节进行拦截的,这个方法可以用到任何一种操作系统上,比如98/2000等,有些方法不是跨平台的,我不建议使用.这个技术大家可以参考windows核心编程里面的545页开始的内容来学习,如果是98系统可以用window系统奥秘那个最后一章来学习.<br>好了方法就是这么多了,看大家怎么运用了,其它的一些针对性的技巧这里我就不说了,要不然会有人杀了我的,呵呵!<br>记住每个游戏的修改方法都不一样,如果某个游戏数据处理全部在服务器端,那么你还是别写外挂了,呵呵,最多写个自动走路的外挂,哈哈!<br>数据分析的时候大家一定要注意,不要轻易尝试和服务器的连接,因为那有很危险,切忌!等你掌握了大量的数据分析结果以后,比较有把握了在试试,看看你的运气好不好,很有可能会成功的哦,呵呵!<br>其实像网金也疯狂的那种模拟客户端的程序也是不错的,很适合office的人用,就看大家产品定位了.<br>好了不说了,大家努力吧!切忌不要被游戏厂商招安哦,那样有损我们的形象,我们是为了让游戏做的更好而开发的,也不愿意打乱游戏的平衡,哎,好像现在不是这样了!不说了随其自然吧</p>
<img src ="http://www.blogjava.net/Daniel2005/aggbug/127880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Daniel2005/" target="_blank">泌鲁沙夫</a> 2007-07-03 16:28 <a href="http://www.blogjava.net/Daniel2005/articles/127880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>