這是我癡迷于破解與接近于游戲開發的階段. 大概是2005年7月

作者:LiquidX

示例圖:

    其實網上有很多的外掛內掛文章我也看了不少,從中得到了很多的幫助。前些時候看到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處地址...

 

代碼如下:

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
 }
}

全文完! 本人能力有限,有任何錯誤之處希望告之.以免造成誤導...

本文配套代碼下載:

http://www.shnenglu.com/Files/liquidx/mir20057122103.rar

作者QQ:380000937 mailto:liquidx@163.com

等過些天把我收集的一些外掛源碼整理一下提供給大家下載研究 :)

相關交流論壇:www.gameres.com,www.cnesort.com

相關資料

全屏看血
內存地址:47A0D3
75 EB
原版:00000075108B45EC
新版:000000EB108B45EC

 


<P>{強行退出
內存地址:004620E6(7)
74 90
0D 90
原版:2000740D8B45
新版:200090908B45
內存地址:00462162(3)
74 90
0A 90
原版:2000740A8B45
新版:200090908B45
內存地址:4914CA(B)
內存地址:491576(7)
74 90
0E 90
原版:0080782000740EA1
新版:00807820009090A1
}</P>
<P>{免助跑
內存地址:00461BEB(C-F0)
0F 90
8E 90
79 90
FD 90
FF 90
FF 90
原版:E8000F8E79FDFFFF
新版:E800909090909090
內存地址:461BB9(A-E)
0F 90
8C 90
DA 90
00 90
00 90
00 90
原版:00010F8CDA000000A1
新版:0001909090909090A1
}</P>
<P>{跑步砍
內存地址:004634E2
00 01
原版:4F00008D45F0
新版:4F00018D45F0
}</P>
<P>{攻擊速度
內存地址:467016(7)
78 E2
05 04
原版:EB0BB87805
新版:EB0BB84805
說明:速度由二位數指定,二位數前后互換為真實數據,數字大為慢小為快
}</P>
<P>{穿人
內存地址:472D17
34 0C
原版:00000034018845
新版:0000000C018845
}</P>
<P>{免蠟
內存地址:471BDE
74 EB
原版:008038007454
新版:00803800EB54
}</P>
<P>{物品閃光
內存地址:471AA6
04
原版:1300007625
新版:0200007625
}</P>
<P>{自動放藥
0048C21F F9 68 FD FF
004623A2 76 07 00 00
0048C21F DD 50 B0 01
004623A2 7A ED B2 01
}</P>
<P>{超負重??
Poke 00499A40 EB
004975A8 EB 5C
00499A40 EB 93</P>
<P>{攻擊方法修改一
原版
00463425 74 1C
0046344A 74 10
00463463 74 15</P>
<P>半月
00463425 74 1C
0046344A 74 10
00463463 90 90
攻殺
00463425 74 1C
0046344A 90 90
00463463 74 15
烈火
00463425 90 90
0046344A 74 10
00463463 74 15</P>
<P>方法二</P>
<P>半月
Poke 00463363 D0
烈火
Poke 00463363 D1
普通
Poke 00463363 C6</P>
<P>C745E8 C60B 單手砍
C745E8 C70B 雙手砍
C745E8 C80B 跳躍砍
C745E8 CA0B 攻殺
C745E8 CB0B 刺殺
C745E8 D00B 半月
C745E8 D10B 烈火
}</P>
<P>{無限刺殺
內存地址:463363
C6 CB
原版:C745E8C60B
新版:C745E8CB0B
內存地址:463373
C7 CB
原版:C745E8C70B
新版:C745E8CB0B
}</P>
<P>{無限攻殺
內存地址:463363
C6 CA
原版:C745E8C60B
新版:C745E8CA0B
內存地址:463373
C7 CA
原版:C745E8C70B
新版:C745E8CA0B
</P>