接下来我们就能让可恶的配方从此在背包中消失
2.首先看看图片,我要用到那些控件
主要控件:
List1 /用于显示地面物品
List2 /用于显示需要过滤的物品名称
Timer1 /用于刷新地面物品
Timer2 /用于过滤地面物品
Combo1 /用于添加或保存过滤物品名称
Command1 /添加按钮
Command2 /删除按钮
模块添加:'存储进程内存的函数Public Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long3.我们来看看过滤物品的核心代码,以下为Timer2_Timer代码:Private Sub Timer2_Timer()Dim base As Long '存储地址Dim mecxi As Long '存储地址Dim WpNameT As Long '存储地址Dim pn As Integer '循环变量Dim WpName(65) As Byte '存储物品名称Dim x As IntegerIf 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 '得到物品数量 If mecxi <> 0 Then For pn = 0 To 768 '循环用来判断那个值内存在物品 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 '用循环查找是否是过滤表内要过滤的物品 If InStr(WpName, List2.List(x)) > 0 Then '用InSet()进行对比,存在过滤表内容则过滤 WriteProcessMemory hProcess, ByVal base + &H110, 0, 4, 0 '变ID为0,有捡物品动作但背包内无此物品 Label1.Caption = "已过滤:" & CStr(WpName) '过滤提示,观察用 End If Next x End If Next pn End IfEnd IfEnd Sub3.1.地面上的物品得用一个0 to 768循环来判断哪个值内存在物品,比如说地面上有四个物品,则0 to 768里面就会有4个值是存在着物品,也就说游戏最多能显示769件地面物品。3.2.首先判断地面上是否存在物品,如果存在则循环769次查找物品,当找到0 to 768中的一个物品时,程序得到物品的名称,接下来用一个循环来对比物品名称与过滤表做对比,如果为要过滤的物品则改变当前物品在内存的ID,游戏程序再执行捡取动作就会实现过滤功能,物品检起来了,但是并不在背包内,也没有捡到物品的提示。4.最后就是过滤表的制作了,这个很简单,只要有添加项目和删除项目的功能就可以。这里我用到Combo控件作为输入框,因为可以记录一些可能会用到的物品名称。Private Sub Command1_Click() '添加物品名称If Combo1.Text <> "" Then List2.AddItem Combo1.TextEnd SubPrivate Sub Command2_Click() '删除物品名称If List2.ListIndex <> -1 Then List2.RemoveItem (List2.ListIndex) '当选中某项则删除某项End Sub
5.最后的成品!标签显示了已经过滤的物品。最后,默哀5分钟以悼念做测试时销毁的5个大补丸
下面我们来实现刷新背包
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 '循环变量Dim pd As Long '判断变量'Dim BaoName(35) As Byte '存储物品名称Dim BaoN As Long '背包格数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 '得到背包格数 ReadProcessMemory hProcess, ByVal mecxi + &HC, mecxi, 4, 0 For pn = 0 To BaoN - 1 '循环查询背包内所有格子内的物品 ReadProcessMemory hProcess, ByVal mecxi + pn * 4, base, 4, 0 ReadProcessMemory hProcess, ByVal base + &H14, pd, 4, 0 '得到格子内物品数量,因为没有确认格内存在物品的地址,所以暂用这个判断是否存在物品 If pd > 0 Then '大于0表示存在物品 ReadProcessMemory hProcess, ByVal base + &H8, base, 4, 0 '得到物品ID ItemList (CStr(base)) '交给转换名称函数处理 '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 '根据list3的项目数得到物品数量End IfEnd Sub3.自建一个函数用于把得到ID转换成物品名称,以下是代码:Private Sub ItemList(ItemName As String) '用于转换物品名称函数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 & "****" '当无匹配项目则输出物品ID和无资料Else List3.AddItem nameEnd IfEnd Sub
4.我用config.ini保存物品名称对应表
[item]
28=精炼石
34=菜鸟布衣(男)
35=丝衣(男)
36=缎衣(男)
38=掩心甲(男)
39=鳞甲(男)
40=金缕甲(男)
41=豹皮战甲(男)
42=狮蛮甲(男)
............
5.程序运行,物品名称正确的显示出来,不过随着游戏的更新你也许需要不断的更新你的文config.ini。
注:
背包物品地址:
[[[[&H8C9E54]+&h24]+&h854]+&h10] 是角色背包最大容量
[[[[&H8C9E54]+&h24]+&h854]+&hC] 是角色背包首地址
[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号] 是格子物品首地址(格子数从0开始)
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h14] 是此格物品的数量
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h18] 是此格物品的堆叠上限
[[[[[[&H8C9E54]+&h24]+&h854]+&hC]+4*格子序号]+&h4] 背包内物品类型
(装备&戒指&项链为0,生产材料&声望材料为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);
参数的意义:
lpAppName : 配置文件的section名
lpKeyName : 配置文件的key名
lpDefault : 如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量.
lpReturnedString : 接收INI文件中的值的CString对象,即目的缓存器.
nSize : 目的缓存器的大小.
lpFileName : 是完整的INI文件名.
例:
config.ini的内容:
[item]
28=精炼石
34=菜鸟布衣(男)
35=丝衣(男)
36=缎衣(男)
38=掩心甲(男)
39=鳞甲(男)
40=金缕甲(男)
41=豹皮战甲(男)
42=狮蛮甲(男)
GetPrivateProfileString& "item", 36, "", name, 35, App.Path & "/config.ini")
在[item]下,找36这项,将值存入变量name,宽度为35,文件地址为App.Path & "/config.ini"
最后...
内容:
1.我们将使用EnumWindows枚举Windows所有窗口。首先来看看MSDN说明:
函数功能:该函数枚举所有屏幕上的顶层窗口,办法是先将句柄传给每一个窗口,然后再传送给应用程序定义的回调函数。EnumThreadWindows函数继续到所有顶层窗口枚举完为止或回调函数返回FALSE为止函数原型:BOOL EnumWindows(WNDENUMPROC lpEnumFunc,LPARAM lParam);
参数:
lpEnumFunc:指向一个应用程序定义的回调数指针,请参看EnumWindowsProc。
lPararm:指定一个传递给回调函数的应用程序定义值。
返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。
2.模块部分:Option Explicit'得到窗口的标题条文本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 BooleanDim S As StringS = String(80, 0)Call GetWindowText(hwnd, S, 80)S = Left(S, InStr(S, Chr(0)) - 1)If Len(S) > 0 Then Form1.List1.AddItem SEnumWindowsProc = TrueEnd Function3.Form部分,我们需要一个List控件用于显示:Private Sub Form_Load()EnumWindows AddressOf EnumWindowsProc, 0&End Sub4.运行程序,显示了所有窗口的文本。5.好了,我们完成了核心程序。现在我们要接着往下做三个工作:(1)只显示我们想要的窗口、(2)显示人物名称、(3)选择目标人物连接游戏窗口。5.1.筛选枚举出来的窗口。这个很简单,只要在插入List之前的If中再加入一个判断窗口文本内容就可以实现。If Len(S) > 0 and UCase(S) = "ELEMENT CLIENT" Then Form1.List1.AddItem S5.2.显示人物名称,我想这个大家都会吧!If Len(S) > 0 And UCase(S) = "ELEMENT CLIENT" ThenDim ProcID As Long, hpID As Long, BuffEnum(35) As Byte, ECXI As Long, eax As Long, Str As StringGetWindowThreadProcessId hwnd, hpIDProcID = 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 If5.3.选择目标窗口连接游戏。当然要在List1_Click中插入代码了。我使用两个Form,先显示Form1选择游戏窗口,传递游戏窗口的PID给Form2,然后再Form2里OpenProcess即可。所以我的List1_Click代码:Form2.ShowMe.Hide
6.写到这里,后面的大家就应该知道怎么吧。这次就不公布源码了,因为特征码的关系遭封杀的几率太大,另外这样也好给大家留出一些设计的空间。
注意:
如果你在原有程序的基础上,添加新的Form2用于选择游戏窗口,请设置从Form2启动。
程序关闭时别忘卸载隐藏的Form。
以后靠大家了~哎~!累哦!
如果觉得《零基础制作【武林外传】辅助工具(三)》对你有帮助,请点赞、收藏,并留下你的观点哦!