VB读写内存

前端之家收集整理的这篇文章主要介绍了VB读写内存前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一些背景知识:

不象C语音,VB不会自动包括普通的API函数的声明,因此我们必须把他们加入我们的项目文件。在几乎所有的修改器中会使用到6个主要的函数,讨论如下:
1. FindWindow(ClassName,WindowTitle) - FindWindow
返回符合指定的类名( ClassName
)
和窗口名( WindowTitle )的窗口句柄。对我们来说,可以让ClassName为空( Null ),只给出游戏的
WindowTitle
函数应该这样声明:

 
 
  1. DeclareFunctionFindWindowLib"user32"Alias
  2. "FindWindowA"(ByVallpClassNameAsString,ByVallpWindowNameAsString) AsLong


2. GetWindowThreadProcessId(WindowHandle,ProcessId) -
在这里我们把FindWindow
函数中得到的句柄作为参数,来获得进程标识符(ProcessId )。声明如下:

 
 
  1. DeclareFunction
  2. GetWindowThreadProcessIdLib"user32"(ByValhwndAsLong,lpdwProcessIdAsLong)AsLong


3. OpenProcess(DesiredAccess,Inherit,ProcessId) -
这个函数将返回一个我们目标进程的句柄,可以用来对目标进行读写操作。DesiredAccess
参数的值决定了句柄对进程的存取权利,对我们来说,要使用PROCESS_ALL_ACCESS (完全存取权限)Inherit应该总是
False
ProcessId是从GetWindowThreadProcessId函数中取得的。Declare Function
OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long,ByVal
bInheritHandle As Long,ByVal dwProcessId As Long) As Long
4. CloseHandle(ProcessHandle) -
每一个打开的句柄必须呼叫这个函数关闭Declare Function
CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
5. WriteProcessMemory(ProcessHandle,Address,value,Sizeofvalue,
BytesWritten) -
把指定的值value写入由Address指定的目标地址。Declare Function
WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long,ByVal
lpBaseAddress As Any,ByVal lpBuffer As Any,ByVal nSize As Long,
lpNumberOfBytesWritten As Long) As Long
6. ReadProcessMemory(ProcessHandle,
BytesWritten) -
Address指定的目标地址的值存入value位置的变量中。这些函数一环扣一环,缺一不可。更详细的内容可以参考VB的帮助文件
一个简单的修改器范例
如何使上面介绍的这些函数一起工作,制作出我们需要的修改器呢?下面是一个为Windows的计算器程序制作修改器的例子。这个修改器将读出计算器窗口中显示的数值,并在点击一个按钮后在计算器窗口中显示我们的名字。
首先我们需要找到计算器显示窗口中显示值的地址。本教程不是关于如何进行内存搜索,因而我将只作简单的说明:
·
在计算器窗口中输入123456
·
使用你喜欢的任何一种内存地址搜索程序寻找字串123456
·
使用另一个值重复上面的过程直到只返回1个地址
那是制作我们的修改器需要的唯一一个地址。在我的计算器程序里这个地址是40B181 hex,4239745 dec。用你找到的地址替代在下面的代码里使用的这个地址。
现在让我们开始设计修改器的界面:
·
VB中新建一个项目,加入一个文本框( TextBox )、一个按钮和一个计时器( timer
)
。文本框用来显示从计算器窗口取得的字串,按钮用来把我们的名字传到计算器窗口
·
把表单( form )标题( Caption )属性设为Calculator Trainer
·
把文本框改名为txtDisplay并清除Text属性
·
把计时器改名为ReadTimer并把间隔( interval )设为500
·
把按钮的标题改为Display Name,按钮的名字改为btnPasteName
在这个修改器中我们将使用所有6函数ReadProcessMemoryWriteProcessMemoryOpenProcessGetWindowThreadProcessIdFindWindow
CloseHandle。在项目中插入一个新的模块,增加下列代码(下面的一些行自动换行了,在你的模块中每一句必须在一行里,或使用延长符_)

 
 
  1. DeclareFunctionFindWindowLib"user32"Alias"FindWindowA"(ByVallpClassNameAsString,ByVallpWindowNameAsString)AsLong
  2. DeclareFunctionGetWindowThreadProcessIdLib"user32"(ByValhwndAs
  3. Long,lpdwProcessIdAsLong)AsLong
  4. DeclareFunctionOpenProcessLib"kernel32"(ByValdwDesiredAccessAs
  5. Long,ByValbInheritHandleAsLong,ByValdwProcessIdAsLong)AsLong
  6. DeclareFunctionWriteProcessMemoryLib"kernel32"(ByValhProcessAs
  7. Long,ByVallpBaseAddressAsAny,ByVallpBufferAsAny,ByValnSizeAs
  8. Long,lpNumberOfBytesWrittenAsLong)AsLong
  9. DeclareFunctionReadProcessMemoryLib"kernel32"(ByValhProcessAsLong,
  10. ByVallpBaseAddressAsAny,ByValnSizeAsLong,
  11. lpNumberOfBytesWrittenAsLong)AsLong
  12. DeclareFunctionCloseHandleLib"kernel32"(ByValhObjectAsLong)AsLong


下面我们要开始写在计时器窗口中显示我们名字的代码了。首先我们使用FindWindow函数取得目标窗口的句柄。把这个返回值保存在一个变量中,并检查它的值是否出错来确保计时器程序正在运行。(FindWindow函数出错时返回0)

 
 
  1. DimhwndAsLong
  2. hwnd=FindWindow(vbNullString,"Calculator")
  3. If(hwnd=0)Then
  4. MsgBox"Windownotfound!"
  5. ExitSub
  6. EndIf


注意在这里我们传递了一个Null值给FindWindow函数,而不是ClassName。因此任何名为Calculator的窗口都符合条件。如果知道计算器程序窗口的ClassName,你可以传给它,但这不是必须的。
现在使用得到的窗口句柄来取得进程标识符( ProcessId )。注意pid是作为参数传递给函数的,而不是被赋以函数返回值。

 
 
  1. DimpidAsLong
  2. GetWindowThreadProcessIdhwnd,pid
  3. '再利用变量pid得到计算器程序的进程句柄。再次检查函数的返回值,如果是非法数据则退出程序。
  4. DimpHandleAsLong
  5. pHandle=OpenProcess(PROCESS_ALL_ACCESS,False,pid)
  6. If(pHandle=0)Then
  7. MsgBox"Couldn’tgetaprocesshandle!"
  8. ExitSub
  9. EndIf


在我们的修改器中WriteProcessMemory函数是最重要的部分,而且非常容易出错。不妨让我们再仔细讨论一下它的参数。
WriteProcessMemory (ByVal hProcess As Long,ByVal lpBaseAddress As Any,
ByVal lpBuffer As Any,lpNumberOfBytesWritten As)
hProcess
是目标进程的句柄,从上面的OpenProcess函数中取得的。
lpBaseAddress
是在计算器程序的虚拟内存中将要被修改的地址,也就是使用内存搜索程序找到的那个地址。(在我的程序里是&H40B181)lpBuffer是将要写如上述地址的数据,可以是一个数值、数组、字符串或其他任何数据类型。
nSize
是希望写入lpBaseAddress的字节数。这个位置应该与你的数据类型相符。如果写入的是一个长整数( long),这里应该是4。如果写入的是一个字符串,那么这里应该是字符串的长度。
lpNumberOfBytesWritten
函数执行返回后,写入目标地址的实际字节数。它能被用来确认函数实际的执行情况。
把我们的数据放到函数中,得到WriteProcessMemory pHandle,&H40B181,"Beans",5,0&。我把0传递到lpNumberOfBytesWritten位置是因为不需要检查两次实际写入的字节数。
最后通过传递进程句柄给CloseHandle()函数关闭OpenProcess打开的句柄。
CloseHandle hProcess
现在将所有的代码输入我们的编辑器中。双击按钮,显示它的代码编辑窗口。代码应该加到名为btnPasteNameClick事件中。(不必输入注释)
Private Sub btnPasteName_Click()
声明一些需要的变量
Dim hwnd As Long ’
储存FindWindow函数返回的句柄
Dim pid As Long ’
储存进程标识符( Process Id )
Dim pHandle As Long ’
储存进程句柄
首先取得目标窗口的句柄
hwnd = FindWindow(vbNullString,"Calculator")
If (hwnd = 0) Then
MsgBox "Window not found!"
Exit Sub
End If
取得进程标识符
GetWindowThreadProcessId hwnd,pid
使用进程标识符取得进程句柄
pHandle = OpenProcess(PROCESS_ALL_ACCESS,False,pid)
If (pHandle = 0) Then
MsgBox "Couldn’t get a process handle!"
Exit Sub
End If
在内存地址中写入名字
WriteProcessMemory pHandle,0&
关闭进程句柄
CloseHandle hProcess
End Sub
完毕。现在单击按钮将使计算器窗口文本变为我们键如的名字。(可能需要最小化计算器程序,再还原,以便程序更新显示)

下面将给我们的修改增加一个新功能。我们将检测计算器程序的窗口显示数据,并在修改器中显示。双击计时器,显示它的代码编辑窗口,然后输入以下代码
Private Sub ReadTimer_Timer()
声明变量
Dim pHandle As Long ’
储存进程句柄
Dim str As String * 20 ’
存储显示文本
取得目标窗口的句柄 If (hwnd = 0) Then Exit Sub
取得进程标识符取得进程句柄读取内存数据
ReadProcessMemory pHandle,str,20,0&
在文本框显示
txtDisplay = str
关闭进程句柄
CloseHandle hProcess
End Sub
在这里出现的新东西是ReadProcessMemory函数。从&H40B181地址中读出的数据被存入变量str中,然后显示在名为txtDisplay的文本框中

22222222222222222222222222222222222222222222222222222222222

Private Declare Sub WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long,ByVal lpDestBuff As Long,ByVal lpPatchBuff As Long,ByVal CodeSizeLen As Long,ByVal lpNumByWrite As Long)

Dim lpBuff(5) As Byte
lpBuff(0) = &HE9 '
这里开始写你的补丁机器码 lpBuff(1) = &HC9 lpBuff(2) = &H60 lpBuff(3) = &H32 lpBuff(4) = 0 WriteProcessMemory hProcess,&H006b1dd2,VarPtr(lpBuff(0)),0

原文链接:https://www.f2er.com/vb/259041.html

猜你在找的VB相关文章