VC6-QQ对对碰

前段时间跟以前的同事玩QQ游戏对对碰,结果输的好惨,后来在网上看到了有对对碰的外挂,但还需要注册,就考虑既然别人可以写出来,我为什么就不能写出来呢?于是花了一个下午的时间仔细研究了一下,把外挂写了出来。
        其实原理很简单,只要将棋盘上面的数据保存起来,然后经过分析就可以知道移动哪里的动物,然后再通过模拟鼠标消息来点击两个位置就可以了。
         1)获取棋盘数据
          要得到棋盘的数据进行分析,思路是这样:首先得获得对对碰的窗口,然后对窗口上面的象素进行分析,从而获取每个格子中的数据。对于每个格子里面的动物,一定可以有几个有特征的点使得可以区分开每个格子中的动物,可以用用2到3个点的数据保存一个动物,这样把每个格子中动物的数据都获得后,棋盘的数据也就出来了。
        首先,要得到对对碰的窗口,这个比较简单,可以用::FindWindow来实现,具体代码如下:
     CQQGameToolDlg * dlg = (CQQGameToolDlg *)parm;//这里因为这个函数是作为一个线程来做的,所以得传递一个参数过来
     dlg->hWnd = ::FindWindow(NULL,"QQ对对碰");//查询
     if(dlg->hWnd == NULL)
      dlg->hWnd = ::FindWindow(NULL,"对对碰");//好像窗口标题有时还不同,不知道是不是我自己搞错了
     if(dlg->hWnd == NULL)
     {
      AfxMessageBox("未找到对对碰窗口,请首先启动对对碰!");
      dlg->SetDlgItemText(IDC_BUTTON1,"启动");
      dlg->m_bStart = false;
      return 0;
     }
      到这里就得到了QQ对对碰的窗口句柄,但是要分析窗口中的象素,还需要得到一个窗口的HDC
    dlg->hDc = ::GetDC(dlg->hWnd);
    下面就是得到棋盘的数据了,首先得测试出棋盘左上角的坐标和每个格子的边长,具体测试方法就不给出了,是比较简单的,经过测试得出的数据,棋盘左上角坐标为(176,102),每个格子的边长是48。
    接下来就是保存棋盘数据了
    下边的函数是为了获取每一个方格的数据的
    参数x,y是棋盘坐标,比如(0,0)代表左上角第一个方格等等。
    我们在这里取每个格子中间那条线的象素作为数据进行存储。
    COLORREF * CQQGameToolDlg::GetRectData(int x, int y)
    {
     COLORREF * color;
     color = new COLORREF[48];
     int count = 0;
     for(int i=(x-1)*48 + m_posX;i<(x-1)*48 + m_posX + 48;i++)
     {
      color[count++] = GetPixel(hDc,i,(y-1)*48 + m_posY + 20);
       //如果是棋盘的底色,则忽略
      if(color[count-1] == 0x00efaa5a || color[count-1] == 0x00f7c384)
       color[count-1] = 0x000000;
     }
     return color;
    }
    下边的函数获取每个格子的特征点的数据:
    在这里我们只取六个特征点进行存储,把六个特征点的十六进制保存起来。
    void CQQGameToolDlg::GetCode()
    {
     for(int i=1;i<=8;i++)
      for(int j=1;j<=8;j++)
      {
       CString str;
       COLORREF * c;
       c = GetRectData(i,j);
       str.Format("%x%x%x%x%x%c",c[25],c[26],c[27],c[28],c[29],c[30]);
       data[i][j] = str;
      }
    }
    经过上面的函数,则data数组保存的就是棋盘的数据了,到这里,对棋盘数据的获取就结束了。
    2)分析棋盘数据
    得到棋盘数据以后,需要对棋盘数据进行分析了,思路是分别分横向和纵向遍历所有的格子,先找到两个相同动物相连的格子,然后找到周围6个可能移动的格子,只要在6个格子中找到一个与那两个相同的,就说明可以移动那个格子中的动物了。
    比如:

只要在C、D、E、F、G、H中找到任意一个与A、B相同的动物,就可以了。具体的代码也比较简单,就是对数组的判断和操作了,在这里就不详细给出了。
    3)移动动物
    从上面的分析我们可以知道需要移动哪里的动物了,现在我们只要标识出来那个位置其实就可以达到目的了,但是为了方便,最好还是不用自己动手,而利用程序自动来完成移动的操作。实现也比较简单,只需要给游戏窗口发送消息就可以实现,代码如下:
    由于开始是直接画图上去没有实现自动移动,所以函数名还是用的DrawRect:)
    x,y是上面得到的移动的坐标。
    void CQQGameToolDlg::DrawRect(int x, int y)
    {
     int xx,yy;
     xx = (x-1)*48 + 10 + m_posX;
     yy = (y-1)*48 + 10 + m_posY;
    // ::Rectangle(hDc,xx,yy,xx + 10,yy + 10);//这里是画一个方块上去,注释掉了。
     LPPOINT lpPoint = new CPoint();
     lpPoint->x = xx;
     lpPoint->y = yy;
     ::ClientToScreen(hWnd,lpPoint);
     LPARAM lParam = MAKELPARAM(xx,yy);//鼠标点击的坐标
     ::SendMessage(hWnd,WM_LBUTTONDOWN,MK_LBUTTON,lParam);//发送鼠标DOWN的消息
     ::SendMessage(hWnd,WM_LBUTTONUP,MK_LBUTTON,lParam);//发送鼠标UP的消息
    }    
    这样就完成了一个自动游戏的小工具,还比较简单吧?如果配合变速齿轮,效果会更好的。根据同样的原理,类似这样的游戏其实都是可以做出来这种外挂的,比如连连看、俄罗斯方块、泡泡龙等等,只是需要对游戏本身进行仔细分析才行。


    还要补充一点:使用的时候必须让对对碰的棋盘完全显示出来,不能有窗口挡住否则得到的数据就不准确了。

--------------------------------------------------------------------------------------------------------------

 

有几个网友问过我,为什么在QQ游戏中不能模拟鼠标,其实我原来在开发的时候也遇到过.  
  那是因为QQ游戏中有反外挂.我的解决方法见下面文章,希望对大家有所帮助.  
   
  或者直接访问我的主页  
   
  http://adong2008.512j.com  
   
   
  /  
  //   作者   :   阿东  
  //   主页   :   http://adong2008.512j.com  
  //   邮箱   :   dongfa@yeah.net  
  //   MSN     :   codelive@hotmail.com  
  //   日期   :   2005.02.06  
  /  
   
   
  关于QQ游戏外挂mouse_event不起作用的原因,及我的对对碰外挂程序.  
   
   
  相信很多朋友都使用过QQ游戏的外挂和自己也开发过.  
  但可能你会发现,mouse_event不起作用了.这是为什么呢?  
  我写对对碰外挂的时候也碰到了.下面就把实现和解决过程说明如下.  
  关于如何判断对对碰中是否可以消除的代码略过(大家应该都是通过颜色来判断的),因为这部分不是难点.  
   
  写好外挂后,反复测试发现,只有第一次运行结果正确,之后就不起作用了,然后动一下鼠标或者点一下鼠标键就又起作用了.想到可能是QQ游戏起作用判断,它能分辨模拟鼠标运作的硬件鼠标动作.(觉得QQ游戏写的很牛,佩服呀~~~)  
   
  经过查看目录,发现在游戏目录下面一般都会有这个文件kmsinput.sys,使用ida   pro打开分析发一下,发现这是nt下的鼠标的驱动,将作为过滤器filter加到的挂接到鼠标驱动中的,这基本上就证实了我的想法,肯定是通过这个驱动程序来分辨模拟鼠标运作还是硬件鼠标动作的.  
   
  然后就设想:当点击鼠标时,QQ程序应该是通过这个驱动程序来检测是否为硬件鼠标的动作,我们的硬件鼠标是能够检测到的,如果你调用了mouse_event则视为非硬件鼠标动作.就不处理鼠标动作,也就是认为你是模拟鼠标,表示你使用的外挂程序.  
   
  没办法只能反汇编跟踪调试了,先用ida   pro反汇编了一下,发现有很大一部分区域没办法反汇编出来,想到肯定是有加密了.于是我就使用windbg运行来分析了,通过跟踪鼠标点击消息,发现在这个地方会跳转  
   
  00408519   8b11   mov   edx,[ecx]  
  0040851b   6a01   push   0x1  
  0040851d   ff5208   call   dword   ptr   [edx+0x8]  
  00408520   3dc9d56601   cmp   eax,0x166d5c9   //这是比较  
  00408525   0f85a0000000   jne   twin!CxImage::`copy   constructor   closure'+0x6a7b(004085cb)   //   这是这里,如果是硬件鼠标动作不跳,如果是模拟就跳转了  
  找到了这个地方,就容易多了,很简单把   cmp   eac,0x166d5c9改为cmp   eax,eax  
  剩下的三个字节改为90   90   90.  
   
  再运行程序和外挂测试通过.大功告成了!哈哈...  
   
  另个,又研究发现,对对碰的速度是通过Sleep控制的,写了一个api   hook,hook到Sleep,将参数  
  VOID   WINAPI   CTwinHookFunc::MySleep(DWORD   dwMilliseconds)  
  {  
          ...  
          dwMilliseconds   =   dwMilliseconds/5;   //   变为1/5  
          ...  
          p_Sleep(dwMilliseconds);   //   调用真正的sleep函数  
  }  
   
  再次测试,哇靠,好快呀~~~  
  通过实战,挂了半天,发现可以同时对付几个人而且也不会输.胜率为90%,2000多分了.  
   
  对对碰外挂程序下载:  
  http://adong2008.512j.com/temp/DDPHelp.rar  
  好久不玩QQ游戏了,上面的外挂是针对对对碰版本0.10.1.12的.  
   
  有任何问题欢迎交流.  
   
   
   
  /  
  附关键代码:  
  我使用DLL注入技术,就是写一个DLL,然后把它注入到   对对碰进程(Twin.exe).  
  你可以写一个DLL,然后加入以下代码:  
   
  //   以下代码做的工作是  
  //   动态的将对对碰游戏中通过驱动判断鼠标的地方,改为不管是硬件还是模拟都让它起作用.  
  //   老的汇编代码:  
  //   00408520   3dc9d56601   cmp   eax,0x166d5c9   //    
  //   00408525   0f85a0000000   jne   004085cb   //   是模拟鼠标就跳转了,我们不能这它跳  
  //   新的汇编代码:  
  //   00408520   39c0   cmp   eax,eax  
  //   00408522   90   nop  
  //   00408523   90   nop  
  //   00408524   90   nop  
  //   00408525   0f85a0000000   jne   004085cb   //   这回肯定不会跳转了  
   
  //  
  //..........................................................................  
  BYTE   chOld[5];  
  DWORD   dwRead   =   5;  
  void   *pCrackAddr   =   (void   *)0x00408520;   //   这是通过反汇编得到的地址  
  if(ReadProcessMemory(GetCurrentProcess(),   pCrackAddr,   chOld,   5,   &dwRead))  
  {  
          //   Old:00408520   3d   c9   d5   66   01  
          if(   (chOld[0]   ==   0x3d)   &&    
          (chOld[1]   ==   0xc9)   &&    
          (chOld[2]   ==   0xd5)   &&    
          (chOld[3]   ==   0x66)   &&    
          (chOld[4]   ==   0x01))  
          {  
                  //   New:00408520   39   c0   90   90   90  
                  BYTE   chCrack[5];  
                  chCrack[0]   =   0x39;  
                  chCrack[1]   =   0xc0;  
                  chCrack[2]   =   0x90;  
                  chCrack[3]   =   0x90;  
                  chCrack[4]   =   0x90;  
   
                  DWORD   dwWrite   =   5;  
                  WriteProcessMemory(GetCurrentProcess(),   pCrackAddr,   chCrack,   5,   &dwWrite);  
          }  
  }  
  //..........................................................................  
  在  
  DllMain(HINSTANCE   hInstance,   DWORD   dwReason,   LPVOID   lpReserved)  
  {  
  UNREFERENCED_PARAMETER(lpReserved);  
  if   (dwReason   ==   DLL_PROCESS_ATTACH)  
  {  
  //在这里执行以上代码  
  }  
  …  
  }  
      
    这样就可以了.  
    或者可这样,我的DDPHelp.exe执行后,会在同目录下产生一个TWin.dat文件,将这个文件注入到Twin.exe进程就可以了.  
   
  注入进程的方法我就不介绍了,网上应该很多的.  

---------------------------------------------------------------------------

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值