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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")