★★★Azure Services Platform入门教程★★★Azure应用程序推荐: Stick Love★★★本博客欢迎转载,但请注明版权、原文链接,谢谢。
Memento..
My stories in my way..

posts - 33,comments - 468,trackbacks - 13

    网上有很多外挂制作的教程,大多是讲针对大型网络游戏的,主要包含一些抓包、反汇编、C++的知识综合。事实也如此,常见的外挂都是使用VC++写的,从来没有过C#或者其他.NET语言编写的外挂。

    作为微软.NET技术的忠实粉丝,这难免是一种遗憾。不过不要紧,下面流牛木马就教大家两招,包教包会,免收学费。 :)

    其实作为游戏外挂来说,主要就是三个功能:模拟键盘操作、模拟鼠标操作、修改内存数据。修改内存数据比较难,但模拟鼠标键盘的操作却很简单。很多流行游戏的外挂,都可以只通过模拟鼠标键盘来实现,例如:劲舞团、QQ音速、连连看、各类网页游戏,以及各类大型网游中的自动打怪、自动吃药等等。

    Warcraft Ⅲ,学名魔兽争霸之冰封王座,俗称魔兽,简称war3,在最近六七年风靡全球。最近两年,war3在中国又掀起了玩DOTA的新高潮。

    本文制作DOTA游戏中的显血、改键外挂为例,简单地介绍如何使用C#语言制作游戏外挂。

    最终界面如下:

image    本示例包含两个功能:显血;将Q键改为小键盘的7键。玩war3的同学都知道,这两个功能对于war3(尤其是DOTA)相当重要。

     首先简单介绍一下,外挂程序模拟键盘的原理。

     外挂程序与游戏程序是两个不同的进程。外挂程序使用Windows提供的API找到游戏程序的进程,并设置键盘钩子(什么叫做钩子?你不知道,但百度知道。)设置完钩子后,我们再监控游戏进程中用户的按键,并根据用户需求进行处理,完成某些模拟键盘动作。 

     了解了这个过程之后,我们就可以开始整理思路了。完成外挂一共需要以下四个步骤:

一、声明Windows API 中的函数和常量

      //键盘Hook结构函数
        [StructLayout(LayoutKind.Sequential)]
        public class KeyBoardHookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        #region DllImport
        //设置钩子
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        //抽掉钩子
        public static extern bool UnhookWindowsHookEx(int idHook);
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        //调用下一个钩子
        public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
        //取得模块句柄 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        //寻找目标进程窗口
        [DllImport("USER32.DLL")]
        public static extern IntPtr FindWindow(string lpClassName,
            string lpWindowName);
         //设置进程窗口到最前 
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
       //模拟键盘事件 
        [DllImport("User32.dll")]
        public static extern void keybd_event(Byte bVk, Byte bScan, Int32 dwFlags, Int32 dwExtraInfo);
//释放按键的常量
   private const int KEYEVENTF_KEYUP =2;
       本例所使用的函数比较少,它们都在系统的USER32.dll里,包括:设置和取消钩子、调用下一个钩子、导入进程、模拟键盘等等。我们依次导入它们。
       这些函数的命名规范合理,几乎只根据函数名就能知道其功能。
       如果读者对于其中的某些函数不熟悉,请自行搜索MSDN。

二、使用Windows API设置钩子  

          有了以上windows API函数的声明,下一步就是设置钩子了。

          寥寥两行代码,但包含了相当丰富的内容。

//委托
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
 
public void Hook_Start()
    {
        // 安装键盘钩子
        if (hHook == 0)
        {
            KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);

            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
                     
        }
    }
 
    先介绍一下设置钩子的明星函数:SetWindowsHookEx 。它的参数说明如下。

SetWindowsHookEx(
idHook: Integer;   {钩子类型}
lpfn: TFNHookProc; {函数指针}
hmod: HINST;       {包含钩子函数的模块(EXE、DLL)句柄; 一般是 HInstance; 如果是当前线程这里可以是 0}
  dwThreadId: DWORD  {关联的线程; 可用 GetCurrentThreadId 获取当前线程; 0 表示是系统级钩子}
): HHOOK;            {返回钩子的句柄; 0 表示失败}

 

    请注意lpfn这个参数。上面的解释是“函数指针”。在C#中,是不能直接使用指针的,更不要说函数指针了。我们可以采用C#中的委托(delegate)来实现函数指针的功能。

    于是乎,在上面的代码中,我们定义了一个处理键盘消息函数的委托KeyBoardHookProcedure = new HookProc(KeyBoardHookProc),并将它作为参数传入SetWindowsHookEx 内。KeyBoardHookProc就是被委托的具体函数。

 

三、监控用户操作

   设置好钩子后,我们可以在被委托的函数中写入监控用户操作与模拟键盘的代码。

public static int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
       //监控用户键盘输入
         KeyBoardHookStruct input = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));

            //截获Home  键          
            if (input.vkCode == (int)Keys.Home)
            {
              //此处写入其他操作逻辑                
            }
       
           // 继续执行下一个钩子程序
            return CallNextHookEx(hHook, nCode, wParam, lParam);

        }

 

四、根据用户需要模拟键盘操作

        显血功能:玩war3的都知道,war3自带的显血快捷键有3个。Alt键是显示所有单位生命,[ 键显示友方单位生命,] 键显示地方单位生命。外挂需要做的事情仅仅是模拟一直按着某个键不松手而已。由于Alt键与其他很多键构成组合键,故我们不能模拟长按Alt,否则会影响正常游戏。我们的解决方案应该是模拟长按 [ 键和 ] 键。代码如下:

              //获得魔兽程序的句柄
                IntPtr wcHandle = FindWindow(null, "Warcraft III");

                //如果钩子有效
                if (wcHandle != IntPtr.Zero)
                {
                    //设置游戏窗口到最前
                    SetForegroundWindow(wcHandle);
                byte VK_NUM1 = 219;   //键盘上 [ 键的代码。按[可显示友方单位生命值。
                  byte VK_NUM2 = 221;   // 键盘上] 键的代码。按]可显示敌方单位生命值。
                  keybd_event(VK_NUM1, 0, 0, 0); //长按[
                keybd_event(VK_NUM2, 0, 0, 0);  //长按]
               }

        改键: 小键盘(Numpad)上的快捷键很不方便按,所以很多玩家喜欢把小键盘上的键改到左边的字母键盘。玩DOTA的同学都知道,没有任何英雄的技能使用"Q”这个快捷键(召唤师有一种球是"Q"(不是技能))。于是我们把小键盘上的7键改到Q上,也不会造成任何冲突。方法也很简单:如果监控到用户按"Q”键,则像游戏进程发送小键盘上的"7"键。代码如下:

        //如果用户按了Q键
          if (input.vkCode == (int)Keys.Q)
          {
              //获得魔兽程序的句柄
              IntPtr wcHandle = FindWindow(null, "Warcraft III");

              //如果钩子有效
              if (wcHandle != IntPtr.Zero)
              {
                  //设置游戏窗口到最前
                  SetForegroundWindow(wcHandle);
                  byte VK_Q = (byte)Keys.NumPad7;
                  keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
                  keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0); //松开小键盘7
              }
              return 1;
          }

好了,到这里就把模拟键盘的外挂介绍完了。模拟鼠标与之非常类似,请用户自行揣摩。本文仅做抛砖引玉,欢迎感兴趣的朋友来流牛木马的博客进行讨论。

 

附件:外挂成品下载(运行需要.net 2.0以上环境)

 参考文献:《精通.NET互操作》。感谢作者黄际洲、崔晓源的赠书,我终于学以致用了一回~ :)

1
0
(请您对文章做出评价)
« 上一篇:【Azure实例】有趣的Silverlight应用:录播简笔画
» 下一篇:Azure完整实例:在线日程表
posted on 2009-07-03 03:57 流牛木马 阅读(6424) 评论(61)  编辑 收藏 网摘

FeedBack:
2009-07-03 07:03 | Jake.NET      
这样用P/Invoke写钩子程序是不是用VC比较简单。
  回复  引用  查看    
2009-07-03 07:12 | mcjtcnblog
不错
  回复  引用    
2009-07-03 07:27 | Joey[Lin]      
NICE!!!
  回复  引用  查看    
2009-07-03 07:34 | Ks.Int-Gel      
哇靠,现在玩魔兽用外挂封号了,VS,HF都是的
怕怕。。。

  回复  引用  查看    
2009-07-03 07:40 | 韦恩卑鄙      
一般键盘钩子属于客户端io辅助  本身不修改封包  不能算常规外挂

  回复  引用  查看    
2009-07-03 07:44 | 无名氏[未注册用户]
曾经也做过一个键盘改键程序.用于WAR3..当时玩真三. 刚学C#.在网上找资料做.
  回复  引用    
2009-07-03 08:11 | 随风风风      
整个源代码发出来啊
  回复  引用  查看    
2009-07-03 08:18 | 张亚      
再来几个序列,说说模拟鼠标和改内存
  回复  引用  查看    
2009-07-03 08:32 | 子风      
最近在学winfrm编程,学习学习。
  回复  引用  查看    
2009-07-03 08:50 | 张蒙蒙      
vs2.3版,魔兽命令 -vshp,相当于长按 alt键。
  回复  引用  查看    
2009-07-03 08:52 | WCF技术联盟      
LZ,可不可以 讨论用C# 做QQ音速、连连看的外挂
  回复  引用  查看    
2009-07-03 08:56 | 海龟      
玩war3的同学都知道,没有任何英雄的技能使用"Q”这个快捷键

很抱歉,兽王的召唤豪猪快捷键就是Q

  回复  引用  查看    
2009-07-03 09:07 | 徐少侠      
呵呵

键盘鼠标的我都实现过,不过直接改内存倒是没玩过


LZ搞个来学学

ps:全拼里面打LZ,不小心跳出来个老赵?呵呵

  回复  引用  查看    
2009-07-03 09:13 | 品香一郎      
LZ你太有才了,我天天玩DOTA呢!~能不能把小键盘改成字母上面的数字呢?

  回复  引用  查看    
2009-07-03 09:15 | 品香一郎      
LZ能不能你弄个出来我们直接用的啊?做个参数表可以修改的
修改一对一就够了!~

  回复  引用  查看    
2009-07-03 09:33 | 小庄      
不错!就是功能弱了点!
  回复  引用  查看    
2009-07-03 09:46 | 雾里kanhua
欢迎大家进入QQ交流群5259672,.net方向。要求至少一年工作经验。
  回复  引用    
2009-07-03 09:53 | kenny.guo
强大了
  回复  引用    
2009-07-03 09:57 | Mr.S[未注册用户]
不知道有没有技术能挂到FLASH?
  回复  引用    
2009-07-03 10:02 | G.Anthony
楼主能不能把源码发放出来学习学习啊
我也是做.NET的 我也天天玩DOTA 呵呵

  回复  引用    
2009-07-03 10:10 | 无为而为      
学习了。玩真三的。
  回复  引用  查看    
2009-07-03 10:22 | 最爱陌生人[未注册用户]
楼主的东西根本谈不上外挂,只能算是辅助工具。。。。

外挂分两种 一种是内挂 一种是脱机外挂

内挂一般要分析处理游戏封包、读取修改游戏内存数据,甚至要api hook ,当然同时会模拟一些键盘鼠标操作实现比如自动打怪等功能(但即便是自动打怪 你也要知道怪对应在屏幕哪个位置呀?)

脱机外挂则根本不用客户端就可以进行游戏 需要破解客户端和服务器端封包协议,难度最大。。。

  回复  引用    
2009-07-03 10:35 | Matz[未注册用户]
写的这是p呀
  回复  引用    
2009-07-03 10:45 | 无为而为      
22楼哥们说的那样,C#能做到么?还得C吧。
  回复  引用  查看    
2009-07-03 10:48 | sunia[未注册用户]
请问LZ,改内存是如何操作啊?
  回复  引用    
2009-07-03 11:00 | Funeral      
刚才参考LZ的写了一个魔兽三小外挂,能运行了
很感谢LZ

  回复  引用  查看    
2009-07-03 11:02 | Suse.Acc
希望楼主发份该程序的完整源代码给我 谢谢 whyxup@sina.com
  回复  引用    
2009-07-03 12:24 | 徐少侠      
有个问题?

必须游戏界面是最前端显示吗?最好不要这样的,因为有些外挂的功能最好能开着游戏,最小化,然后干自己的事情哦

呵呵


  回复  引用  查看    
2009-07-03 12:24 | iyangel[未注册用户]
看这些要源码的很好笑,核心代码别人都给出来了~
你们都懒到只想直接F5了,还要源码干什么?

  回复  引用    
2009-07-03 12:24 | 徐少侠      
同时觉得楼主已经写了这么多了

楼上那些直接要源码的还算程序员的说不?自己写写就是了啊

  回复  引用  查看    
#31楼[楼主]
2009-07-03 12:29 | 流牛木马      
@sunia
读写内存也是使用类似的方法,只是稍微复杂。我自己实验了一个能修改金钱的,觉得放上来不妥,过几天我想想看用什么方式再写一些吧。谢谢你的关注。

  回复  引用  查看    
#32楼[楼主]
2009-07-03 12:31 | 流牛木马      
@海龟
非常不好意思,我以为你应该发现我所说的是玩DOTA。

  回复  引用  查看    
#33楼[楼主]
2009-07-03 12:34 | 流牛木马      
@最爱陌生人
--引用--------------------------------------------------
最爱陌生人: 楼主的东西根本谈不上外挂,只能算是辅助工具。。。。

外挂分两种 一种是内挂 一种是脱机外挂

内挂一般要分析处理游戏封包、读取修改游戏内存数据,甚至要api hook ,当然同时会模拟一些键盘鼠标操作实现比如自动打怪等功能(但即便是自动打怪 你也要知道怪对应在屏幕哪个位置呀?)

脱机外挂则根本不用客户端就可以进行游戏 需要破解客户端和服务器端封包协议,难度最大。。。
--------------------------------------------------------

我不知道你这些自以为是的对外挂的定义是怎么来的,不过我可以告诉你:
外挂,英文简称OGC,本意为“外界辅助工具”。
这是对外挂的专业定义。

  回复  引用  查看    
#34楼[楼主]
2009-07-03 12:35 | 流牛木马      
--引用--------------------------------------------------
Suse.Acc: 希望楼主发份该程序的完整源代码给我 谢谢 whyxup@sina.com
--------------------------------------------------------
--引用--------------------------------------------------
随风风风: 整个源代码发出来啊
--------------------------------------------------------

要源代码的同学,请参考29楼和30楼。

  回复  引用  查看    
#35楼[楼主]
2009-07-03 12:37 | 流牛木马      
@Jake.NET
呵呵,是啊。
这归根结底就是P/Invoke在游戏中的简单应用而已。
VC来做当然是最方便的。

  回复  引用  查看    
2009-07-03 13:08 | 最爱陌生人[未注册用户]
另外 键盘和鼠标消息钩子比较特殊 跨进程下用SetWindowsHookEx可以实现。

如果是其他消息的话(比如你想hook socket),用C#是实现不了的 必须借助native DLL进行代码注入才行, 所以c# 开发游戏外挂 纯粹是扯淡。。。。

  回复  引用    
2009-07-03 13:16 | 游侠_1      
这确实不叫外挂,只能算辅助工具
真正的外挂,不用客户端的才算,但估计很难,

  回复  引用  查看    
2009-07-03 13:24 | 当然能[未注册用户]
@无为而为
当然能做到

  回复  引用    
2009-07-03 13:27 | 深蓝      
好东西啊,好久没有玩过魔兽了,楼主哪天有空的时候我们来打几把!
  回复  引用  查看    
2009-07-03 13:48 | Funeral      
请教楼主这个问题
KeyBoardHook.keybd_event(VK_KEY, 0, 0, 0);
KeyBoardHook.keybd_event(VK_KEY, 0, KeyBoardHook.KEYEVENTF_KEYUP, 0);

虽然说是按下然后释放一个键 但这个键对应的值会输出两次 请问这个问题应该怎么解决

比如VK_KEY 是1,就会输出11

  回复  引用  查看    
#44楼[楼主]
2009-07-03 14:46 | 流牛木马      
@Funeral 你说得很对。
在本例中,亦有此问题,不过对于DOTA游戏来说,没有影响。
 刚才我试了一下,用以下方法可以解决,你看看吧。
 [DllImport("user32.dll")]
static extern byte MapVirtualKey(byte wCode, int wMap);
 
byte a = MapVirtualKey((byte)Key, 0);
keybd_event((byte)Key, a, 0, 0);
System.Threading.Thread.Sleep(10); keybd_event((byte)Key, a, KEYEVENTF_KEYUP, 0);

  回复  引用  查看    
2009-07-03 17:57 | Red_angelX      
没有任何内存操作,只是模拟按键,只能算辅助程序而已
用按键精灵作不是更方便?
用正确的工具做正确的事情

  回复  引用  查看    
2009-07-03 18:04 | ztofemale
用Api,还不如用VC++,VB6,Delphi.....
因.Net中用Api真的很麻烦,性能也差,功能也不怎么样

  回复  引用    
2009-07-03 18:15 | ITbird
呵呵.先过了NP.再谈外挂吧.
  回复  引用    
2009-07-03 22:20 | yellowyu      
你说下个几K的外挂,还要安装个几十M的framework,这外挂有人用么...是吧啦.....

而且这外挂早就有了.....楼主要不,偶发个给你.....

不用装环境的....

  回复  引用  查看    
#49楼[楼主]
2009-07-03 22:28 | 流牛木马      
@yellowyu
cnblogs是一个技术讨论社区。本文也只是一个技术性的探讨。你如果是来找好用的软件的,你走错地方了,cnblogs并不适合你。 此外,C++的显血挂我也写过,放在了网上。没准儿你手里的就是我写的。

  回复  引用  查看    
2009-07-04 01:03 | yellowyu
@流牛木马
那如果是楼主你写的,那就十分感谢了....

而且我不认为我的想法不针对于技术......

  回复  引用    
2009-07-04 09:25 | DOTA[未注册用户]
哇靠 没想到博客园里 嫩多玩DOTA的啊 吼吼
  回复  引用    
2009-07-04 09:52 | 郑希强
会不会做木马的啊
  回复  引用    
2009-07-04 17:14 | 99书城[未注册用户]
会不会做木马的啊

  回复  引用    
2009-07-06 09:47 | 大隐于市[未注册用户]
发现很多人很无聊,博主明显是来探讨技术的,一些自以为是的人以为自己懂得啥叫外挂就出来显摆,还有一坨人要全部源码,居然还有人说为了这个外挂还要下framework,汗哪~~顶博主大牛。。。
  回复  引用    
2009-07-06 10:31 | 2B2B2B2B2B2B2B[未注册用户]
最受不了的就是楼上几个乱喷粪的人,人家楼主好心写了个tutorial给新手看,你们几个装B犯非要跑到这里用满嘴的粪喷人家楼主。你们以为就你们知道外挂的原理啊?看到楼主写点浅显的东西就来喷人家,别那么浮躁好不好?

你们牛B怎么没看你们写点tutorial啊?真是的,只会喷粪的人少在这里乱叫。

  回复  引用    
2009-08-04 13:00 | MagicHu      
什么时候,鼠标和键盘的系统钩子,也能叫外挂了?

  回复  引用  查看    
#61楼[楼主]
2009-08-04 15:15 | 流牛木马      
引用MagicHu:什么时候,鼠标和键盘的系统钩子,也能叫外挂了?

我本来不打算搭理你的无知。
不过你可以猜一下,如果你在Google搜索“显血外挂”和“改键外挂”,会有多少条结果呢?

  回复  引用  查看    
2009-08-04 16:07 | ShaPherD      
个人感觉,仁者见仁,没必要去计较别人怎么说吧,总有人爱挑点毛病的。。。
  回复  引用  查看    
2009-08-12 11:27 | IS黑山老妖      
不知道博主还在不?虽然上面有个人装x说要源码的人技术怎么怎么不行,但我还是想要下源码,因为我的确不会,想参考一下源码学习学习,拜托博主给个学习机会,如果可以拜托发下邮箱mamahuhusoft@126.com
  回复  引用  查看    
2009-08-20 09:01 | madyina[未注册用户]
看到上面的评论,觉得就是我们程序员的悲哀:
楼主辛苦写了研究外挂的基础文章,有些无聊的人却用专业外挂的定义来衡量,相当于中国解放初期那帮外国狗一样:
中国人民造出东风车了,外国的奔驰宝马一看就笑了:那是车吗?那能开吗?
今天楼主写了一个探讨外挂的文章,于是就有人说:那是外挂吗?
古人有云:人们一般都是 “严”君子,“宽”小人的,大家对你的要求苛刻正是证明了楼主是个君子,希望楼主不要因为这些无知的指责而放弃研究的精神,还是那句话:技术无对错

  回复  引用    
2009-09-02 08:36 | hans.hu      
支持一下!找机会试试看。
  回复  引用  查看    
2009-09-28 14:14 | 王书奎(网名:无忌)      
我转了 ,用于学习api 因为最近要学习嵌入式开发了
  回复  引用  查看    
2009-11-04 14:50 | fhefh      
楼主 谢谢了 怎需要
  回复  引用  查看    
2009-12-29 17:03 | 撞破南墙      
学习了。3Q
  回复  引用  查看