Simples Gamehacking via Memoryediting

07/10/2009 00:04 Mi4uric3#1
Vorwort:
In diesem Tutorial wird erklärt, wie mit VB.Net auf den Arbeitsspeicher eines (Spiele-)Prozesses zugegriffen und dieser modifiziert werden kann.
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.
Basics:
Microsoft stellt elementare Systemfunktionen bereit, die es einem ermöglichen, auf den Arbeitsspeicher des (Spiele-)Prozesses zuzugreifen. Diese Funktionen werden dazu verwendet:
PHP Code:
OpenProcess(ByVal DesiredAccess As IntegerByVal InheritHandle As BooleanByVal ProcessId As Integer) As IntPtr
CloseHandle
(ByVal ProcessHandle As IntPtr) As Boolean
ReadProcessMemory
(ByVal ProcessHandle As IntPtrByVal Address As IntPtrByVal Buffer As Byte(), ByVal Size As IntegerByRef NumberOfBytesRead As Integer) As Boolean
WriteProcessMemory
(ByVal ProcessHandle As IntPtrByVal Address As IntPtrByRef Buffer As Byte(), ByVal Size As IntegerByRef NumberOfBytesWritten As Integer) As Boolean 
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.
Schlussendlich sollten wir der Sauberkeit halber das Handle noch mit CloseHandle() schließen, sobald es nicht mehr verwendet wird.
Nun müssen diese Methoden in VB.Net manuell eingebettet werden.

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".

In VB.Net können native Windows-Funktionen mit folgender Syntax angelegt werden:
Code:
<DllImport("DLL-Name", Optionen)> _
[Modifizierer] Function/Sub FunktionsName(Parameter) Rückgabewert
End Function/Sub
In unserem Falle sähe das so aus:
PHP Code:
<DllImport("kernel32.dll"SetLastError:=True)> _
Private Shared Function OpenProcess(ByVal DesiredAccess As IntegerByVal InheritHandle As BooleanByVal 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 IntPtrByVal Address As IntPtrByRef Buffer As Byte(), ByVal Size As IntegerByRef NumberOfBytesRead As Integer) As Boolean
End 
Function
<
DllImport("kernel32.dll"SetLastError:=True)> _
Private Shared Function WriteProcessMemory(ByVal ProcessHandle As IntPtrByVal Address As IntPtrByVal Buffer As Byte(), ByVal Size As IntegerByRef NumberOfBytesWritten As Integer) As Boolean
End 
Function 
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.
Implementierung der API-Erleichterung:
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.
Der Körper der Funktion besteht aus folgenden Zeilen:
PHP Code:
NativeMethods.ProcessHandle NativeMethods.OpenProcess(&H1F0FFFFalsePID)
Return 
IIf(NativeMethods.ProcessHandle IntPtr.ZeroFalseTrue
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.
CloseHandle:
Diese wird so wie die OpenProcess()-Methode implementiert, nur komplett parameterlos.
Der Körper sieht wie folgt aus:
PHP Code:
If NativeMethods.ProcessHandle IntPtr.Zero Then Return False
Return NativeMethods.CloseHandle(NativeMethods.ProcessHandle
ReadProcessMemory:
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:
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.OKMessageBoxIcon.Information)
Else
    
MessageBox.Show("Failed attaching to process!" vbNewLine "Errorcode: 0x" Err.GetException.ToString("X8"), "Error"MessageBoxButtons.OKMessageBoxIcon.Error)
End If 
CloseHandle:
PHP Code:
NativeMethods.CloseHandle() 
Read Float Value:
PHP Code:
Dim MyFloat As Single 0
NativeMethods
.ReadSingle(&H401234MyFloat
Read Byte from pointer:
PHP Code:
Dim MyByte As Byte 0
Dim PointerValue 
As Integer 0
NativeMethods
.ReadInteger(&H401234PointerValue)
If 
PointerValue 0 Then NativeMethods.ReadByte(PointerValueMyByte
Read Float from pointer with offset (example: 0x1234):
PHP Code:
Dim MyFloat As Single 0
Dim PointerValue 
As Integer 0
NativeMethods
.ReadInteger(&H401234PointerValue)
If 
PointerValue 0 Then NativeMethods.ReadInteger(PointerValue + &H1234PointerValue)
If 
PointerValue 0 Then NativeMethods.ReadSingle(PointerValueMyFloat
07/10/2009 08:19 Akorn#2
Am besten überarbeitest du nochmal das tutorial weil du hast ja nichtmal den code erklärt oder kommentiert sondern einfach nur geschrieben was wo hingeschrieben werden soll.
07/10/2009 17:43 Mi4uric3#3
Okay mach ich, ich hatte nur gestern kaum noch Zeit, weil dann bald mein Internet ausgegangen ist ;)

#habs ein wenig überarbeitet, hoffe es ist jetzt ersichtlicher .. :/
08/06/2009 01:58 snopy12#4
wo soll ich das next hinschreiben ? da kommt For Each ....... und dann erwartet der ein next :mad:
09/05/2009 15:32 DarkHaze#5
pList = System.Diagnostics.Process.GetProcesses
For Each proc As System.Diagnostics.Process In pList
If proc.ProcessName = ExeName Then
Prozess1 = proc
LabelActive.ForeColor = Color.Green
LabelActive.Text = "Game found!"
TextBoxLives.Text = ReadLong(Prozess1, "&H *EureAdresseOhneDieErsteNullAmAnfang*") 'Lebenszahl
Exit Sub
End If
LabelActive.ForeColor = Color.Red
LabelActive.Text = "Game not found!"
TextBoxLives.Text = Nothing
next

Die Grundkenntnisse sollten schon vorhanden sein...
12/20/2009 17:23 .ShoXx!#6
Hab da mal eine Frage, im 3. Code:

Code:
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcessId As Integer) As Integer
    Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    Private Declare Function WriteFloatMemory Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Single, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    Private Declare Function ReadFloat Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByRef buffer As Single, ByVal size As Int32, ByRef lpNumberOfBytesRead As Int32) As Boolean
    Private Declare Function ReadProcessMemory Lib "kernel32" Alias "ReadProcessMemory" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
    Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Public RBuff As Long
    Public RBuff2 As Single
    Public RBuff3 As Integer

    Public Function Writememory(ByVal ProcessName As Process, ByVal Address As Integer, ByVal Value As Long, ByVal Bytes As Integer)
        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If
        [color=red]Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)[/color]

        WriteProcessMemory(processHandle, Address, Value, Bytes, Nothing)

        CloseHandle(processHandle)

    End Function

    Public Function ReadFloat(ByVal ProcessName As Process, ByVal Address As Single)

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Address, RBuff, 4, Nothing)

        CloseHandle(processHandle)

        Return RBuff

    End Function

    Public Function WriteFloat(ByVal ProcessName As Process, ByVal Address As Integer, ByVal Value As Single)

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        WriteFloatMemory(processHandle, Address, Value, 4, Nothing)

        CloseHandle(processHandle)

    End Function

    Public Function ReadLong(ByVal ProcessName As Process, ByVal Address As Integer)

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Address, RBuff, 4, Nothing)

        CloseHandle(processHandle)

        Return RBuff

    End Function

    Public Function ReadFloatPointer(ByVal ProcessName As Process, ByVal Base As Integer, ByVal Offset As Short)

        Dim fullAddress As Long

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Base, RBuff, 4, Nothing)

        fullAddress = RBuff + Offset

        ReadFloat(processHandle, fullAddress, RBuff2, 4, Nothing)

        Return RBuff2

        CloseHandle(processHandle)

    End Function

    Public Function ReadLongPointer(ByVal ProcessName As Process, ByVal Base As Integer, ByVal Offset As Short, ByVal Bytes As Integer)

        Dim fullAddress As Long

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Base, RBuff, 4, Nothing)

        fullAddress = RBuff + Offset

        ReadProcessMemory(processHandle, fullAddress, RBuff3, Bytes, Nothing)

        Return RBuff3

        CloseHandle(processHandle)

    End Function

    Public Function WriteFloatPointer(ByVal ProcessName As Process, ByVal Base As Integer, ByVal Offset As Short, ByVal Value As Single)

        Dim fullAddress As Long

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Base, RBuff, 4, Nothing)

        fullAddress = RBuff + Offset

        WriteFloatMemory(processHandle, fullAddress, Value, 4, Nothing)

        CloseHandle(processHandle)

    End Function

    Public Function WriteLongPointer(ByVal ProcessName As Process, ByVal Base As Integer, ByVal Offset As Short, ByVal Value As Long, ByVal Bytes As Integer)

        Dim fullAddress As Long

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        ReadProcessMemory(processHandle, Base, RBuff, 4, Nothing)

        fullAddress = RBuff + Offset

        WriteProcessMemory(processHandle, fullAddress, Value, Bytes, Nothing)

        CloseHandle(processHandle)

    End Function

    Public Function NOP(ByVal ProcessName As Process, ByVal Address As Integer, ByVal value As Integer)

        Dim GameLookUp As Process() = Process.GetProcessesByName(ProcessName.ProcessName)

        If GameLookUp.Length = 0 Then

            End

        End If

        Dim processHandle As IntPtr = OpenProcess(&H1F0FFF, 0, GameLookUp(0).Id)

        WriteProcessMemory(processHandle, Address, value, 1, Nothing)

        CloseHandle(processHandle)

    End Function

End Module
Muss man das, was ich jetzt rotmarkiert habe, stehen lassen, oder in das ändern, was man davor in CheatEngine herausbekommen hat?
12/28/2009 17:33 Wild-Life78#7
Gibt es jemanden bei dem das Funktioniert, irgenwie kommt es mir so vor als wenn die hälfte des Codes der im Modul steht garnicht notwendig ist.????
Gruss Wild-Life78
12/29/2009 22:41 GoneUp#8
mhm habs mla gerade getestet.

Hab es aber nicht zum Laufen bekommen.
Wie zur Hölle bekomme ich die Adresse "0BF38FB4" als Intreger hin?

EDIT: Geschafft kann man ganz einfach online konvertiern. [Only registered and activated users can see links. Click Here To Register...]
Funktioniert also
12/30/2009 00:53 Wild-Life78#9
Ja bei funzt es jetzt auch, allerdings nur auf den Rechner mit Xp, auf Vista64 Bit gibt ReadProcessMemory immer 0 zurück und das obwohl die Pointer/BasePointer richtig sind.
Hat jemand unter 64 Bit ebenfalls Probleme mir ReadProcessMemory ????

Lg Wild

Ps ansonsten gutes Tut obwohl ich am Anfang etwas skeptisch war.
12/30/2009 00:57 Wild-Life78#10
Quote:
Originally Posted by cheater94x View Post
mhm habs mla gerade getestet.

Hab es aber nicht zum Laufen bekommen.
Wie zur Hölle bekomme ich die Adresse "0BF38FB4" als Intreger hin?

EDIT: Geschafft kann man ganz einfach online konvertiern. [Only registered and activated users can see links. Click Here To Register...]
Funktioniert also
Du brauchst nicht konvertieren mache aus "0BF38FB4" ein "&H0BF38FB4" und schon gehts das "&H" steht für hexadezimal Visualbasic weiß dann schon was gemeint ist.

Lg Wild....
12/30/2009 01:48 GoneUp#11
Au da bin ich auf einem schlauch gestanden.

Aber das tut ist ausbauwürdig. Das sollte man an einem programm wie solitär erklären.
12/30/2009 08:52 Wild-Life78#12
LOL genau da bin ich gerade Dabei, allerdings Macht mir mein 64Bit system zu schaffen, denn dort funktioniert der ReadProcessMemory nicht, er gibt mir als Wert immer 0 zurück.
Und unter Xp 32 Bit geht es ohne Probleme.

Lg Wild-Life78
01/14/2010 17:09 bozzh22#13
Das Tutorial ist einfach Sche*sse!
Garnichts funktioniert und nur Errors...!
Der Name "pList" wurde nicht deklariert.
Die Writememory-Funktion gibt nicht für alle Codepfade einen Wert zurück. Wenn das Ergebnis verwendet wird, kann zur Laufzeit eine Nullverweisausnahme auftreten.
UND UND UND!
Garnichts funktioniert -.-
01/18/2010 21:20 Mi4uric3#14
Quote:
Originally Posted by bozzh22 View Post
Das Tutorial ist einfach Sche*sse!
Garnichts funktioniert und nur Errors...!
Der Name "pList" wurde nicht deklariert.
Die Writememory-Funktion gibt nicht für alle Codepfade einen Wert zurück. Wenn das Ergebnis verwendet wird, kann zur Laufzeit eine Nullverweisausnahme auftreten.
UND UND UND!
Garnichts funktioniert -.-
Deine Mama gibt auch nichts zurück. Was sie einmal geklaut hat, behält sie für immer
Deine Mama hat mit deinem Vadder auch nicht funktioniert

Das Ergebnis warst letztendlich du

_
Mal ernsthaft. Das geht auch anständig, oder?
Bei mir klappt alles, vielleicht liegts daran, dass du Win7 benutzt, auf meinem XP Rechner funktioniert alles bestens.

Und wenn, mach doch ein besseres, anstatt nur zu nörgeln
03/11/2010 15:38 Bruno1212#15
Hallo,

Ich habe folgenede frage wie kann ich eine text value auslesen ???

ich hab schon folgendes versucht:

Code:
Private Sub setlives()
        Writememory(Prozess1, "&H1012F60", MyLives, "Text")
    End Sub

aber das hat leider nicht geklappt könntest mir bitte einer helfen

Mfg Bruno1212