Vorwort:
Einbettung der Nativen Funktionen:
Anwendung:
In diesem Tutorial wird erklärt, wie mit VB.Net auf den Arbeitsspeicher eines (Spiele-)Prozesses zugegriffen und dieser modifiziert werden kann.Basics:
Dabei werde ich keinen kompletten Sourcecode zur Verfügung stellen, da ich möchte, dass hier was gelernt wird. Kopieren kann schon jeder, dafür muss ich mir für das Tutorial keine Mühe geben.
Microsoft stellt elementare Systemfunktionen bereit, die es einem ermöglichen, auf den Arbeitsspeicher des (Spiele-)Prozesses zuzugreifen. Diese Funktionen werden dazu verwendet:Nun müssen diese Methoden in VB.Net manuell eingebettet werden.
Um überhaupt Zugriff auf den (Spiele-)Prozess zu bekommen muss mit OpenProcess() ein Handle erstellt werden, wobei die [Only registered and activated users can see links. Click Here To Register...] festgelegt werden können. Wir verwenden der Einfachheit halber PROCESS_ALL_ACCESS (&H1F0FFF), das ist zwar nicht sauber, aber am einfachsten.PHP Code:OpenProcess(ByVal DesiredAccess As Integer, ByVal InheritHandle As Boolean, ByVal ProcessId As Integer) As IntPtr
CloseHandle(ByVal ProcessHandle As IntPtr) As Boolean
ReadProcessMemory(ByVal ProcessHandle As IntPtr, ByVal Address As IntPtr, ByVal Buffer As Byte(), ByVal Size As Integer, ByRef NumberOfBytesRead As Integer) As Boolean
WriteProcessMemory(ByVal ProcessHandle As IntPtr, ByVal Address As IntPtr, ByRef Buffer As Byte(), ByVal Size As Integer, ByRef NumberOfBytesWritten As Integer) As Boolean
Schlussendlich sollten wir der Sauberkeit halber das Handle noch mit CloseHandle() schließen, sobald es nicht mehr verwendet wird.
Einbettung der Nativen Funktionen:
Wir erstellen nun eine neue Klasse mit dem "Public" Modifizierer und dem Namen "NativeMethods" und importieren in dieser Klasse die Klasse "System.Runtime.InteropServices".Implementierung der API-Erleichterung:
In VB.Net können native Windows-Funktionen mit folgender Syntax angelegt werden:
In unserem Falle sähe das so aus:Code:<DllImport("DLL-Name", Optionen)> _ [Modifizierer] Function/Sub FunktionsName(Parameter) Rückgabewert End Function/Sub
Zu bemerken ist hier, dass ich die Modifizierer "Private" und "Shared" benutzt habe, das liegt daran, dass ich zum möchte, dass die Funktion nicht direkt, sondern im späteren Sourcecode von einer selbst geschriebenen Funktion aufgerufen werden können, die die Handhabung damit vereinfacht; mehr dazu später.PHP Code:<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function OpenProcess(ByVal DesiredAccess As Integer, ByVal InheritHandle As Boolean, ByVal ProcessID As Integer) As IntPtr
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function CloseHandle(ByVal Handle As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function ReadProcessMemory(ByVal ProcessHandle As IntPtr, ByVal Address As IntPtr, ByRef Buffer As Byte(), ByVal Size As Integer, ByRef NumberOfBytesRead As Integer) As Boolean
End Function
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function WriteProcessMemory(ByVal ProcessHandle As IntPtr, ByVal Address As IntPtr, ByVal Buffer As Byte(), ByVal Size As Integer, ByRef NumberOfBytesWritten As Integer) As Boolean
End Function
Für die nativen Methoden werden als nächstes die Erleichterungs-Funktionen programmiert.
Die OpenProcess()-Methode wird am Ende einzig und allein mit der ProcessId aufgerufen werden, da sich die beiden anderen Paramter für uns nicht verändern, die CloseHandle()-Funktion sogar ganz ohne Parameter.
Für die Read- und WriteProcessMemory()-Methoden werden wir mehrere Erleichterungs-Funktionen implementieren, die es uns ermöglichen mit verschiedenen Variablentypen zu arbeiten.
Zuerst legen wir uns in der Klasse NativeMethods eine IntPtr Variable namens "ProcessHandle" an, welche die Modifizierer "Private" und "Shared" hat und definieren diese als IntPtr.Zero.
OpenProcess:Wir legen in der Klasse NativeMethods eine neue Funktion mit den Modifizierern "Friend" und "Shared", welche ebenfalls "OpenProcess()" heißt ("Überladen einer Funktion") und ein Boolean als Rückgabewert hat, an. Der einzige Parameter der Funktion ist ein Integer-Wert, den wir "PID" nennen.CloseHandle:
Der Körper der Funktion besteht aus folgenden Zeilen:
Somit können wir nun immer NativeMethods.OpenProcess(PID) aufrufen, ohne die beiden für uns unwichtigen Parameter immer setzen und uns um das Handle kümmern zu müssen.PHP Code:NativeMethods.ProcessHandle = NativeMethods.OpenProcess(&H1F0FFF, False, PID)
Return IIf(NativeMethods.ProcessHandle = IntPtr.Zero, False, True)
Diese wird so wie die OpenProcess()-Methode implementiert, nur komplett parameterlos.ReadProcessMemory:
Der Körper sieht wie folgt aus:
PHP Code:If NativeMethods.ProcessHandle = IntPtr.Zero Then Return False
Return NativeMethods.CloseHandle(NativeMethods.ProcessHandle)
Hier gebe ich einfach mal meinen Code zum kopieren, damit lassen sich dann ganz einfach jegliche Variablentypen auslesen. Es wird einfach nur ReadProcessMemory() aufgerufen und der Variablentyp in den gewünschten konvertiert.WriteProcessMemory:
Das selbe für WriteProcessMemory:Unsere Klasse "NativeMethods" ist somit fertig und sollte etwa so aussehen: ([Only registered and activated users can see links. Click Here To Register...])
Anwendung:
OpenProcess:
CloseHandle:PHP Code:If NativeMethods.OpenProcess(Process.GetProcessesByName("GameClient")(0).Id) = True Then ' .exe weglassen, falls der (Spiele-)Prozess auf .exe endet. '
MessageBox.Show("Attached to process!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
MessageBox.Show("Failed attaching to process!" & vbNewLine & "Errorcode: 0x" & Err.GetException.ToString("X8"), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Read Float Value:PHP Code:NativeMethods.CloseHandle()
Read Byte from pointer:PHP Code:Dim MyFloat As Single = 0
NativeMethods.ReadSingle(&H401234, MyFloat)
Read Float from pointer with offset (example: 0x1234):PHP Code:Dim MyByte As Byte = 0
Dim PointerValue As Integer = 0
NativeMethods.ReadInteger(&H401234, PointerValue)
If PointerValue > 0 Then NativeMethods.ReadByte(PointerValue, MyByte)
PHP Code:Dim MyFloat As Single = 0
Dim PointerValue As Integer = 0
NativeMethods.ReadInteger(&H401234, PointerValue)
If PointerValue > 0 Then NativeMethods.ReadInteger(PointerValue + &H1234, PointerValue)
If PointerValue > 0 Then NativeMethods.ReadSingle(PointerValue, MyFloat)