天天看點

寫外挂的方法

在多個WINDOWS平台上進行測試,以保證外挂在不同版本的WINDOWS上都能正常運作。

除非有用公共伺服器,再去下載下傳一個遊戲程式源代碼。

外挂分為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

}

}

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

本文配套代碼下載下傳:

mir20057122103.rar

作者QQ:156789519 mailto:[email protected]

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

相關資料

全屏看血

記憶體位址:47A0D3

75 EB

原版:00000075108B45EC

新版:000000EB108B45EC

}  

{強行退出

記憶體位址: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

}

{免助跑

記憶體位址: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

}

{跑步砍

記憶體位址:004634E2

00 01

原版:4F00008D45F0

新版:4F00018D45F0

}

{攻擊速度

記憶體位址:467016(7)

78 E2

05 04

原版:EB0BB87805

新版:EB0BB84805

說明:速度由二位數指定,二位數前後互換為真實資料,數字大為慢小為快

}

{穿人

記憶體位址:472D17

34 0C

原版:00000034018845

新版:0000000C018845

}

{免蠟

記憶體位址:471BDE

74 EB

原版:008038007454

新版:00803800EB54

}

{物品閃光

記憶體位址:471AA6

04

原版:1300007625

新版:0200007625

}

{自動放藥

0048C21F F9 68 FD FF

004623A2 76 07 00 00

0048C21F DD 50 B0 01

004623A2 7A ED B2 01

}

{超負重??

Poke 00499A40 EB

004975A8 EB 5C

00499A40 EB 93

{攻擊方法修改一

原版

00463425 74 1C

0046344A 74 10

00463463 74 15

半月

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

方法二

半月

Poke 00463363 D0

烈火

Poke 00463363 D1

普通

Poke 00463363 C6

C745E8 C60B 單手砍

C745E8 C70B 雙手砍

C745E8 C80B 跳躍砍

C745E8 CA0B 攻殺

C745E8 CB0B 刺殺

C745E8 D00B 半月

C745E8 D10B 烈火

}

{無限刺殺

記憶體位址:463363

C6 CB

原版:C745E8C60B

新版:C745E8CB0B

記憶體位址:463373

C7 CB

原版:C745E8C70B

新版:C745E8CB0B

}

無限攻殺

記憶體位址:463363

C6 CA

原版:C745E8C60B

新版:C745E8CA0B

記憶體位址:463373

C7 CA

原版:C745E8C70B

新版:C745E8CA0B