1. 程式人生 > >遊戲外掛製作原理

遊戲外掛製作原理

遊戲外掛開發原理

       外掛現在大體上來講分為三種,分別是模擬按鍵,WPE封包和記憶體掛。比如模擬鍵盤的,滑鼠的,這種就叫做按鍵模擬,也叫指令碼精靈;還有修改資料包的,這種就叫做WPE封包外掛,這種外掛相對而言比較穩定,但是對於技術要求難度也比較高,因為修改WPE封包,你需要知道和了解加密解密演算法等等一系列的知識;還有最後一種就是修改本地記憶體的,這種相對而言比較常見,市場上面比較常見的也是這種遊戲外掛,相對而言技術要求也不是太高,資料也比較齊全,比較大眾;但好像沒有修改伺服器記憶體的哦,呵呵。其實修改伺服器也是有辦法的,只是技術太高一般人沒有辦法入手而已。這裡就記一下本地修改記憶體的外掛製作原理。


       其實,製作記憶體掛也不是很難,步驟就這麼幾步。第一步,找遊戲資料記憶體地址,偏移地址;第二步,修改記憶體地址的值,達到外掛的目的;第三步,用程式語言寫出一個程式,使得外掛方便於攜帶傳輸,同時也方便於下次玩遊戲直接使用。其實第三步主要是方便使用,方便販賣等等,很多時候對於一個高手而言,根本不需要寫出來,記錄下記憶體地址,偏移地址以後,下次上游戲直接工具裡面修改就是了。但是如果經常玩某個遊戲,可以寫出來,用不著每次玩遊戲都去修改。

外掛開發第一步——找遊戲記憶體地址

       說道找遊戲記憶體地址,偏移地址,這可能是整個遊戲外掛開發中最難的一步,因為一個大型的網路遊戲,可能一個技能或者血條的記憶體基址可能會偏移很多次,最後才得到一個記憶體地址也叫實體地址。那麼,這裡有個問題來了,我們為什麼要找技能或者血條的記憶體基址?不是直接修改實體地址就行了嗎?這樣是不行的,因為實體地址是會變動的;舉個例子,每次關閉遊戲重新啟動以後,遊戲程序是會變動的,同樣的,遊戲程式碼在記憶體中的存放位置,因為遊戲結束以後,釋放掉了記憶體地址,這個記憶體地址可能會被其他程式所佔用,所以是會變動的;當你關閉遊戲重新進入以後,遊戲的技能或者血條在記憶體中的實體地址就變了。但是,遊戲技能或者血條的記憶體基址是不會變動的,在記憶體中的實體地址不管怎麼變動,記憶體基址都不會變動。那麼記憶體基址和實體地址之間是一種什麼樣的關係呢?看下面這個公式:

1
2
3
4
實體地址 = 一級偏移地址 + 偏移地址
一級偏移地址 = 二級偏移地址 + 偏移地址
二級偏移地址 = 三級偏移地址 + 偏移地址
三級偏移地址 = 遊戲技能基址 + 偏移地址

 

       如上公式,一個遊戲的實體地址是等於這個遊戲的基址加上偏移地址的,所以,想要每次重新進入遊戲都能夠找到準確的實體地址進行修改記憶體地址的值,達到外掛的目的的話,就必須找到這個實體地址當前對應的偏移地址和基址,只有這樣才能夠確保每次登陸游戲都能夠修改實體地址的值。下面,就通過《植物大戰殭屍》這款經典的單機遊戲來演示一下找這款遊戲的記憶體基址的過程。
       首先,介紹一款找遊戲記憶體基址的工具Cheat Engine簡稱CE,Cheat Engine是一款記憶體修改編輯工具 ,它允許修改遊戲或軟體記憶體資料,以得到一些其他功能。它包括16進位制編輯,反彙編程式,記憶體查詢工具。與同類修改工具相比,它具有強大的反彙編功能,且自身附帶了外掛製作工具,可以用它直接生成外掛。好了,這個工具的具體介紹有興趣的去百度,這裡也就是百度了一下,簡單的說了一下這個工具的作用,下面,開啟植物大戰殭屍,開啟CE,在CE中找到植物大戰殭屍,附加到CE中去,如圖所示:

iHbEFK.png
iHbZWD.png
       遊戲附加到OD以後,看自己想修改哪兒的內容,就去找對應的記憶體基址,怎麼找呢?比如修改無限陽光吧;首先,看一下最開始的陽光是多少?比如這裡,開局陽光是50,就在CE中數值一項輸入50,掃描型別選擇精確數值數值型別選擇4位元組然後點選首次搜尋,這裡不懂為什麼這樣選擇的,自己百度科普一下基礎知識。如圖所示:
iHqFXj.png
       如上圖所示,出來了這麼多的地址,究竟哪一個是我們想要的實體地址呢?接下來就需要在遊戲中改動一下陽光的值,然後點選再次搜尋,結果就會出來了,如圖所示:
iHqeA0.png
iHqnhT.png
       如上第二幅圖所示,我們想要的實體地址就出來了,把這個地址新增到地址列表中去,然後修改一下陽光的值,確認一下是不是想要的地址,不過這裡要注意,在修改的時候,我們需要點選列表地址中我們拉下來的這一行的數值這一欄,其他是修改地址和位元組型別用的,不要亂動,如圖所示:
iHqljJ.png
       如上圖所示,這就是我們想要的實體地址,這裡我們可以鎖定這個記憶體地址的值,一直是100或者200或者更多。只需要點選前面啟用這一欄選中就行了,從而達到鎖定陽光值的效果。但是當關閉遊戲,重新進入,這個地址就沒用了,又需要重新找。所以,這裡就需要找到真正的陽光值的基址和偏移地址,那麼,怎麼找呢?我們找到這個實體地址以後,就右鍵,選擇找出是什麼改寫了這個地址也就是快捷鍵F6這個名字每個版本的漢化效果都不一樣的,這裡就會彈出一個視窗,是空白,然後我們再到遊戲中改變陽光的值,看看這個空白視窗中出現的程式碼,如圖所示:
iHqb5V.png
iHqxKJ.png
iHLCUx.png
       如上圖三所示,分析這兩條程式碼,看見最終都指向了一個指標數值17C88118,然後我們分析一下這兩條程式碼什麼意思,相信稍微懂一點組合語言的人都能夠看懂。首先分析一下mov [edi+00005560],esi這條指令,我們在詳細資訊中看見,暫存器esi中的程式碼是000026DE這個值換算成十進位制剛好是9950,那麼這個9950是怎麼來的呢?其實就是剛剛我在做上一步的時候,說了要變動遊戲中的陽光值,所以我先直接把陽光值修改成了10000,然後種了一個石頭,剛好是50,所以陽光值發生了變化,這條指令mov [edi+00005560],esi就是把暫存器esi的9950的陽光值放入edi+00005560這個地址中去,這個地址是誰呢?其實這個地址就是剛剛找出來的實體地址,剛好滿足前面的公式:實體地址 = 陽光基址地址 + 偏移地址不信的朋友可以自己加一下算一算,用暫存器edi裡面的指標數值17C88118加上偏移地址00005560看看是不是等於陽光實體地址17C8D678。接下看看add [eax+00005560],ecx這條指令,add指令是相加的意思,前面的mov是賦值或者移動的意思,這條程式碼的意思就是,把ecx暫存器中的值加入[eax+00005560]這個地址中的值當中去,再看看暫存器eax的地址是多少?剛好又是17C88118這個指標數值,那麼,我們就可以確定一個事情,那就是17C88118這個指標數值,肯定是上一級的地址的指標數值,那麼上一級要麼是基址,要麼還是一個不偏移地址,這個需要進一步來確認。怎麼確認呢?這裡不是出來了17C88118這個指標數值嘛,再次放到CE中搜索一波,看看這個值對應的地址是多少,看看出來的是一個動態地址還是靜態地址,這裡需要普及一個知識點,在CE中,黑色的地址表示動態地址,綠色的表示靜態地址,那好,丟到CE中搜索,這裡這個值是十六進位制的,所以在搜尋的時候,需要勾選搜尋框前面的hex,也就是十六進位制搜尋的意思,這裡填好以後點選新的掃描,首次掃描如圖所示:
iHjMI1.png
       這裡可以看見結果為56個地址,這麼多,我們怎麼來確認究竟是哪個呢?可以看見還有很多紅色的地址。其實,這裡的紅色的地址,是一直在改變的地址,我們不用管它,直接點選再次掃描,把這些紅色的過濾掉,然後看看還剩下的地址有哪些,如圖所示:
iHjJMD.png
       多次點選再次掃描以後發現不管怎麼點選都剩下來了52個結果,然後看了一下這些結果中並沒有綠色的靜態地址,並且其他地址開頭幾位都比較像,唯獨如圖所示兩個地址比較特殊,這兩個可能就是我們需要的地址了,後來我也去百度了一波,結果所說的是這種開頭比較像的是陣列,也就是說,遇到這種,基本都不是我們需要的地址,直接放棄,把這兩個特殊的拉進下邊的地址列表,開始分析,雙擊地址這一欄,在出來的更改地址視窗中複製下這個地址,然後再勾選指標選項,在出來的內容框中填寫入剛剛複製的地址,在上面的內容框中寫入剛剛找到的00005560這個偏移地址,得到的結果剛好是陽光的實體地址,最後的陽光值也正好和當前的陽光值一樣,並且,這兩個地址都是一樣的,而且都是動態地址,如圖所示:
iHj2Zj.png
iHjhiq.png
       如上圖所示,這兩個地址加上偏移地址都可以得到陽光實體地址,那麼哪個才是我們所需要的真正的一級偏移地址呢?這裡就需要我們對這兩個地址進行詳細的分析了,同樣的右鍵-找出是什麼訪問了這個地址,也就是快捷鍵的F5,這裡一定不要搞混淆了,前面是找出是什麼改寫了這個地址,不一樣的!我們進去以後也是和前面一樣出來一個視窗,但是這兩個窗口裡面的內容就不一樣了,第一個地址0264A400F5找出是什麼訪問了這個地址以後的視窗中會出現內容,但是第二個地址0956BD3C在出現的窗口裡面是一片空白,所以,這兩個地址中,0264A400才是我們要找的真正的一級偏移地址,如圖所示:
iHjvJx.png
iHjxW6.png
       如上第二幅圖所示,找到了真正的一級偏移地址0264A400後,訪問這個地址的視窗中看這些程式碼指令,通過對比,發現這些程式碼都指向同一個指標數值02649C98且都有偏移地址00000768,如圖所示:
iHvCOe.png
     如上圖所示,既然所有的程式碼都指向了同一個指標數值02649C98那麼就繼續按照前面找一級偏移地址的辦法,丟到CE中,繼續新的十六進位制搜尋,搜尋指標數值02649C98以後得到如下圖所示的結果:
iHvlwj.png
     如上圖所示,一共搜尋到923個地址,而且還有幾個綠色的靜態地址,這裡我們就可以嘗試一下了,看看這幾個綠色的靜態地址究竟是不是我們想要的陽光基址,同樣的原理,我們把幾個綠色的靜態地址拉到地址列表中,在地址這一欄雙擊,在出來的更改地址視窗中複製下這個地址,然後再勾選指標選項,在出來的內容框中填寫入剛剛複製的地址,在上面的內容框中寫入剛剛找到的00000768這個偏移地址,然後再點選新增偏移在出來的內容框中輸入剛剛第一次找到的00005560這個偏移地址,得到的結果剛好是陽光實體地址和陽光當前的值,並且這幾個靜態地址的結果都是一樣的。這裡需要說明一下,為什麼這裡要填寫兩個偏移地址,因為剛剛第一次找到的是一級偏移地址,這次是二級偏移地址了,所以,這裡

1
2
3
陽光實體地址 = 一級偏移地址 + 偏移地址
一級偏移地址 = 陽光基址 + 偏移地址
陽光實體地址 =陽光基址 + 第一次的偏移地址 + 第二次的偏移地址

 

如圖所示:
iHx3uD.png
iHx0v8.png
iHxDKS.png
iHxsbQ.png
     如上四幅圖所示,四個靜態地址最終結果都是一樣的,都可以用作陽光基址,那麼就隨便取一個就行。這樣,陽關的基址和偏移地址就找到了,陽光的基址和偏移地址如下:

1
2
3
陽光基址:006A9EC0
一級偏移:00000768
二級偏移:00005560

 

     這裡可能有人會問,一級偏移地址不是我們第一次找出來的地址嗎?你這裡的一級偏移不應該是00005560嗎?對,也不對,我這裡所說的一級偏移不是一級偏移地址的偏移,而是基於陽光基址的一級偏移,可以理解為從陽關基址開始,第一次偏移是00000768第二次偏移才是00005560,這樣做主要是為了方便後面寫程式碼。好了,這就是找遊戲基址的思路,同樣的道理,還可以找植物冷卻時間,不過找冷卻時間思路不太一樣,因為冷卻時間我們不知道具體的值,可以通過找未知的初始化值的方式來找,也可以通過位元組的方式來找,具體詳見百度,我這裡只是把找遊戲記憶體基址的思路和過程中怎麼分析的給寫了出來,免得後人掉坑,比如我在找植物冷卻時間的時候,就掉了一個坑,我是通過位元組的方式來找來找的,通過植物冷卻的時候為0,冷卻好了為1找到了實體地址以後,在找一級偏移地址的時候,忘記把搜尋方式位元組換為4位元組型了,找了半天沒找到!其他思路是一樣的!

外掛開發第二步——修改遊戲記憶體地址的值

     其實,這一步就比較簡單了,比如陽光的值,找到了以後,我們每次上游戲,直接在CE的地址列表框中手動新增地址,把像上面我們驗證這幾個基址的時候一樣,把基址,偏移地址填寫好,然後在數值這一欄雙擊,修改數值成為我們想要的陽光值就可以了,冷卻就把數值改為1即可,這一步就不用過多的提及了!

外掛開發第三步——編寫遊戲外掛

     其實編寫外掛只有會寫程式的人都知道該怎麼弄了,只要找出來想要的功能的記憶體基址,偏移等,直接在程式中寫上讀取和寫入記憶體地址就行了,下面就是我寫的植物大戰殭屍的外掛的原始碼,簡單的分析一波:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
.版本 2

.程式集 視窗程式集_啟動視窗
.程式集變數 程序ID, 整數型
.程式集變數 a, 整數型

.子程式 __啟動視窗_建立完畢, , , 視窗建立完畢就利用時鐘事件獲取陽光值並輸出

程序ID = 取程序ID (“PlantsVsZombies.exe”)
時鐘1.時鐘週期 = 999

.子程式 _時鐘9_週期事件

標籤提示資訊.左邊 = 標籤提示資訊.左邊 - 2
.如果真 (標籤提示資訊.左邊 = -300)
    標籤提示資訊.左邊 = 300
.如果真結束


.子程式 _時鐘1_週期事件, , , 獲取陽光值並輸出
.區域性變數 讀陽光基址, 整數型
.區域性變數 讀偏移地址一, 整數型
.區域性變數 陽光實體地址, 整數型

讀陽光基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9EC0”), )
讀偏移地址一 = 讀記憶體整數型 (程序ID, 讀陽光基址 + 十六到十 (“768”))
陽光實體地址 = 讀記憶體整數型 (程序ID, 讀偏移地址一 + 十六到十 (“5560”), )
標籤當前陽光值.標題 = “當前陽光值:” + 到文字 (陽光實體地址)

.子程式 _編輯框輸入陽光值_獲得焦點, , , 設定輸入框在被獲取焦點以後情況編輯框內容

編輯框輸入陽光值.內容 = “”

.子程式 _按鈕增加陽光_被單擊, , , 增加陽光值
.區域性變數 取陽光基址, 整數型
.區域性變數 取偏移地址一, 整數型
.區域性變數 取陽光實體地址, 整數型

取陽光基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9EC0”), )
取偏移地址一 = 讀記憶體整數型 (程序ID, 取陽光基址 + 十六到十 (“768”))
取陽光實體地址 = 讀記憶體整數型 (程序ID, 取偏移地址一 + 十六到十 (“5560”), )
a = 到整數 (編輯框輸入陽光值.內容)
寫記憶體整數型 (程序ID, 取偏移地址一 + 十六到十 (“5560”), 取陽光實體地址 + a)

.子程式 _按鈕減少陽光_被單擊
.區域性變數 取陽光基址, 整數型
.區域性變數 取偏移地址一, 整數型
.區域性變數 取陽光實體地址, 整數型

取陽光基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9EC0”), )
取偏移地址一 = 讀記憶體整數型 (程序ID, 取陽光基址 + 十六到十 (“768”))
取陽光實體地址 = 讀記憶體整數型 (程序ID, 取偏移地址一 + 十六到十 (“5560”), )
a = 到整數 (編輯框輸入陽光值.內容)
寫記憶體整數型 (程序ID, 取偏移地址一 + 十六到十 (“5560”), 取陽光實體地址 - a)


.子程式 _按鈕鎖定陽光值_被單擊, , , 鎖定陽光值

時鐘2.時鐘週期 = 100

.子程式 _時鐘2_週期事件, , , 鎖定陽光值時鐘事件
.區域性變數 鎖定陽光基址, 整數型
.區域性變數 鎖定偏移地址一, 整數型
.區域性變數 鎖定陽光實體地址, 整數型

鎖定陽光基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9EC0”), )
鎖定偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定陽光基址 + 十六到十 (“768”))
鎖定陽光實體地址 = 讀記憶體整數型 (程序ID, 鎖定偏移地址一 + 十六到十 (“5560”), )
寫記憶體整數型 (程序ID, 鎖定偏移地址一 + 十六到十 (“5560”), 1000)

.子程式 _按鈕取消鎖定陽光_被單擊, , , 取消鎖定陽光值

時鐘2.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻1_被單擊, , , 鎖定冷卻1

時鐘3.時鐘週期 = 100

.子程式 _時鐘3_週期事件, , , 鎖定冷卻1時鐘事件
.區域性變數 鎖定冷卻一基址, 整數型
.區域性變數 鎖定冷卻一偏移地址一, 整數型
.區域性變數 鎖定冷卻一偏移地址二, 整數型
.區域性變數 鎖定冷卻一實體地址, 整數型

鎖定冷卻一基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9F38”), )
鎖定冷卻一偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻一基址 + 十六到十 (“768”))
鎖定冷卻一偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻一偏移地址一 + 十六到十 (“144”), )
鎖定冷卻一實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻一偏移地址二 + 十六到十 (“70”), )
寫記憶體整數型 (程序ID, 鎖定冷卻一偏移地址二 + 十六到十 (“70”), 1)

.子程式 _按鈕取消鎖定冷卻1_被單擊, , , 取消鎖定冷卻1

時鐘3.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻2_被單擊, , , 鎖定冷卻2

時鐘4.時鐘週期 = 100

.子程式 _時鐘4_週期事件, , , 鎖定冷卻2時鐘事件
.區域性變數 鎖定冷卻二基址, 整數型
.區域性變數 鎖定冷卻二偏移地址一, 整數型
.區域性變數 鎖定冷卻二偏移地址二, 整數型
.區域性變數 鎖定冷卻二實體地址, 整數型

鎖定冷卻二基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006A9F78”), )
鎖定冷卻二偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻二基址 + 十六到十 (“768”))
鎖定冷卻二偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻二偏移地址一 + 十六到十 (“144”), )
鎖定冷卻二實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻二偏移地址二 + 十六到十 (“C0”), )
寫記憶體整數型 (程序ID, 鎖定冷卻二偏移地址二 + 十六到十 (“C0”), 1)

.子程式 _按鈕取消鎖定冷卻2_被單擊, , , 取消鎖定冷卻2

時鐘4.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻3_被單擊, , , 鎖定冷卻3

時鐘5.時鐘週期 = 100

.子程式 _時鐘5_週期事件, , , 鎖定冷卻3時鐘事件
.區域性變數 鎖定冷卻三基址, 整數型
.區域性變數 鎖定冷卻三偏移地址一, 整數型
.區域性變數 鎖定冷卻三偏移地址二, 整數型
.區域性變數 鎖定冷卻三實體地址, 整數型

鎖定冷卻三基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006AA00C”), )
鎖定冷卻三偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻三基址 + 十六到十 (“768”))
鎖定冷卻三偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻三偏移地址一 + 十六到十 (“144”), )
鎖定冷卻三實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻三偏移地址二 + 十六到十 (“110”), )
寫記憶體整數型 (程序ID, 鎖定冷卻三偏移地址二 + 十六到十 (“110”), 1)

.子程式 _按鈕取消鎖定冷卻3_被單擊, , , 取消鎖定冷卻3

時鐘5.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻4_被單擊, , , 鎖定冷卻4

時鐘6.時鐘週期 = 100

.子程式 _時鐘6_週期事件, , , 鎖定冷卻4時鐘事件
.區域性變數 鎖定冷卻四基址, 整數型
.區域性變數 鎖定冷卻四偏移地址一, 整數型
.區域性變數 鎖定冷卻四偏移地址二, 整數型
.區域性變數 鎖定冷卻四實體地址, 整數型

鎖定冷卻四基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006AA00C”), )
鎖定冷卻四偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻四基址 + 十六到十 (“768”))
鎖定冷卻四偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻四偏移地址一 + 十六到十 (“144”), )
鎖定冷卻四實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻四偏移地址二 + 十六到十 (“160”), )
寫記憶體整數型 (程序ID, 鎖定冷卻四偏移地址二 + 十六到十 (“160”), 1)

.子程式 _按鈕取消鎖定冷卻4_被單擊, , , 取消鎖定冷卻4

時鐘6.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻5_被單擊, , , 鎖定冷卻5

時鐘7.時鐘週期 = 100

.子程式 _時鐘7_週期事件, , , 鎖定冷卻5始終事件
.區域性變數 鎖定冷卻五基址, 整數型
.區域性變數 鎖定冷卻五偏移地址一, 整數型
.區域性變數 鎖定冷卻五偏移地址二, 整數型
.區域性變數 鎖定冷卻五實體地址, 整數型

鎖定冷卻五基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006AA00C”), )
鎖定冷卻五偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻五基址 + 十六到十 (“768”))
鎖定冷卻五偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻五偏移地址一 + 十六到十 (“144”), )
鎖定冷卻五實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻五偏移地址二 + 十六到十 (“1B0”), )
寫記憶體整數型 (程序ID, 鎖定冷卻五偏移地址二 + 十六到十 (“1B0”), 1)

.子程式 _按鈕取消鎖定冷卻5_被單擊, , , 取消鎖定冷卻5

時鐘7.時鐘週期 = 0

.子程式 _按鈕鎖定冷卻6_被單擊, , , 鎖定冷卻6

時鐘8.時鐘週期 = 100

.子程式 _時鐘8_週期事件, , , 鎖定冷卻6時鐘事件
.區域性變數 鎖定冷卻六基址, 整數型
.區域性變數 鎖定冷卻六偏移地址一, 整數型
.區域性變數 鎖定冷卻六偏移地址二, 整數型
.區域性變數 鎖定冷卻六實體地址, 整數型

鎖定冷卻六基址 = 讀記憶體整數型 (程序ID, 十六到十 (“006AA00C”), )
鎖定冷卻六偏移地址一 = 讀記憶體整數型 (程序ID, 鎖定冷卻六基址 + 十六到十 (“768”))
鎖定冷卻六偏移地址二 = 讀記憶體整數型 (程序ID, 鎖定冷卻六偏移地址一 + 十六到十 (“144”), )
鎖定冷卻六實體地址 = 讀記憶體整數型 (程序ID, 鎖定冷卻六偏移地址二 + 十六到十 (“200”), )
寫記憶體整數型 (程序ID, 鎖定冷卻六偏移地址二 + 十六到十 (“200”), 1)

.子程式 _按鈕取消鎖定冷卻6_被單擊, , , 取消鎖定冷卻6

時鐘8.時鐘週期 = 0

 

     由於是易語言寫的,比較簡單快捷,我大概說一下就好了,就是在外掛軟體啟動以後,我就讀取植物大戰殭屍的遊戲程序ID,然後讀取陽光的實體地址,加以輸出顯示,然後在啟動視窗建立完畢的時候還加了一個時鐘,達到實時監控陽光值的目的,然後設定了幾個按鈕,分別是增加陽光、鎖定陽光、鎖定冷卻時間和減少陽光、取消鎖定陽光、取消鎖定冷卻時間。下面分別來說一下幾個按鈕怎麼實現功能的。

增加陽光
增加陽光就定義了一個全域性變數,變數中獲取輸入框中的值,然後讓陽光實體地址裡面的值加上輸入的值,就達到了增加陽光的目的!

減少陽光
減少陽光和增加陽關的寫法一模一樣,只不過把陽光實體地址裡面的值設定為了減去輸入的值而已,這樣就達到了減少陽關的目的!

鎖定陽光
鎖定陽光我定義了一個時鐘,設定時鐘週期為999毫秒,然後設定了陽光固定值1000。當按鈕鎖定陽光被單擊以後,就執行這個時鐘的時鐘週期,也就是每隔999毫秒執行一次時鐘下面的程式碼,也就是執行在陽光實體地址中改陽光的值為1000,這樣就達到了鎖定陽光的目的!

取消鎖定陽光
取消鎖定陽光其實就是把鎖定陽光這個時鐘的時鐘週期設定為0,當取消鎖定陽光的按鈕被單擊以後,就執行這個時鐘週期事件,時鐘下面的程式碼也就不執行了,達到了取消陽光鎖定的目的!
     後面的鎖定冷卻時間和取消鎖定冷卻時間的原理和上面鎖定陽光和取消鎖定陽光的原理一樣,就不再做詳細的解釋了,因為我這裡針對每個欄位的植物做了單獨的冷卻鎖定和取消鎖定,所以程式碼比較長,其實在找植物冷卻時間的時候,可以配合OD,直接找到冷卻時間前面的迴圈幹掉,這樣所有的植物欄的冷卻時間都沒了!

總結

     其實不管是單機遊戲也好,還是網路遊戲也罷,原理都一樣,只不過,可能遊戲型別不同,所需要的東西也不一樣,比如射擊類遊戲,就需要D3D技術來做人物透視的定位等等,這個具體的方法,可以百度參考。但是萬變不離其中,都是找記憶體基址,找偏移地址。