第二节开课啦。。。
在上一节中,我们知道了当打开英雄状态窗口时,8261D8中存放的数值再+23(十六进制,以下一样),就是英雄名字的首字符位置,什么,你不知道是怎么来的,我汗,朋友,作修改器不是请客吃饭,在这种关键时刻,你必须得一行一行代码的看,别的不说,你必须要知道关键位置是从哪里读取的。
大家可以在57A25F的位置按下F2下断,然后回来游戏,打开英雄状态窗口,断下后,按F7跟着程序走,你就会明白啦。一般来说,在CALL之前PUSH入栈的数据都是关键数据。如果您还是不懂,………………建议您去看一下汇编基础再回来。
下面,我们就要用修改器来实现这一功能。因为在游戏中,英雄姓名首字符位置与英雄其它的属性相隔的位置是固定的。比如四围啦。宝物啦,军队,魔法什么的。位置相隔都是一定的。
我们来打个比方吧。比如英雄的攻击力与姓名首字符的距离是1F。我们打开VB6,新建一个标准EXE,在窗体上新建一个CommandButton,其Caption为“读取”新建一个TextBox,其Text为空。如图。
然后开始写代码啦。。在窗体的通用部分声明以下API
Option Explicit
'1.查找窗口
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'2.取得进程ID
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
'3.打开进程
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
'4.把数值写入内存
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
'5.从内存中读取数值
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
'6.关闭打开的线程句柄
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'7.一个操作内存的权力常数
Private Const PROCESS_ALL_ACCESS = &H1F0FFF
'以上7个项目可以从API浏览器中复制,,但可能会有一点不同,,建议复制上面的代码
'8.一个保存游戏进程ID的变量
Public hProcess As Long
'9我们刚才找到的基础地址
Const BaseAddr = &H8261D8
然后打开SPY++,查看游戏窗口的名称:魔法门之英雄无敌III 3.1 Jul 18 2000 13:48:09
再接着上边写以下函数:
Function FindGame() As Boolean
Dim PID As Long, Gamehwnd As Long
FindGame = False
Gamehwnd = FindWindow(VbNullString, "魔法门之英雄无敌III 3.1 Jul 18 2000 13:48:09") '查找游戏的句柄
If (Gamehwnd = 0) Then Exit Function '如果找不到(例如游戏未运行)就退出函数
GetWindowThreadProcessId Gamehwnd, PID '取得进程ID
hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, PID) '以全部权力打开进程
If (hProcess = 0) Then Exit Function '打开进程失败
FindGame = True '成功!!
End Function
然后在FORM1的LOAD事件中写如下代码:
If Not FindGame Then
MsgBox "请先运行游戏,并双击英雄,打开英雄信息窗口!", vbCritical
Command1.Enable = False
Text1.Enable=False
Exit sub
End If
以上意思就是说如果找不到游戏进程,就给出提示,并且使命令按键和文本编辑框不可用。
然后双击“读取”在CLICK事件中写以下代码:
Dim MyAddr&
ReadProcessMemory hProcess, BaseAddr, MyAddr, 4, 0
MyAddr = MyAddr + &H23
这样,我们就完成了程序中读取英雄姓名首字节的工作。在MYADDR中存放的就是英雄名字首字节。
接着,我们就是要读取英雄的攻击力,并在TEXTBOX中显示出来。
Dim I as Byte ‘因为攻击力最大是100,所以我们就用BYTE类型来表示。
ReadProcessMemory hProcess, MyAddr + &H1F, I, 1, 0 '读取攻击力
Text1.Text = i
这样我们就完成了攻击力的读取并显示在窗体上。
如果我们要保存呢,我们可以再新建一个CommandButton,并命名为“保存”
在其CLICK事件中这么写
Dim I as Byte
I = Text1.Text
WriteProcessMemory hProcess, MyAddr + &H1F, I, 1, 0
这样,就完成了写入,当然,这只是最简单的一个示例,如果大家自己在写修改器时,一定要把一些情况考虑全面,比如错误处理,限制输入,数据长度等等。这些大家去百度一下就会找到很好的源代码,我就不浪费大家时间了。希望大家看过后,能对您有一些小启发。