秀纳

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::
其实网上有很多的外挂内挂文章我也看了不少,从中得到了很多的帮助。前些时候看到shaker写出的一些传奇外挂的文章之后,再根据自己的研究对外挂知识也算是有了个初步的了解。

 
     外挂分为2种,一种是脱机程序,也就是模拟客户端的程序称为外挂.另一种是利用游戏程序本身的函数对游戏进行一些相关动作的称之为内挂,因为是在游戏进程内部完成任务的。今天要说的是传奇2(虽然这游戏过时了但作为研究来说还是值得的:)内挂的一点点知识,其实我也不太懂,复杂的东西也弄不出来,所以我就把我所学到的一点点知识写了出来,希望更多的人能够了解这方面的知识。

本文没有什么技术可言,但相信对一些未入门的人很有用.

第一步:  首先我们得将传奇的mir.dat脱壳有些私服没有mir.dat那就看看mir.exe,我们查得他是用aspack加的壳,你可以去网上下载相关工具也可以手动脱掉. 这样传奇2现在就是赤裸裸的站在我们面前了:) 现在要做的就是给他开开刀,看他的心肝肠肺都在做些什么,在哪里长着.....

第二步:我们用OLLYDBG加载刚才已经脱壳的mir.dat,然后我们利用插件菜单里的中文字符插件来获得相关信息,如果你没有此插件可以去www.pediy.com找找.不一会儿od给我们呈现出了很多的字符串信息,我们现在就搜索他的“肺”-("攻城区域")我们找到如下图:

  

 在此行双击鼠标左键我们来到:

 

 经过调试确定这里就是个屏幕输出就是在我们攻城的时候屏幕左上角显示的那几个字.

0047A4B3    .  68 FFFFFF00       push 0FFFFFF   //字体颜色
0047A4B8    .  6A 00                 push 0                //背景色
0047A4BA    .  68 94A54700       push unpacked.0047A594 
0047A4BF    .  33C9                  xor ecx,ecx         //x坐标
0047A4C1    .  33D2                  xor edx,edx        //y坐标
0047A4C3    .  8B45 F8              mov eax,dword ptr ss:[ebp-8] //设备场景句柄
0047A4C6    .  E8 D5640200       call unpacked.004A09A0 //内部屏幕输出函数

 那么我们就写出这个函数

typedef struct
{
 int len;
 char text[100];
}DT;

void  SText(DWORD eax1)
{
 
    DT dstring;
    strcpy(dstring.text,(char*)string);
    dstring.len=strlen(string);
    txtaddress=(DWORD)&dstring.text[0];
 _asm
 {
      mov eax, eax1
      call setshowmode1
      call setshowmode2
      push TRANSPARENT
      push eax
      call setshowmode3
      push txtcolor
      push bkcol
      push txtaddress
      mov ecx, y
      mov edx, x
      mov eax, eax1
      call ShowTxtcall
 }
}

 然后定义一些全局变量和一个可以动态修改输出的字符串和颜色与位置的函数:

const DWORD conaddress=0x47A6CC;
const DWORD ShowTxtcall=0x4a09a0;
const DWORD setshowmode1=0x44D8B4,setshowmode2=0x41834C,setshowmode3=0x406434;
DWORD x=0x0, y=0x0,txtcolor=0x0,bkcol=0x1e00ff;
DWORD  txtaddress=0x0;

char* string="传奇小外挂--By LiquidX Diy 2005.6.15";

void settxt(char* strings,

                DWORD X,DWORD Y,

                DWORD TXTCOLOR,DWORD     BKCOL)
{
                string=strings;
                x=X;

                y=Y;

                txtcolor=TXTCOLOR;

                bkcol=BKCOL;
}

 现在我们的屏幕输出函数已经模拟出来了,下面要做的就是改掉游戏显示屏幕坐标函数(关于这个函数地址你可以用金山游侠等工具查找很方便的)内部执行的流程,使这个函数跳转到我们的函数中来这样就可以在屏幕上无闪动的输出想输出的字符串了..

定义一个naked函数 关于naked可以去网上查查..

__declspec(naked) initST()
{
    
 _asm
 {       
   push eax
   push edx
   push ecx
   push ebp//保存参数
   mov eax,dword ptr[ebp-0x8] //获得我们当时eax中的值
   push eax                              //传入eax参数
   call disfunc                           //调用我们的函数
   pop ebp                               //恢复堆栈
   pop ecx
   pop edx
   pop eax
   mov ecx,9                            
   jmp conaddress                    //返回游戏函数继续执行
 }
 
}

void __stdcall disfunc(DWORD eax1)
{
    SText(eax1);//调用我们的函数
}

好了,现在基本上都完成得差不多了,现在只需要修改机器码了

上面代码中我们看到函数中一直都需要获得当时的eax中的值,经过跟踪分析我选择0x47a6cc(返回)(显示地图坐标函数的入口偏移几个字节在这里可以在本函数第一时间内拿到eax而处理机器码量较少)处地址...

 

代码如下:

LRESULT CALLBACK hookproc(int ncode ,WPARAM wparam,LPARAM lparam)
{
 if(KEYUP(lparam)&&ncode==HC_ACTION&&wparam==VK_HOME)
 {
  settxt("ShowText Testing....终于成功啦!!!",0x120,0x80,0x0,0x00ffff);
 }
 if(KEYUP(lparam)&&ncode==HC_ACTION&&wparam==VK_F12)
 {
  
  char buf[MAX_PATH];
  ::GetClassName(GetActiveWindow(),buf,MAX_PATH);
  if (lstrcmpi(buf,"TFrmMain")==0)
  {
  
   _asm  //改写 地址 跳转到我们的函数
   {
       lea eax,initST
       mov ebx,0x47a6cc //写入这个地址
       sub eax,ebx
       mov esi,0x47a6c7
       mov dword ptr[esi],0xe9 //JMP
       mov dword ptr[esi+0x1],eax //合成跳转指令
   }
  }
 }
 return ::CallNextHookEx(hook,ncode,wparam,lparam);
}

现在我们的一个屏幕输出的简单内挂就完成了,根据网上提供的一些内存地址你可以给它加上更多的功能。

最后一件事情就是外挂退出时恢复机器码,以免游戏跳转到一个不可用的地址造成崩溃..

代码如下:

void revert()
{

 _asm
 {
     mov esi,0x47A6C7
     mov eax,0xb9
     mov dword ptr[esi],eax
     mov eax,0x09
     mov dword ptr[esi+0x1],eax
 }
}

全文完! 本人能力有限,有任何错误之处希望告之.以免造成误导...

本文配套代码下载:

 user2/16215/upload/20057122103.rar
posted on 2007-03-28 19:37  秀纳  阅读(729)  评论(1)    收藏  举报