Because so many people seem to have so much trouble finding a 32-bit and 64-bit compatible memory module since the most commonly used one is just downright wrong, I'm posting this which is based off
v1 with fixes/updates based on user suggestion/response.
It supports ANY 'primitive' value type, the most common one you guys will be using is probably:
Integer,
Single (Float) and
String (string is not a primitive type but it's still supported). You can also read
Byte() too (byte array), make sure to indicate how many bytes you want to read though.
Here's a full list if you're interested:
Boolean,
Byte,
SByte,
Int16 (
Short),
UInt16 (
UShort),
Int32 (
Integer),
UInt32 (
UInteger),
Int64 (
Long),
UInt64 (
ULong),
IntPtr,
UIntPtr,
Char,
Double, and
Single (Float).
Here's the code:
Code:
Option Strict On
Imports System.Runtime.InteropServices
Imports System.Text
Module MemoryModule
<DllImport("kernel32.dll")> _
Private Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Function WriteProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As Byte(), ByVal nSize As IntPtr, <Out()> ByRef lpNumberOfBytesWritten As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, <Out()> ByVal lpBuffer() As Byte, ByVal dwSize As IntPtr, ByRef lpNumberOfBytesRead As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)>
Private Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Const PROCESS_VM_WRITE As UInteger = &H20
Private Const PROCESS_VM_READ As UInteger = &H10
Private Const PROCESS_VM_OPERATION As UInteger = &H8
Private TargetProcess As String = "iw6mp64_ship"
Private ProcessHandle As IntPtr = IntPtr.Zero
Private LastKnownPID As Integer = -1
Private Function ProcessIDExists(ByVal pID As Integer) As Boolean
For Each p As Process In Process.GetProcessesByName(TargetProcess)
If p.ID = pID Then Return True
Next
Return False
End Function
Public Sub SetProcessName(ByVal processName As String)
TargetProcess = processName
If ProcessHandle <> IntPtr.Zero Then CloseHandle(ProcessHandle)
LastKnownPID = -1
ProcessHandle = IntPtr.Zero
End Sub
Public Function GetCurrentProcessName() As String
Return TargetProcess
End Function
Public Function UpdateProcessHandle() As Boolean
If LastKnownPID = -1 OrElse Not ProcessIDExists(LastKnownPID) Then
If ProcessHandle <> IntPtr.Zero Then CloseHandle(ProcessHandle)
Dim p() As Process = Process.GetProcessesByName(TargetProcess)
If p.Length = 0 Then Return False
LastKnownPID = p(0).Id
ProcessHandle = OpenProcess(PROCESS_VM_READ Or PROCESS_VM_WRITE Or PROCESS_VM_OPERATION, False, p(0).Id)
If ProcessHandle = IntPtr.Zero Then Return False
End If
Return True
End Function
Public Function ReadMemory(Of T)(ByVal address As Object) As T
Return ReadMemory(Of T)(CLng(address))
End Function
Public Function ReadMemory(Of T)(ByVal address As Integer) As T
Return ReadMemory(Of T)(New IntPtr(address), 0, False)
End Function
Public Function ReadMemory(Of T)(ByVal address As Long) As T
Return ReadMemory(Of T)(New IntPtr(address), 0, False)
End Function
Public Function ReadMemory(Of T)(ByVal address As IntPtr) As T
Return ReadMemory(Of T)(address, 0, False)
End Function
Public Function ReadMemory(ByVal address As IntPtr, ByVal length As Integer) As Byte()
Return ReadMemory(Of Byte())(address, length, False)
End Function
Public Function ReadMemory(ByVal address As Integer, ByVal length As Integer) As Byte()
Return ReadMemory(Of Byte())(New IntPtr(address), length, False)
End Function
Public Function ReadMemory(ByVal address As Long, ByVal length As Integer) As Byte()
Return ReadMemory(Of Byte())(New IntPtr(address), length, False)
End Function
Public Function ReadMemory(Of T)(ByVal address As IntPtr, ByVal length As Integer, ByVal unicodeString As Boolean) As T
Dim buffer() As Byte
If GetType(T) Is GetType(String) Then
If unicodeString Then buffer = New Byte(length * 2 - 1) {} Else buffer = New Byte(length - 1) {}
ElseIf GetType(T) Is GetType(Byte()) Then
buffer = New Byte(length - 1) {}
Else
buffer = New Byte(Marshal.SizeOf(GetType(T)) - 1) {}
End If
If Not UpdateProcessHandle() Then Return Nothing
Dim success As Boolean = ReadProcessMemory(ProcessHandle, address, buffer, New IntPtr(buffer.Length), IntPtr.Zero)
If Not success Then Return Nothing
If GetType(T) Is GetType(Byte()) Then Return CType(CType(buffer, Object), T)
If GetType(T) Is GetType(String) Then
If unicodeString Then Return CType(CType(Encoding.Unicode.GetString(buffer), Object), T)
Return CType(CType(Encoding.ASCII.GetString(buffer), Object), T)
End If
Dim gcHandle As GCHandle = gcHandle.Alloc(buffer, GCHandleType.Pinned)
Dim returnObject As T = CType(Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject, GetType(T)), T)
gcHandle.Free()
Return returnObject
End Function
Private Function GetObjectBytes(ByVal value As Object) As Byte()
If value.GetType() Is GetType(Byte()) Then Return CType(value, Byte())
Dim buffer(Marshal.SizeOf(value) - 1) As Byte
Dim ptr As IntPtr = Marshal.AllocHGlobal(buffer.Length)
Marshal.StructureToPtr(value, ptr, True)
Marshal.Copy(ptr, buffer, 0, buffer.Length)
Marshal.FreeHGlobal(ptr)
Return buffer
End Function
Public Function WriteMemory(Of T)(ByVal address As Object, ByVal value As T) As Boolean
Return WriteMemory(CLng(address), value)
End Function
Public Function WriteMemory(Of T)(ByVal address As Object, ByVal value As Object) As Boolean
Return WriteMemory(CLng(address), CType(value, T))
End Function
Public Function WriteMemory(Of T)(ByVal address As Integer, ByVal value As T) As Boolean
Return WriteMemory(New IntPtr(address), value)
End Function
Public Function WriteMemory(Of T)(ByVal address As Integer, ByVal value As Object) As Boolean
Return WriteMemory(address, CType(value, T))
End Function
Public Function WriteMemory(Of T)(ByVal address As Long, ByVal value As T) As Boolean
Return WriteMemory(New IntPtr(address), value)
End Function
Public Function WriteMemory(Of T)(ByVal address As Long, ByVal value As Object) As Boolean
Return WriteMemory(address, CType(value, T))
End Function
Public Function WriteMemory(Of T)(ByVal address As IntPtr, ByVal value As T) As Boolean
Return WriteMemory(address, value, False)
End Function
Public Function WriteMemory(Of T)(ByVal address As IntPtr, ByVal value As Object) As Boolean
Return WriteMemory(address, CType(value, T), False)
End Function
Public Function WriteMemory(Of T)(ByVal address As Object, ByVal value As T, ByVal unicode As Boolean) As Boolean
Return WriteMemory(CLng(address), value, unicode)
End Function
Public Function WriteMemory(Of T)(ByVal address As Integer, ByVal value As T, ByVal unicode As Boolean) As Boolean
Return WriteMemory(New IntPtr(address), value, unicode)
End Function
Public Function WriteMemory(Of T)(ByVal address As Long, ByVal value As T, ByVal unicode As Boolean) As Boolean
Return WriteMemory(New IntPtr(address), value, unicode)
End Function
Public Function WriteMemory(Of T)(ByVal address As IntPtr, ByVal value As T, ByVal unicode As Boolean) As Boolean
If Not UpdateProcessHandle() Then Return False
Dim buffer() As Byte
If TypeOf value Is String Then
If unicode Then buffer = Encoding.Unicode.GetBytes(value.ToString()) Else buffer = Encoding.ASCII.GetBytes(value.ToString())
Else
buffer = GetObjectBytes(value)
End If
Dim result As Boolean = WriteProcessMemory(ProcessHandle, address, buffer, New IntPtr(buffer.Length), IntPtr.Zero)
Return result
End Function
End Module
How do I use the code?
Right-click on your project and
Add >
Module. Call it MemoryModule.vb or whatever you like. Then copy the code above and paste it into the new module (replace everything). If you want to use this module on another process, replace "iw6mp64_ship" with whatever you want next to 'TargetProcess'.
How do you change the process during runtime?
I've added a function called "SetProcessName" which allows you to do that.
Example:
Code:
SetProcessName("iw6sp64_ship")
How do you know what the current process is set to?
Use the "GetCurrentProcessName" function.
How do I know if the process/game is open?
There's a function called "UpdateProcessHandle" which returns a boolean saying if the game is active or not.
Example (in a timer):
Code:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If UpdateProcessHandle() Then ' Check if the game is running
' Do stuff here, like writing/reading memory or telling a user in a Label the game is open.
End If
End Sub
How do I read or write memory?
Version 1 of the memory module made things a little complicated for writing memory but this version tries to fix that. To read or write memory, you use the "ReadMemory" or "WriteMemory" functions.
' Reads the value from 0x12345678 as an Integer
Dim myIntValue As Integer = ReadMemory(Of Integer)(&H12345678)
' Reads the value from 0x12345678 as a Single (remember that Single is the same as Float)
Dim myFloatValue As Single = ReadMemory(Of Single)(&H12345678)
' Reads 10 characters at 0x12345678 as an ASCII String
Dim myASCIIStringValue As String = ReadMemory(Of String)(&H12345678, 10, False)
' Reads 10 characters at 0x12345678 as a Unicode String
Dim myUnicodeStringValue As String = ReadMemory(Of String)(&H12345678, 10, True)
' Reads 12 bytes from 0x12345678
Dim myByteData() As Byte = ReadMemory(&H12345678, 12)
' Writes 10 as an Integer to 0x12345678
WriteMemory(Of Integer)(&H12345678, 10)
' Writes 0.5 as a Single/Float to 0x12345678
WriteMemory(Of Single)(&H12345678, 0.5)
' Writes Hello World as an ASCII string to 0x12345678 (the + vbNullChar erases the rest of the old string)
WriteMemory(Of String)(&H12345678, "Hello World" + vbNullChar, False)
' Writes Hello World as a Unicode string to 0x12345678 (the + vbNullChar erases the rest of the old string)
WriteMemory(Of String)(&H12345678, "Hello World" + vbNullChar, True)
' Writes '0x90, 0x90, 0x90, 0x90' as a byte array to 0x12345678
WriteMemory(&H12345678, New Byte() { &H90, &H90, &H90, &H90 })
How do I read or write a number into memory if I'm going to get it from a textbox or a string?
Since VB.NET (by default) doesn't care much about types (they are converted automatically), you should be able to get away with this:
' Reads the integer from the address inside TextBox1 (warning: the string must start with &H if its an address/hex value)
Dim myIntValue As Integer = ReadMemory(Of Integer)("&H" + TextBox1.Text)
' Writes the value from TextBox1 into 0x12345678 as an integer
WriteMemory(Of Integer)(&H12345678, TextBox1.Text)
' Writes the value from TextBox1 into 0x12345678 as a single/float
WriteMemory(Of Single)(&H12345678, TextBox1.Text)
' Writes 10 into the address inside TextBox1 as an integer (warning: the string must start with &H if its an address/hex value)
WriteMemory(Of Integer)("&H" + TextBox1.Text, 10)
What's the difference between a ASCII and Unicode string?
Unicode strings use 2 bytes for every letter it uses and ASCII only uses 1 byte for every letter. If you find a string in memory with Cheat Engine with the Unicode box unticked then it's a ASCII string. If the Unicode box is ticked then it's a Unicode string.