初級遊戲外掛編程詳解 windows運行原理+遊戲輔助編程 遊戲外掛編程

來源:互聯網
上載者:User

標籤:彙編代碼   exit   修改   探索   原因   多少   使用   提高   取資料   

詳解遊戲輔助編程

【目錄】

1-什麼是Windows API

2-Windows進程

3-Windows 的記憶體的運行原理

4-windows 中控制代碼的概念

5-Windows的變數類型

6-輔助實現的原理

7-編程實現遊戲輔助

8-怎樣尋找記憶體位址

9-總結

準備軟體:VC,CheatEngineer5.5

學習這部分內容,你必須要掌握C語言的基礎知識,非常基礎的文法就行了。這篇文章的內容適合剛開始接觸編程的人,高手請飄過。

【1】什麼是windows API

Windows API 中文翻譯過來就是windows應用程式介面(Application Programming Interface)

我們知道,我們在使用C/C++的時候,會包含很多的標頭檔,例如最常用的stdio.h,裡面有很多函數的聲明,例如使用scanf函數能輸入資料,使用printf函數能列印文本到螢幕上顯示出來。又例如math.h裡面有很多數學計算函數,如sqrt求平方根的函數。我們只要包含這些標頭檔,就能調用這些函數。只要給函數傳遞相應的參數,就能實現我們想要的效果,這些函數就是C語言給我們提供的“介面”。

所謂windows應用程式介面,其實就是windows提供給程式員的一組函數。

Windows api 包含幾千個可調用的函數,這些函數能讓我們程式員作業系統的方方面面。

我們就可以調用者幾千個函數實現各種功能。如調用ExitWindowsEx來關閉電腦,CopyFile來複製檔案,MessageBox來彈出系統提示框,用BitBlt來繪製映像等等。而調用這幾千函數的條件,就是在代碼的開頭加上#include <windows.h>就行了,因為絕大部分的函式宣告都在windows.h裡面,我們只要包含了這個標頭檔,就能夠使用這些函數。

所以可以這麼理解

Windows API =windows提供的幾千個函數

【windows進程】

關於進程,我想大家都應該熟悉這個名詞。在應用程式無響應無法關閉的時候,我們常常使用CTRL + ALT +DELETE來叫出工作管理員

我們可以看到一個進程列表,其中列出了所有正在啟動並執行進程

進程的概念:進程就是一個正在執行的程式。

假如我們要運行一個程式,首先找到檔案(如qq.exe)或者捷徑,雙擊開啟。作業系統就會把這個程式的檔案從硬碟上載入到記憶體中,等載入完畢後,CPU開始執行包含在程式中的代碼,然後系統進程列表多了一個qq.exe,這就是進程——正在啟動並執行應用程式。等到這個程式qq.exe運行結束了,系統就會釋放這個程式在記憶體中佔用的空間,並且從進程列表裡移除這個程式。

進程的特點:每個進程都是相互獨立的,互不干擾的。通常情況下,一個進程只能操作自己的代碼和資料,無法對其他進程造成影響。這也保證了windows系統啟動並執行穩定性。

進程=正在記憶體中啟動並執行程式

【windows記憶體的運行原理】

這個是外掛編程的最重要部分,我們分幾個方面討論:1 什麼是記憶體?2 進程的邊界--虛擬記憶體空間 3 開啟進程的邊界

什麼是記憶體

記憶體是電腦中重要的組件之一,它是與CPU進行溝通的橋樑,其存取速度比硬碟快很多倍。記憶體對應是電腦的記憶體條,能儲存資料,但是與硬碟不同,在記憶體中的資料一斷電就會消失,並且存取資料的速度是硬碟的幾十倍,所以將程式載入到記憶體中運行將大大提高程式的運行速度。現在一般的電腦記憶體1GB,2GB,4GB或者更高的8GB。

電腦中所有程式的運行都是在記憶體中進行的,因此記憶體的效能對電腦的影響非常大,並且CPU只能執行和處理在記憶體中代碼和資源。

程式的存在形式實際上是這樣的:我們的程式檔案,首先是以二進位存在於硬碟上的,有的遊戲特別大,幾個GB,當我們開啟資源管理員時,查看的,其實就是硬碟上的檔案。當我們運行程式時,程式會適當的從硬碟載入自己需要的資料,然後開始運行。

由於記憶體比較少,當程式不需要這些資料的時候,就會從記憶體中釋放一些不需要的資源,以保證記憶體的充足。

總的看來當執行一個程式的時候,系統會將exe檔案中的代碼和資源從硬碟載入到記憶體中,載入完成後,CPU開始執行程式進入點的代碼,一個程式開始運行。

程式結束時,將釋放所有這個進程佔用的資源,以避免記憶體的浪費。

概括來說:記憶體,其實儲存運行中的程式碼和資料的地方(CPU只能處理記憶體中的代碼和資料),當進程結束時,該進程所有佔用的記憶體空間將被系統釋放。

進程的邊界--虛擬記憶體空間、

我們設想一下,假如一個系統中有很多的程式在運行,我們只有一個記憶體空間,這樣的話,一個程式在讀寫資料的過程中,由於程式自己本身的缺陷,錯誤的讀寫了其他程式的資料,這樣就很容易影響其他程式,造成其他程式的崩潰。這當然是我們不願意見到的。

為瞭解決程式之間使用記憶體互相干擾的問題,於是便有了虛擬記憶體。

Windows的虛擬記憶體機製為每個進程分配了4GB的虛擬記憶體空間。這裡我們不免產生疑問,我們的實際實體記憶體空間只有1GB或者2GB的,等等,怎麼能給每個進程分配4GB記憶體空間呢?

實際上,這4GB空間最下面的64KB是null 指標賦值地區,系統保留。記憶體最上面的2G被系統佔用。我們能夠訪問和使用的,也只有中間這一部分記憶體而已。這部分記憶體將近2GB,我想對所有程式來說,儲存代碼和資料都是夠用的。

但是每個進程都有這麼大記憶體可以用,這些記憶體空間從何而來呢。Windows在執行一個程式的時候,為了節約記憶體空間,將程式記憶體中暫時用不到的資料,以二進位儲存到硬碟上(這些二進位檔案其實就是分頁檔)。等到需要的時候,再從硬碟上載入到記憶體中,這樣就以犧牲少量CPU已耗用時間為代價,將硬碟當做記憶體使用量。使得多程式同時執行成為了可能。這4GB中的資料,有的是存在於硬碟上的,有的是存在於記憶體中,所以說,每個進程的4GB記憶體空間,是“虛擬”記憶體。

虛擬記憶體的地址一般用十六進位表示,以位元組為單位,位址範圍是0x00000000~0xFFFFFFFF(0x表示十六進位)。

由於這樣的機制,我們不難發現,進程之間就不能相互影響,保證了各進程的穩定性。例如有兩個進程A和B,進程A可以在它自己記憶體空間0x12345678地址儲存資料,進程B也可以在0x12345678地址處儲存資料。當進程A訪問0x12345678處的記憶體時,訪問的是進程A的記憶體空間;當進程B訪問0x12345678處的記憶體時,訪問的是進程B的記憶體空間。進程A無法訪問位於進程B的記憶體空間中的資料,反之亦然。

這就是進程的邊界--每個進程分配了4GB的虛擬記憶體空間,它們在自己的記憶體空間內運行,不會相互幹擾,保護了系統和各進程的穩定性。

為什麼要以16進位表示地址

編程中,我們一般用十進位表示一個數,因為C/C++是進階語言。

例如x=78;
不過,由於資料在電腦中的表示,最終以二進位的形式存在,所以有時候使用二進位,可以更直觀地解決 問題。但位元太長了。比如int 類型佔用4個位元組,32位。比如100,用int類型的位元表達將是:  
0000 0000 0000 0000 0110 0100   
面對這麼長的數進行思考或操作,沒有人會喜歡。因此,C,C++ 沒有提供在代碼直接寫位元的方法。用16進位可以解決這個問題。因為,進位越大,數的表達長度也就越短。

例如同樣一個地址。用十進位和十六效果對比下:

十進位 十六進位
1258965451 4B0A49CB

5600 000015E0

85693 00014EBD

8965231 0088CC6F

這樣可以看到用十六進位表現更直觀一些。並且,在很多軟體中,數值的表示都是用十六進位的,例如WinHex,CE,OllyDBG,幾乎所有與記憶體有關的資料都是用十六進位表示。用十六進位最大的優點就是縮小了表達長度。

開啟進程的邊界 

當然所有的事情不是絕對的,我們有很多時候也需要訪問其他進程中的資料。例如,殺毒軟體要監視其他進程的行為,防止其他進程做有害系統的事,殺毒軟體往往就會在其他進程裡注入自己的代碼,以此來監視其他進程的行為。這就是訪問其他進程資料的最好例子。

當然,想要訪問其他進程的記憶體空間,需要強大的windows api。我們知道,windows api是系統提供給程式員的一組強大的函數,幾乎能實現任何關於系統的任何操作。

我們要開啟進程的邊界,修改其他進程的資料,當然需要調用相應的函數。

我們的目的很明確,就是要修改其他進程(如遊戲進程)的資料。

下面的一些函數是訪問其他進程資料和外掛編程必備的函數,在後面介紹外掛編程的時候,我會詳細的介紹這幾個函數,現在先熟悉一下。

1. 尋找視窗函數

FindWindow

2. 通過視窗擷取進程ID函數

GetWindowThreadProcessId

3. 開啟進程函數

OpenProcess

4. 寫其他進程資料的函數

WriteProcessMemory

5. 讀其他進程資料的函數

ReadProcessMemory

6. 關閉控制代碼的函數

CloseHandle

這六個函數,就是寫一個簡單外掛的所有函數。在後面我會詳細說明開啟進程邊界的步驟,以及如何使用這些函數。

【windows 中控制代碼的概念】

控制代碼,是整個windows編程的基礎。一個控制代碼是指使用的一個唯一的整數值,即一個四位元組長的數值,來標誌系統中的不同對象。

打個比喻,一個學校有很多很多的學生,為了識別這些學生,我們會給每個學生分配一個學號。當我們要找一個學生的時候,我們只需要知道這個學生的學號,然後查閱相關資訊就能找到這個學生。

同樣,在windows系統中有很多很多的對象,如一個表單,一個進程,一個表徵圖,一張圖片,甚至一塊記憶體空間等。Windows 給它們都分配了不同的一個unsigned int型數(即無符號整型數)來標識和區分它們。這個標識號,就叫做控制代碼。

我們可以通過系統分配的這個標識號,也就是控制代碼,來訪問這些對象。

例如,我們可以通過一個視窗的控制代碼,找到這個視窗,然後可以修改這個視窗的大小,標題名字等等。

我們可以通過一個進程的控制代碼,來結束這個進程。

我們可以通過一張圖片的控制代碼,來將這張圖片畫在螢幕上。

等等等等。

控制代碼,就是系統中每個對象的標識號,我們可以通過這些標識號,來訪問相應的系統對象,如表單,進程等等。

【windows變數類型】

在windows編程中,我們往往會看到很多變數類型,如HANDLE,HWND,BYTE,DWORD等等。

這些變數類型是什麼呢,和我們熟悉的char,short,int等等的變數類型有什麼區別呢。

而經常要用到的  控制代碼  HANDLE類型,實質上是無類型指標void,HANDLE定義為:

typedef PVOID HANDLE;

HANDLE實際上就是一個PVOID,那PVOID又是什麼呢?

Typeef void *PVOID;

PVOID就是指向void的指標(void *)。

所以HANDLE = void*

那為什麼要多此一舉呢,直接用void*代替就行了,為什麼要用HNADLE呢?其實,這是為了讓程式員更能讀懂程式。只要看到變數類型就能知道這個變數是用來幹什麼的。

例如:我要用a,b來表示長方形的寬和高,如果都用int型我們要花費一番功夫才能理解這些意思。

但是我們分別定義兩種變數類型Width,Height就能一目瞭然了。

typedef int Width;

typedef int Height;

Width a;   //定義width型變數a,一眼就能看出a變數是來表示寬度的

Height b;   /定義wheight型變數b,一眼就能看出b變數是來表示高度的

聲明特定的變數類型其好處就不言而喻了,就是為了讓程式員更好的理解任何變數的作用,使人一目瞭然。

下面我們需要知道的變數類型以及這些變數類型的作用;

HANDLE =void * HANDLE型變數是一個物件控點

HWND      =void *HANDLE WINDOW 視窗控制代碼

DWORD    = unsigned int   無符號整型,windows通常用來表示一個對象的序號ID

BYTE       =unsigned char   無符號字元型,0255

我們做外掛,只需要瞭解上面3種windows資料類型就行。

另外我需要聲明一點:void *型的變數,一般都是用來表明記憶體位址的,

如 void * Ptr=0x12345678

這個ptr指標,表示的是0x12345678這個記憶體位址

指標我現在不想多說了,這部分在後面的編程中會看到

【輔助的的實現原理】

我們現在做的只是遊戲外掛,有一句古話說的好:知己知彼,方能百戰不殆。我們要做遊戲的輔助,就要Crowdsourced Security Testing道遊戲是怎樣啟動並執行。

我們知道,一個遊戲進程的有很多資料,例如,一個角色的HP,一個角色的經驗,他的金錢,等級,以及裝備都是通過變數來儲存的。我們只要找到這些變數在記憶體中的地址,然後通過某種方法去修改這些數的數值,就能達到修改遊戲的目的。

我們先來說說這些遊戲中德資料,怎麼判斷是什麼類型,怎麼得到在記憶體中占的空間大小。

例如,一個人的經驗一般用int型變數(4位元組)來儲存,為什麼呢?

因為int型變數(4位元組)的取值範圍是2147483648~2147483647,而short型變數(2位元組)的範圍是,由於short的範圍太小,而很多遊戲的經驗值一般都超過這個範圍,例如在地下城與勇士的遊戲中,我的經驗值是108866674523,一千多萬,所以,在這個遊戲中,一個人物的經驗值是必須是int型的,用short型變數會超出範圍導致程式運行出錯。

我們為什麼要知道這些變數佔多大記憶體空間呢?那是因為我們在修改其他進程的資料的時候,我們必須首先要有三個參數:1:在哪個地址 2要修改成多少 3有多大的記憶體資料要被修改。例如:我們要修改的地址是0x00EFFAE0,要修改成1000000,由於這個變數是int型的,所以,有4位元組的記憶體資料要被修改。這很容易讓我們想到遊戲程式的原始碼裡面有這條代碼      

int exp;     //人物經驗

然後&exp就等於0x00EFFAE0

好吧,開始進入正題了。遊戲輔助一般分為兩大部分:

一就是找出我們想要的記憶體位址。

二就是寫程式去修改這個記憶體位址的數到一個相應的數值。

我們先不談第一個部分,因為第一個部分變化性大,因為很多遊戲做了不同程度的保護,使我們找記憶體位址大費周折,例如CS。不過也有遊戲沒做任何保護,例如,植物大戰殭屍。但是,我們寫程式修改其他進程記憶體中的資料,這個方法是不變的。所以我先來說說如何修改其他進程中的記憶體資料。

第一步:尋找遊戲視窗控制代碼

第二步:通過視窗控制代碼,擷取目標進程的ID

第三步:通過目標進程的ID,開啟目標進程,獲得控制代碼

第四步:通過目標進程的控制代碼,修改目標進程的記憶體資料

第五步:關閉目標進程

我想有必要說一下,第一步,第二步是為第三步服務的,我們要修改某一進程的記憶體資料,必須獲得這個進程在系統的身份證,即進程的控制代碼。擷取一個進程的控制代碼有很多方法,我在這裡說的第一步,第二步,第三步是最常用的擷取目標進程控制代碼的方法。

但是,為什麼如此曲折的才能獲得目標進程的控制代碼呢,我想,主要和我們要使用的windows api 有關。

接下來我們就要具體說說這些強大的windows api函數了。我們之前說的所有知識,很多windows運行原理,都是為了理解下一節這些函數的調用。

並且下一節用到的函數較多,我們只有經常使用,我們才能掌握它們。

[編程實現輔助]

上一節我們說了:要修改一個進程的記憶體資料必須先獲得這個進程的控制代碼,就像我們要找一個人一樣,我們可以通過這個人的身份證,知道這個人住在哪裡,才能找到這個人。在windows系統裡面也一樣,我們只有知道這個進程的身份證--控制代碼,系統才能找到這個進程,並相應的按照我們的需求修改資料。

在開始說輔助編程之前,我先要說說一個很有用的函數,這個函數就是MessageBox,先來看看這個函數有什麼效果。

                                     

是不是有種熟悉的感覺,沒錯這就是我經常看見的windows提示,現在我們程式員可以自由操作windows提示。現在來具體說說MessageBox函數

首先來看看函數原型

int WINAPI MessageBox(

HWND hWnd,//訊息視窗父視窗控制代碼

LPCTSTR lpText,//顯示的訊息內容

LPCTSTR lpCaption, //訊息框的標題

UINT uType);//訊息框風格

第一個參數:訊息框的父視窗控制代碼,為了方便,我們可以設為NULL,不影響輔助的使用。

第二個參數:顯示的訊息內容,上面圖片樣本中遊戲已經運行,遊戲沒有運行都屬於訊息內容

第三個參數:訊息視窗標題,上面圖片樣本中都是“提示”。

第四個參數:訊息框的風格,現在我只介紹三個常量

MB_OK:表示有確定按鈕

MB_ICONINFORMATON:表示有資訊表徵圖,上左圖

MB_ICONERROR:表示有錯誤表徵圖上右圖

用 ” | ”符號同時使用多種風格,例如使用MB_OK|MB_ICONINFORMATION,確定按鈕和資訊表徵圖,上左圖所示。MB_OK|MB_ICONERROR,確定按鈕和錯誤表徵圖,上右圖所示。

下面,進入正題我們來說說修改其他進程記憶體資料的第一,二,三步——擷取目標進程的控制代碼,並且學習相應的函數。

第一步:擷取目標遊戲視窗的控制代碼

在windows中,一個視窗的控制代碼資料類型是HWND,就是handle window的簡寫,我們可以這樣,前面我們已經說過windows變數類型的概念,HWND其實就是void*類型的,這裡我就不多說了。重點我們知道怎麼用。

Window API裡面有這麼一個函數,函數原型如下

HWND FindWindow(

LPCSTR  lpClassName,

LPCSTR  lpWindowName);

我們可以知道,傳回值HWND類型的變數是儲存一個視窗的控制代碼的。那麼LPCSTR是什麼變數類型呢?

LPCSTR=char *,這個變數類型其實就是char *類型,是一個字串的指標,以後我們只要看到LPCSTR類型的變數,我們就可以知道這個變數是儲存一個字元床地址的指標的。這就是聲明很多變數類型的好處,看到這個變數是什麼類型的,就知道這個變數是用來幹什麼的。

它有兩個參數,兩個參數都是字串的指標

第一個參數lpClassName,這是要尋找視窗的類名,關於視窗的類名,這裡沒有說明,主要是因為我們可以將此參數設為NULL,也基本不影響我們尋找遊戲視窗的控制代碼。有興趣的可以看看《windws核心編程第5版》,上面說的很詳細。

第二個參數lpWindowName,這個就是主要參數了,目標視窗的標題,例如,植物大戰殭屍的視窗標題就是“植物大戰殭屍中文版”,紅色警戒視窗的標題就是“Red Alert 2”.但是有很多遊戲是全螢幕顯示的,不是表單形式的,沒有標題,那我們怎麼知道它的標題呢?其實有一種很簡單的方法,遊戲全屏運行後,就是按開始菜單鍵將遊戲最小化。然後將滑鼠移動到工作列的遊戲表徵圖上,系統就會提示該表單的標題。

知道了這兩個參數,我們可以這麼寫代碼調用這個函數。

HWND gameWindow=FindWindow(NULL,”植物大戰殭屍中文版”);

當這行代碼執行完畢後我們gameWindow這個變數就儲存遊戲視窗的控制代碼。但是我們需要注意,當目標進程沒有運行,也就是不存在表單標題為”植物大戰殭屍中文版”的表單時,遊戲系統找不到這個視窗,FindWindow調用失敗,傳回值為0,即gameWindow為0。所以這個函數,可以判斷遊戲有沒有運行。加上下面代碼就有這個效果

If(gameWindow==NULL)

//提示遊戲沒有運行

Else

//提示遊戲已運行

第二步:通過視窗控制代碼,獲得進程ID

Windows api提供了這樣一個函數,函數定義如下

DWORD GetWindowThreadProcessId(

HWND hWnd,

LPDWORD lpdwProcessId

);

我們可以看到,這個函數只有兩個參數,第一個參數,就是目標視窗的控制代碼(上例中的gameWindow),我們只要填上我們擷取到的視窗控制代碼就OK

第二個參數LPDWORD,LP代表指標,DWORD代表unsigned int,所以這個參數就代表unsigned int *,是一個不帶正負號的整數型的指標。那麼這個參數是什麼呢?

每個進程不僅有自己的控制代碼,還有自己的序號,在系統中叫ID,這個ID是DWORD型整數,在windows中就叫ProcessID

上面這張圖就是我用tasklist命令列舉出系統中正在啟動並執行進程,上面的PID(ProcessID)就是該進程的標識號,可以看到,wininit.exe進程的ID是516 ,csrss.exe進程的ID是528,等等。我們可以通過目標視窗的控制代碼,知道這個表單是屬於哪個進程的,然後通過這個函數我們就可以知道,這個表單所在進程的ID,我們可以這樣使用。

DWORD pid;

GetWindowThreadProcessID(gameWindow,&pid);

第二個參數傳入一個DWORD變數的地址就行了。

當這行代碼運行完畢後。pid就自動填滿了目標表單所在進程的ID。

第三步通過目標進程的ID,開啟目標進程,獲得控制代碼

Windows api提供了這樣一個函數

HANDLE OpenProcess(

DWORD dwDesiredAccess, //渴望得到的存取權限(標誌)

BOOL bInheritHandle, // 是否繼承控制代碼

DWORD dwProcessId// 進程標示符即,進程ID

);

首先它的傳回值是HANDLE類型的,傳回值就是目標進程的控制代碼。再來看看這三個參數。

第一個參數,我們想要得到的存取權限。這裡我們使用常量PROCESS_ALL_ACCESS,這個是在windows.h裡面定義的常量,注意要全部大寫。用了這個常量,就等於我們對系統說:“我要擷取對該進程操作的所有許可權”,例如讀寫記憶體空間等等。等這個函數調用成功後,我們就可以擷取對該進程進行任何操作了。

第二個參數,我們不考慮,設為NULL。

第三個參數,就是我們獲得的進程ID。

我們可以這麼調用:

HANDLE hProcess=OpenPrcess(PROCESS_ALL_ACCESS,NULL,pid);

這樣這行代碼運行後,hProcess被填充了目標進程的控制代碼。當然,如果這個函數因為某種原因調用失敗的話hProcess就為NULL,所以我們可以加上下面的錯誤處理代碼

If(hProcess==NULL)

//提示開啟進程失敗

好現在總結一下這個步驟。

我們先通過FindWindow找出目標表單的控制代碼

再通過GetWindowThreadProcessId獲得目標進程的ID

最後通過OpenPocess開啟進程,獲得控制代碼

最後需要特別注意一點,在windows xp上這麼寫代碼會運行正常,但是在windows7或者windows8上,程式必須要管理員權限。FindWindow會因為你沒有管理員權限而調用失敗,最後導致你的程式無法正確的獲得目標進程控制代碼。

第四步修改進程的記憶體資料

這是最關鍵的一步了,修改記憶體資料。前面我們已經說過,外掛主要分為兩個重要步驟,第一個是找記憶體位址,哪些資料是我們要修改的,如一個人的金錢,經驗,屬性,等級。我們要找出這些資料在進程中的記憶體位址。第二步就是寫程式去修改這些資料。寫程式修改資料的方法是一成不變的,但是找記憶體位址卻有很大的技巧性。這裡限於篇幅就不多說了,後面我會簡單的介紹一下找代碼的原理,然後我會推薦一些專門的文章給大家看的。

Window提供了下面一個函數來修改進程的記憶體資料,函數定義如下

BOOL WriteProcessMemory(

HANDLE hProcess,//目標進程控制代碼

LPVOID lpBaseAddress,//目標進程寫入地址

LPVOID lpBuffer,//自己進程中緩衝區地址

DWORD nSize,//緩衝區大小

LPDWORD lpNumberOfBytesWritten//實際資料長度,設為NULL

);

傳回值是BOOL型,返回TRUE調用成功,FALSE調用失敗

第一個參數:目標進程的控制代碼,我們可以通過前三步獲得目標進程的控制代碼

第二個參數:目標寫入的起始地址,即要將資料寫到目標進程哪個位置。這個就是我們找到的記憶體位址,例如一個人的血量記憶體位址是0x40000000

第三個參數:寫入的緩衝區地址

第四個參數;寫入的緩衝區大小

這第三個,第四個參數是什麼意思呢?其實WriteProcessMemory工作原理是這樣的

我們將自己進程中的資料,拷貝到其他進程中。自己這個緩衝區的地址就是第三個參數lpBuffer,緩衝區的大小事第四個參數nSize。這個函數將我們進程中lpBuffer地址起始處nSize大小的資料,原封不動的拷貝到目標進程的 lpBaseAddress(第二個參數)處。

假如,我們找到遊戲進程人物金錢的地址是0x40000000,,我們就可以這樣寫代碼

Int Money=10000000;//定義一個變數後自己進程已經分配一塊地區存這個變數

WriteProcessMemory(hProcess,(LPVOID)0x40000000,(LPVOID)&Money,,(DWORD)4,NULL);

第一個參數我們填入目標進程的控制代碼

第二個參數是目標進程的寫入地址,編譯器認識“0x”,知道0x40000000是一個16進位的數,我們將這個數強制轉換成LPVOID型,也就是void*型,無值型指標

第三個參數我們填入了我們進程Money變數的地址,並且將這個變數地址強制轉換成LPVOID型。

第四個參數由於在c++中int型變數預設佔四個位元組記憶體空間,所以我們填入4,並將這個數轉換成LPVOID型

第五個參數 填NULL

這就是WriteProcessMemory的用法,功能強大,能寫其他進程的資料。

這樣,我們就完成了第四步,寫遊戲記憶體資料,我們再次回到遊戲會發現,遊戲中相應的資料已經變成我們想要的數值了,看,植物大戰殭屍修改後的結果

 

第五步關閉進程控制代碼

我們需要調用CloseHandle函數來關閉我們開啟的進程,這個函數的使用方法很簡單。

CloseHandle(hProcess);

它只有一個參數------要關閉的控制代碼這裡我們填入我們開啟的進程控制代碼即可。

至此我們已經看到了一個完整的程式碼

我們來回顧一下

我想沒有什麼能比真實的遊戲輔助原始碼更好的瞭解外掛了,下面,我將給出Vc++6.0環境下,植物大戰殭屍輔助的真實原始碼。我把修改代碼放到了ChangeGame函數裡面,我們只要在main函數或者WinMain中調用這個函數就ok

void ChangeGame()

{

//通過標題擷取視窗

HWND gameWindow=FindWindow(NULL,"植物大戰殭屍中文版");

if(!gamewindow)

MessageBox(NULL,”遊戲未運行”,”錯誤”,MB_OK|MB_ICONERROR);

//擷取進程標示符pid

DWORD pid;

GetWindowThreadProcessId(gameWindow,&pid);

//開啟進程

HANDLE hprocess=OpenProcess(PROCESS_ALL_ACCESS,0,pid);

//修改資料

int sun=56789;

WriteProcessMemory(hprocess,(void *)0x1429E2B0,&sun,4,0);

//關閉進程

CloseHandle(hprocess);

 

}

[怎樣尋找記憶體位址]

CE是一個強大的工具,它的搜尋速度非常快,一般的遊戲程式用它來搜尋記憶體能在短短數秒內搜尋幾百萬甚至幾千萬個記憶體位址。為我們編寫外掛提供了很大的協助。

好,廢話不多說,邊邊解說,先來學學簡單的記憶體修改,熟悉熟悉CE的操作。

第一步:選擇目標進程

                         

先點擊左上方的第一個按鈕,會出現右圖進程列表。該列表中列舉出了系統中所有正在啟動並執行程式。我們選擇植物大戰殭屍程式(PlantVsZombies.exe)。這樣就完成了選擇目標進程。

第二部:搜尋陽光的記憶體位址

先運行植物大戰殭屍,開始一局遊戲,我們的目的是要修改陽光。於是先看看陽光現在是多少,150,很好(下左圖)。我們在CE值裡面的填入150,點擊首次掃描(下右圖)

                     

看CE左邊的地址欄,我們可以看到,我們用CE搜尋到了145個地址(下左圖)。這說明在這個遊戲中,有這麼多個地址的值是150.。但是我們所需要的陽光的變數,只是這麼多其中的一個,所以我們種一顆植物,現在陽光變成了50,然後我們輸入50,點擊再次掃描(下右圖)

                       

再次掃描其實是在上次掃描的結果中,再次搜尋這些結果的值。當我們通過遊戲操作修改我們所需要的變數的值的時候,通過再次搜尋就很容易把我們想要的變數找出來。之後會出現下面的結果

                              

我們可以看到,結果地址裡面只有一個了,沒錯,這個搜尋到的地址0x1429E2B0就是我們要找到陽光的地址。我們雙擊這個地址,這個地址會出現在下面。的編輯列表裡,我們再雙擊編輯列表裡這個地址的值,輸入56789,點確定。這個時候我們回遊戲就會發現已經變成我們想要的值了。

好了,這是找記憶體的最簡單的方法。但是還有一些問題。

第一個問題:

事實上,有很多遊戲都做了一些保護措施。例如你的植物大戰殭屍裡面金幣顯示的是1120,但是實際上在記憶體中這個值是112。如果你一開始搜1120,並且按照這個方法搜下去的話會一個地址也搜不到。相同的例子還有很多。例如俠盜飛車人物的血量上面顯示的是87,在記憶體中這個數值是17023+87,流星蝴蝶劍中你看到你的血是230,但是在記憶體中你的血的值是2300等等。

第二個問題:

如果你重啟植物大戰殭屍後會發現,陽光變數的地址發生了改變,變成0x143780B4,這是為什麼呢。因為植物大戰殭屍中,儲存陽光的變數地址是動態分配的,每次分配的地址都是不一樣呢。

這就是編程中的局部變數,這個局部變數所屬的函數執行完了,這個局部變數就會從記憶體中釋放。等下次再次執行這個函數時,這個局部變數又會從記憶體中重新分配空間。

這樣每次運行植物大戰殭屍,由於動態分配,每次陽光變數的的地址都是不一樣的。

所以說,搜尋也是有一定複雜性的。第一個問題可以通過模糊搜尋,多次搜尋解決。第二個問題,可以通過尋找變數的位移地址,計算出準確的陽光地址(這個需要ReadProcessMemory函數)或者通過反組譯碼。

雖然聽起來很複雜,但是這些搜尋技巧其實都是很簡單的,這裡就不一一介紹了。因為要說搜尋記憶體的方法的話,說清楚沒有幾千字是不行的。這篇文章主要是說外掛編程的原理,關於記憶體搜尋的方法,我找到幾篇很好的文章,大家看一看就足夠了:

CE找記憶體位移地址圖文教程:

http://bbs.52miji.com/thread-1224-1-1.html

CE搜尋記憶體技巧:

http://www.v5pc.com/thread-572-1-1.html

關於找記憶體位址就說到這裡。

[總結]

遊戲輔助,其實就是用來修改遊戲,方便玩家玩遊戲的的一個軟體工具。

這篇文章所說的遊戲修改都是初級的遊戲修改,只涉及到修改記憶體變數。事實上,像進階的遊戲修改,例如消除冷卻時間,修改遊戲介面,改變遊戲運行邏輯等等,這些知識還遠遠不夠。這些都需要最低級而又最強大的組合語言來解決。通過反組譯碼逆向分析遊戲代碼,修改遊戲代碼而達到令人咋舌效果。

例如LOL盒子,至少運用了DLL遠線程注入,函數擋截,反組譯碼代碼修改等等技術,所以能夠給遊戲添上一些協助工具功能。

學習編程的道路很漫長,有很多的非常有用知識不是課堂上能學到的,等著你自己去發現,去挖掘。等你深入到某一領域的時候,你會發現,這裡還有非常廣闊的天空,你要用一生的時間去探索它,掌握它。

初級遊戲外掛編程詳解 windows運行原理+遊戲輔助編程 遊戲外掛編程

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.