工具:
VB6企業(yè)版(盜版)/VB6精裝版
CE
一,打開游戲和CE用CE載入游戲
二,讓你的血量回到最滿狀態(tài),記住血量值

如上圖,我的是1312點血,好的,用CE搜"1312",.用"Exact value"方式,4字節(jié)

搜到N個址,好,再回到游戲里,我們讓人物掉點血(打怪什么的,最好多掉點,這樣方便后面來查數(shù)),再用"Decreased value"(減少了的數(shù))來搜,這樣掉點血,搜一次,搜點血搜一次,幾次下來,好的,找到的地址就只剩四個了(我是兩次就找到只剩四個了,電腦不同,可能找的次數(shù)也不同,不過方法是一樣的,先找最大血量值,然后,再掉點血,再用減少的搜,如此循環(huán)幾次就OK了)記下第一個地址(為什么用第一個地址,CE的教程里說,一般如果找到少量的地址后,正確的一般在第一個,如果你不確定,你可以讓人物自動回血,就可以看到,第一個地址的數(shù)也在跟著增加~)

接著,把第一個地址雙擊,加入下面的欄里,再在地址上單擊右鍵,彈出菜單中選"Find out what writes to this address"(誰在改定這個地址),調(diào)出監(jiān)視窗口,再回到游戲,掉點血,就可以看到監(jiān)視窗口里己經(jīng)有改寫該地址的命令了~

選中該命令,點"Mor information",得到如下圖

mov [esi+00000254],ecx 紅色加亮的這句,(+00000254也就是血量的偏移量了)
可以看到,是把ECX的值寫入ESI+00000254這個內(nèi)存地址中,所以,我們記下下面的ESI地址:ESI=05C0B548,再回到CE主界面,搜"05C0B548"這個數(shù)(選中HEX,用十六進(jìn)制四字節(jié)方式搜)

得到26個地址都含有這個數(shù),好的,把最前面的三個數(shù)保存到下欄里,然后,小退一下(回到人物選擇界面,再進(jìn)入游戲),就可以看到,三個地址的數(shù)值都有變化了.好,再重新找血量地址,然后再"Find out what writes to this address"(誰在改定這個地址)這個地址,得到ESI的值,記下來,對比剛保存 下來的三個地址內(nèi)的數(shù),呵呵,發(fā)現(xiàn)
010AEAE4里的值剛好等于ESI,這就可以肯定,010AEAE4一定二級基址了,好,我們監(jiān)視010AEAE4,"Find out what writes to this address".好,再次小退一下,再進(jìn)入游戲,這時監(jiān)視窗口有東東了,如下圖

得到:mov [esi+24],0000000
記下ESI的值,010AEAC0,再回到CE主界面,用十六進(jìn)制的方法找010AEACO
得到N個數(shù),反復(fù)搜幾次,好,得到下圖

按CE教程說的,一般最是地址最小的就是正確的,呵呵,有點那個啊,~~~~~~~~~~~~
選第一個008BE594,加到下面的欄里,完全退出游戲,再進(jìn)入游戲
重復(fù),最后還是得到008BE594,這樣就可以肯定,008BE594就是一級基址了
得出公式如下
一級基址:008BE594
008BE594地址里面保存的數(shù)值+24的偏移=二級基址
二級基址里面保存的地址數(shù)+254的偏移得到血量的地址
下面開始搜索數(shù)據(jù)!
用CE打開武林外傳。運行CE,按照下圖的次序打開(...\武林外傳\element\elementclient.exe)

2.游戲啟動后,別忘了選擇游戲窗口。

3.這是游戲中人物的數(shù)據(jù)。

4.好,現(xiàn)在我們要在CE中顯示人物的生命值。同樣按照圖中的順序打開“添加地址”對話框,在數(shù)據(jù)框中添加我們已知的內(nèi)存地址。當(dāng)然,我們要用指針的方式,因為存儲這些數(shù)據(jù)的地址是不固定的,我們可以用8C6A54這個固定的基地址以及相關(guān)的偏移地址找到我們需要的數(shù)據(jù)。我們就來看看生命的值,完成圖上的項目點“確定”來看看結(jié)果。

5.怎么樣!是不是角色的生命值呢,使自己失去一些血量看看這個值是不是也在跟著變化。

6.根據(jù)已知的人物地址,我們還可以顯示其它數(shù)據(jù)。

相關(guān)武林外傳地址:
一級基址=8CF51C
人物基址=+24
當(dāng)前血=+254
最大血=+26C
當(dāng)前藍(lán)=+258
最大藍(lán)=+270
以上數(shù)字均為16進(jìn)制
1.建立一個新的標(biāo)準(zhǔn)EXE工程,我們就可以開始這次的學(xué)習(xí)了。
2.我們要建立一個模塊,然后添加以下代碼:
Option Explicit '---------------聲明函數(shù)----------------------- '得到窗體句柄的函數(shù),FindWindow函數(shù)用來返回符合指定的類名( ClassName )和窗口名( WindowTitle )的窗口句柄 Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long '得到窗體控件句柄的函數(shù) Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long '得到進(jìn)程標(biāo)識符的函數(shù) Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long '得到目標(biāo)進(jìn)程句柄的函數(shù) Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long '關(guān)閉句柄的函數(shù) Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long '讀取進(jìn)程內(nèi)存的函數(shù) Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long '參數(shù)決定了對進(jìn)程的存儲權(quán)限,使用完全控制 Public Const PROCESS_ALL_ACCESS = &H1F0FFF
3.接下來Form中,我們要在程序啟動時連接游戲窗口,以下是Form_Load的代碼: Dim hwd As Long ‘ 儲存 FindWindow 函數(shù)返回的句柄 Dim pid As Long Dim hProcess As Long '存放進(jìn)程句柄
Private Sub Form_Load() hwd = FindWindow("QElementClient Window", "Element Client") If hwd = 0 Then MsgBox "未啟動游戲", vbOKOnly, "提示" Unload Form1 End If GetWindowThreadProcessId hwd, pid '獲取進(jìn)程標(biāo)識符 '將進(jìn)程標(biāo)識符做為參數(shù),返回目標(biāo)進(jìn)程PID的句柄,得到此句柄后 '即可對目標(biāo)進(jìn)行讀寫操,PROCESS_ALL_ACCESS表示完全控制,權(quán)限最大 hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) If hProcess = 0 Then MsgBox "不能打開進(jìn)程", vbOKOnly, "提示" Unload Form1 End If CloseHandle hProcess
4.我們在Form中添加一個Label控件和一個Timer控件,設(shè)置Timer的Interval屬性為100,Timer1_Timer的代碼如下: Dim h As Long hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
If hProcess Then ReadProcessMemory hProcess, ByVal &H8C6A54, h, 4, 0& ‘這三條代碼讀取獲得生命值 ReadProcessMemory hProcess, ByVal h + &H24, h, 4, 0& ReadProcessMemory hProcess, ByVal h + &H254, h, 4, 0&
CloseHandle hProcess End If
Label1.Caption = h '輸出生命值
|
下面我們來給外掛增加自動保護(hù)功能.
1.首先我們要繪制一個界面,最先添加一個Frame控件、最少兩個Label控件用于輸出生命和真氣值、兩個Text控件用于輸入數(shù)據(jù)還有兩個Timer控件,分別改名為TimerList及TimerAdd,最后添加一個Command控件。可以參考下圖,呵呵~我知道你可以畫的更好看!

2.下一步就是添加代碼了,和上次一樣新建一個模塊,模塊內(nèi)容如下:
Option Explicit '---------------聲明函數(shù)----------------------- '得到窗體句柄的函數(shù),FindWindow函數(shù)用來返回符合指定的類名( ClassName )和窗口名( WindowTitle )的窗口句柄 Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long '得到窗體控件句柄的函數(shù) Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long '得到進(jìn)程標(biāo)識符的函數(shù) Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long '得到目標(biāo)進(jìn)程句柄的函數(shù) Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long '關(guān)閉句柄的函數(shù) Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long '讀取進(jìn)程內(nèi)存的函數(shù) Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long '參數(shù)決定了對進(jìn)程的存儲權(quán)限,使用完全控制 Public Const PROCESS_ALL_ACCESS = &H1F0FFF '發(fā)送信息的函數(shù) Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long '延遲函數(shù) Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) [/code]
發(fā)送消息函數(shù)和延遲函數(shù)是以前內(nèi)容沒有用過的,這回我們將涉及發(fā)送模擬鍵盤消息給窗口,所以加入這兩個函數(shù)。 3.做好模塊,下一步該寫Form了。同樣還是聲明一些變量及Form_Load,代碼如下:
[code] Dim hwd As Long Dim pid As Long Dim hProcess As Long '存放進(jìn)程句柄 Dim base As Long '存放人物基地址 Dim hp As Long '存儲生命值 Dim hpmax As Long '存儲生命最大值 Dim mp As Long '存儲真氣值 Dim mpmax As Long '存儲真氣最大值
Private Sub Form_Load() hwd = FindWindow("QElementClient Window", "Element Client") If hwd = 0 Then MsgBox "未啟動游戲", vbOKOnly, "提示" Unload Form1 End If GetWindowThreadProcessId hwd, pid '獲取進(jìn)程標(biāo)識符 '將進(jìn)程標(biāo)識符做為參數(shù),返回目標(biāo)進(jìn)程PID的句柄,得到此句柄后 '即可對目標(biāo)進(jìn)行讀寫操,PROCESS_ALL_ACCESS表示完全控制,權(quán)限最大 hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) If hProcess = 0 Then MsgBox "不能打開進(jìn)程", vbOKOnly, "提示" Unload Form1 End If CloseHandle hProcess End Sub [/code]
4.下一步,我們通過TimerList顯示人物信息,設(shè)置TimerList的Interval屬性值為1000,其代碼如下: [code] Private Sub TimerList_Timer() '顯示人物信息時鐘 Dim name(31) As Byte '存儲人物名稱 Dim name_temp As Long
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, pid) If hProcess Then ReadProcessMemory hProcess, ByVal &H8C9E54, base, 4, 0& ReadProcessMemory hProcess, ByVal base + &H24, base, 4, 0& '得到為人物基地址,方便以后使用 ReadProcessMemory hProcess, ByVal base + &H254, hp, 4, 0& '得到生命值 ReadProcessMemory hProcess, ByVal base + &H26C, hpmax, 4, 0& '得到生命最大值 ReadProcessMemory hProcess, ByVal base + &H258, mp, 4, 0& '得到真氣值 ReadProcessMemory hProcess, ByVal base + &H270, mpmax, 4, 0& '得到真氣最大值 ReadProcessMemory hProcess, ByVal base + &H390, name_temp, 4, 0& ReadProcessMemory hProcess, ByVal name_temp, name(0), 32, 0& '得到人物名稱 CloseHandle hProcess End If Frame1.Caption = name '顯示人物名稱 Label2.Caption = "生命值:" & hp & "/" & hpmax '顯示生命值 Label3.Caption = "真氣值:" & mp & "/" & mpmax '顯示真氣值 End Sub [/code]
現(xiàn)在可以運行一下看看數(shù)值是否能正常顯示! 5.在來做第二個TimerAdd,設(shè)置Enabled = False,Interval屬性值為100,期代碼如下: [code] Private Sub TimerAdd_Timer() '加血判斷時鐘 If Val(Text1.Text) > hp Then '比較當(dāng)前血量是否比預(yù)定值低,是則按下F1健 SendMessage hwd, &H100, &H70, 0& '按住F1鍵,&H100代表按下,&H70代表F1 SendMessage hwd, &H101, &H70, 0& '松開F1鍵,&H101代表松開,&H70代表F1 Sleep Val(Text2.Text) '延遲text2中的數(shù)值,用val()取數(shù)值 End If End Sub [/code]
6.最后就剩下Command了,設(shè)置其Caption屬性為“開始”,期代碼如下: [code] Private Sub Command1_Click() If Command1.Caption = "開始" Then '按下標(biāo)簽為“開始”的按鈕,激活TimerAdd并改變標(biāo)簽為“停止” TimerAdd.Enabled = True Command1.Caption = "停止" ElseIf Command1.Caption = "停止" Then '剛好和上面相反 TimerAdd.Enabled = False Command1.Caption = "開始" End If End Sub
|
7.小功告成!運行測試看看,能否實現(xiàn)加血功能!那加藍(lán)、補(bǔ)助技能呢?

8.本次內(nèi)容重點:SendMessage /通過此函數(shù)實現(xiàn)模擬鍵盤操作功能Sleep /必不可少的延遲函數(shù)
9.當(dāng)然,你看完整個文章或者在測試的時候會發(fā)現(xiàn),這個程序還有很多的漏洞或者說還可以做的更完善,沒錯,這就是接下來你要做的,還是那句話:“因為我知道你可以做的到”
ps:自己設(shè)置按鍵
SendMessage hwd, &H100, Key(Combo1.ListIndex), 0&
SendMessage hwd, &H101, Key(Combo1.ListIndex), 0&
Private Function Key(Anjian As Long) As Long '用于轉(zhuǎn)換按鍵的函數(shù)
Select Case Anjian
Case 0
Key = &H70 ‘F1
Case 1
Key = &H71 'F2
Case 2
Key = &H72 'F3
Case 3
Key = &H73 'F4
Case 4
Key = &H74
Case 5
Key = &H75
Case 6
Key = &H76
Case 7
Key = &H77
Case 8
Key = &H31 '1
Case 9
Key = &H32 '2
Case 10
Key = &H33 '3
Case 11
Key = &H34
Case 12
Key = &H35
Case 13
Key = &H36
Case 14
Key = &H37
Case 15
Key = &H38
Case 16
Key = &H39 '9
Case 17
Key = &H30 '0
End Select
End Function
我們已經(jīng)學(xué)會如何監(jiān)視血量達(dá)到加血的功能,其實自動攻擊和加血的核心原理是一樣的,同樣是發(fā)送消息給游戲窗口,只不過要先通過按Tab鍵選去身邊的怪然后按攻擊快捷鍵打怪。
提示:
SYSKEYDOWN = &H104
KeyDOWN = &H100
KeyUP = &H101
CHAR = &H102
SHIFT = &H10 'Shift鍵的常數(shù)
CONTROL = &H11 'Ctrl鍵的常數(shù)
MENU = &H12 'Windows鍵的常數(shù)
TAB = &H9 'Tab鍵的常數(shù)
[[eax]+ &H798] '&H798 或地址 &H0354AF44 當(dāng)前目標(biāo)怪物ID ,為負(fù)就是怪,為正就是NPC或玩家,為0則怪物死亡或沒有選擇
[[eax] + &H408] '人物攻擊狀態(tài),攻擊時為1,無動作為0
[[eax] + &H25C] '&H25C 當(dāng)前經(jīng)驗值,十進(jìn)制
[[[[eax]+&h8]+&h24]+&h14] '地上所有物品數(shù)量,包含別人打掉地上的物品
2.我們要做一個小程序,用于顯示地面上的所有物品。添加一個List控件、一個Time控件,如下圖所示。

3.下面添加代碼! 3.1.模塊: Option Explicit '---------------聲明函數(shù)----------------------- '得到窗體句柄的函數(shù),FindWindow函數(shù)用來返回符合指定的類名( ClassName )和窗口名( WindowTitle )的窗口句柄 Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long '得到窗體控件句柄的函數(shù) Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long '得到進(jìn)程標(biāo)識符的函數(shù) Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long '得到目標(biāo)進(jìn)程句柄的函數(shù) Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long '關(guān)閉句柄的函數(shù) Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long '讀取進(jìn)程內(nèi)存的函數(shù) Public Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long '參數(shù)決定了對進(jìn)程的存儲權(quán)限,使用完全控制 Public Const PROCESS_ALL_ACCESS = &H1F0FFF
3.2.Form_Load: Option Explicit Dim hwd As Long Dim pid As Long Dim hProcess As Long '存放進(jìn)程句柄
Private Sub Form_Load() hwd = FindWindow("QElementClient Window", "Element Client") If hwd = 0 Then MsgBox "未啟動游戲", vbOKOnly, "提示" Unload Form1 End If GetWindowThreadProcessId hwd, pid '獲取進(jìn)程標(biāo)識符 '將進(jìn)程標(biāo)識符做為參數(shù),返回目標(biāo)進(jìn)程PID的句柄,得到此句柄后 '即可對目標(biāo)進(jìn)行讀寫操,PROCESS_ALL_ACCESS表示完全控制,權(quán)限最大 hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid) If hProcess = 0 Then MsgBox "不能打開進(jìn)程", vbOKOnly, "提示" Unload Form1 End If End Sub
3.3.Timer_Timer: 'Timer.interval=1000,利用1秒的延遲顯示列表
Private Sub Timer1_Timer() '顯示地面物品名稱列表 Dim base As Long '存儲地址 Dim mecxi As Long '存儲地址 Dim pn As Integer '循環(huán)變量 Dim WpName(65) As Byte '存儲物品名稱
List1.Clear '用于刷新物品列表 If hProcess Then ReadProcessMemory hProcess, ByVal &H8C9E54, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H8, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 '得到物品數(shù)量 If mecxi <> 0 Then For pn = 0 To 768 '循環(huán)用來判斷那個值內(nèi)存在物品 ReadProcessMemory hProcess, ByVal mecxi + &H18, base, 4, 0 ReadProcessMemory hProcess, ByVal base + pn * 4, base, 4, 0 '從列表中選出地面上物品的地址 If base > 0 Then '判斷是否存在物品 ReadProcessMemory hProcess, ByVal base + 4, base, 4, 0 ReadProcessMemory hProcess, ByVal base + &H164, base, 4, 0 ReadProcessMemory hProcess, ByVal base, WpName(0), 64, 0 '得到物品名稱 List1.AddItem WpName '添加到List控件 End If Next pn End If End If End Sub
3.4.Form_Unload: Private Sub Form_Unload(Cancel As Integer) CloseHandle hProcess End Sub
|

OK了~收工!
接下來我們就能讓可惡的配方從此在背包中消失
2.首先看看圖片,我要用到那些控件

主要控件:
List1 /用于顯示地面物品
List2 /用于顯示需要過濾的物品名稱
Timer1 /用于刷新地面物品
Timer2 /用于過濾地面物品
Combo1 /用于添加或保存過濾物品名稱
Command1 /添加按鈕
Command2 /刪除按鈕
模塊添加: '存儲進(jìn)程內(nèi)存的函數(shù) Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
3.我們來看看過濾物品的核心代碼,以下為Timer2_Timer代碼: Private Sub Timer2_Timer() Dim base As Long '存儲地址 Dim mecxi As Long '存儲地址 Dim WpNameT As Long '存儲地址 Dim pn As Integer '循環(huán)變量 Dim WpName(65) As Byte '存儲物品名稱 Dim x As Integer
If hProcess Then ReadProcessMemory hProcess, ByVal &H8C9E54, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H8, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 '得到物品數(shù)量 If mecxi <> 0 Then For pn = 0 To 768 '循環(huán)用來判斷那個值內(nèi)存在物品 ReadProcessMemory hProcess, ByVal mecxi + &H18, base, 4, 0 ReadProcessMemory hProcess, ByVal base + pn * 4, base, 4, 0 '從列表中選出地面上物品的地址 If base > 0 Then '判斷是否存在物品 ReadProcessMemory hProcess, ByVal base + 4, base, 4, 0 ReadProcessMemory hProcess, ByVal base + &H164, WpNameT, 4, 0 ReadProcessMemory hProcess, ByVal WpNameT, WpName(0), 64, 0 '得到物品名稱 For x = 0 To List2.ListCount - 1 '用循環(huán)查找是否是過濾表內(nèi)要過濾的物品 If InStr(WpName, List2.List(x)) > 0 Then '用InSet()進(jìn)行對比,存在過濾表內(nèi)容則過濾 WriteProcessMemory hProcess, ByVal base + &H110, 0, 4, 0 '變ID為0,有撿物品動作但背包內(nèi)無此物品 Label1.Caption = "已過濾:" & CStr(WpName) '過濾提示,觀察用 End If Next x End If Next pn End If End If End Sub
3.1.地面上的物品得用一個0 to 768循環(huán)來判斷哪個值內(nèi)存在物品,比如說地面上有四個物品,則0 to 768里面就會有4個值是存在著物品,也就說游戲最多能顯示769件地面物品。
3.2.首先判斷地面上是否存在物品,如果存在則循環(huán)769次查找物品,當(dāng)找到0 to 768中的一個物品時,程序得到物品的名稱,接下來用一個循環(huán)來對比物品名稱與過濾表做對比,如果為要過濾的物品則改變當(dāng)前物品在內(nèi)存的ID,游戲程序再執(zhí)行撿取動作就會實現(xiàn)過濾功能,物品檢起來了,但是并不在背包內(nèi),也沒有撿到物品的提示。
4.最后就是過濾表的制作了,這個很簡單,只要有添加項目和刪除項目的功能就可以。這里我用到Combo控件作為輸入框,因為可以記錄一些可能會用到的物品名稱。
Private Sub Command1_Click() '添加物品名稱 If Combo1.Text <> "" Then List2.AddItem Combo1.Text End Sub
Private Sub Command2_Click() '刪除物品名稱 If List2.ListIndex <> -1 Then List2.RemoveItem (List2.ListIndex) '當(dāng)選中某項則刪除某項 End Sub
|
5.最后的成品!標(biāo)簽顯示了已經(jīng)過濾的物品。最后,默哀5分鐘以悼念做測試時銷毀的5個大補(bǔ)丸

下面我們來實現(xiàn)刷新背包

1.在模塊添加以下代碼: '讀配置文件 Public Declare Function GetPrivateProfileString& Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String)
2.以下是用于刷新背包物品名稱Timer3的代碼: Private Sub Timer3_Timer() '用于刷新背包物品名稱 Dim base As Long '存儲地址 Dim mecxi As Long '存儲地址 Dim pn As Integer '循環(huán)變量 Dim pd As Long '判斷變量 'Dim BaoName(35) As Byte '存儲物品名稱 Dim BaoN As Long '背包格數(shù)
List3.Clear '清除,用于刷新物品列表 If hProcess Then ReadProcessMemory hProcess, ByVal Buffer, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H24, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H854, mecxi, 4, 0 ReadProcessMemory hProcess, ByVal mecxi + &H10, BaoN, 4, 0 '得到背包格數(shù) ReadProcessMemory hProcess, ByVal mecxi + &HC, mecxi, 4, 0 For pn = 0 To BaoN - 1 '循環(huán)查詢背包內(nèi)所有格子內(nèi)的物品 ReadProcessMemory hProcess, ByVal mecxi + pn * 4, base, 4, 0 ReadProcessMemory hProcess, ByVal base + &H14, pd, 4, 0 '得到格子內(nèi)物品數(shù)量,因為沒有確認(rèn)格內(nèi)存在物品的地址,所以暫用這個判斷是否存在物品 If pd > 0 Then '大于0表示存在物品 ReadProcessMemory hProcess, ByVal base + &H8, base, 4, 0 '得到物品ID ItemList (CStr(base)) '交給轉(zhuǎn)換名稱函數(shù)處理 'ReadProcessMemory hProcess, ByVal base + &H44, base, 4, 0 'ReadProcessMemory hProcess, ByVal base + &HE, BaoName(0), 34, 0 'If InStr(BaoName, "\r") - 1 > 0 Then List3.AddItem Left(BaoName, InStr(BaoName, "\r") - 1) End If base = 0 pd = 0 Next pn Frame3.Caption = "背包物品 * " & List3.ListCount '根據(jù)list3的項目數(shù)得到物品數(shù)量 End If End Sub
3.自建一個函數(shù)用于把得到ID轉(zhuǎn)換成物品名稱,以下是代碼: Private Sub ItemList(ItemName As String) '用于轉(zhuǎn)換物品名稱函數(shù) Dim name As String '存儲物品名稱 Dim dz As String '存放文件地址 Dim a As Integer '用于判斷 name = Space$(35) '定義讀取值的字串寬度 a = GetPrivateProfileString("item", ItemName, "", name, 35, App.Path & "\config.ini") '在文件中查找匹配物品名稱 name = Trim$(name) '去掉多余字符 If a = 0 Then '輸出到List的判斷 List3.AddItem ItemName & "****" '當(dāng)無匹配項目則輸出物品ID和無資料 Else List3.AddItem name End If End Sub
|
4.我用config.ini保存物品名稱對應(yīng)表
[item]
28=精煉石
34=菜鳥布衣(男)
35=絲衣(男)
36=緞衣(男)
38=掩心甲(男)
39=鱗甲(男)
40=金縷甲(男)
41=豹皮戰(zhàn)甲(男)
42=獅蠻甲(男)
............
5.程序運行,物品名稱正確的顯示出來,不過隨著游戲的更新你也許需要不斷的更新你的文config.ini。
注:
背包物品地址:
[[[[&H8C9E54]+&h24]+&h854]+&h10] 是角色背包最大容量
[[[[&H8C9E54]+&h24]+&h854]+&hC] 是角色背包首地址
[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序號] 是格子物品首地址(格子數(shù)從0開始)
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序號]+&h14] 是此格物品的數(shù)量
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序號]+&h18] 是此格物品的堆疊上限
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序號]+&h4] 背包內(nèi)物品類型
(裝備&戒指&項鏈為0,生產(chǎn)材料&聲望材料為1,藥品為2,精煉石為7,垃圾石頭為8,配方為17,寵物牌為23)
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序號]+&h8] 物品ID
GetPrivateProfileString:
DWORD GetPrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName);
參數(shù)的意義:
lpAppName : 配置文件的section名
lpKeyName : 配置文件的key名
lpDefault : 如果INI文件中沒有前兩個參數(shù)指定的字段名或鍵名,則將此值賦給變量.
lpReturnedString : 接收INI文件中的值的CString對象,即目的緩存器.
nSize : 目的緩存器的大小.
lpFileName : 是完整的INI文件名.
例:
config.ini的內(nèi)容:
[item]
28=精煉石
34=菜鳥布衣(男)
35=絲衣(男)
36=緞衣(男)
38=掩心甲(男)
39=鱗甲(男)
40=金縷甲(男)
41=豹皮戰(zhàn)甲(男)
42=獅蠻甲(男)
GetPrivateProfileString& "item", 36, "", name, 35, App.Path & "\config.ini")
在[item]下,找36這項,將值存入變量name,寬度為35,文件地址為App.Path & "\config.ini"
最后...
內(nèi)容:
1.我們將使用EnumWindows枚舉Windows所有窗口。首先來看看MSDN說明:
函數(shù)功能:該函數(shù)枚舉所有屏幕上的頂層窗口,辦法是先將句柄傳給每一個窗口,然后再傳送給應(yīng)用程序定義的回調(diào)函數(shù)。EnumThreadWindows函數(shù)繼續(xù)到所有頂層窗口枚舉完為止或回調(diào)函數(shù)返回FALSE為止函數(shù)原型:BOOL EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam);
參數(shù):
lpEnumFunc:指向一個應(yīng)用程序定義的回調(diào)數(shù)指針,請參看EnumWindowsProc。
lPararm:指定一個傳遞給回調(diào)函數(shù)的應(yīng)用程序定義值。
返回值:如果函數(shù)成功,返回值為非零;如果函數(shù)失敗,返回值為零。若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。
2.模塊部分: Option Explicit '得到窗口的標(biāo)題條文本 Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long '枚舉所有屏幕上的頂層窗口 Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean Dim S As String S = String(80, 0) Call GetWindowText(hwnd, S, 80) S = Left(S, InStr(S, Chr(0)) - 1) If Len(S) > 0 Then Form1.List1.AddItem S EnumWindowsProc = True End Function
3.Form部分,我們需要一個List控件用于顯示:
Private Sub Form_Load() EnumWindows AddressOf EnumWindowsProc, 0& End Sub
4.運行程序,顯示了所有窗口的文本。
5.好了,我們完成了核心程序。 現(xiàn)在我們要接著往下做三個工作:(1)只顯示我們想要的窗口、(2)顯示人物名稱、(3)選擇目標(biāo)人物連接游戲窗口。
5.1.篩選枚舉出來的窗口。這個很簡單,只要在插入List之前的If中再加入一個判斷窗口文本內(nèi)容就可以實現(xiàn)。 If Len(S) > 0 and UCase(S) = "ELEMENT CLIENT" Then Form1.List1.AddItem S
5.2.顯示人物名稱,我想這個大家都會吧! If Len(S) > 0 And UCase(S) = "ELEMENT CLIENT" Then Dim ProcID As Long, hpID As Long, BuffEnum(35) As Byte, ECXI As Long, eax As Long, Str As String
GetWindowThreadProcessId hwnd, hpID ProcID = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, hpID)
ReadProcessMemory ProcID, ByVal &H8C9E54, ECXI, 4, 0 '這個是存放基址的地址 ReadProcessMemory ProcID, ByVal ECXI + &H24, eax, 4, 0 ReadProcessMemory ProcID, ByVal eax + &H390, ECXI, 4, 0 ReadProcessMemory ProcID, ByVal ECXI, BuffEnum(0), 36, 0 Str = Left$(BuffEnum, 36) Form1.List1.AddItem hpID & " " & Str ‘這里我耍了一個小聰明,可以省好多事。 End If
5.3.選擇目標(biāo)窗口連接游戲。 當(dāng)然要在List1_Click中插入代碼了。我使用兩個Form,先顯示Form1選擇游戲窗口,傳遞游戲窗口的PID給Form2,然后再Form2里OpenProcess即可。所以我的List1_Click代碼: Form2.Show Me.Hide
|
6.寫到這里,后面的大家就應(yīng)該知道怎么吧。這次就不公布源碼了,因為特征碼的關(guān)系遭封殺的幾率太大,另外這樣也好給大家留出一些設(shè)計的空間。
注意:
如果你在原有程序的基礎(chǔ)上,添加新的Form2用于選擇游戲窗口,請設(shè)置從Form2啟動。
程序關(guān)閉時別忘卸載隱藏的Form。
以后靠大家了~哎~!累哦!
這個只是個例子~其它的游戲都可以這么做.首先最好就用winIO模擬.懶得考慮這么復(fù)雜.這些代碼轉(zhuǎn)換成DELPHI也比較容易.嘎嘎~
如果你還不會winIO VB版本.請看此貼.
讓VB菜鳥最快寫出自己的外掛.通殺所有游戲.呵呵.
繼續(xù)模擬按鍵WinIO (DELPHI版)
沒有VB知識請看
VB的一些入門知識.
posted on 2007-07-20 15:54
聶文龍 閱讀(4239)
評論(0) 編輯 收藏 引用