Register for your free account! | Forgot your password?

Go Back   elitepvpers > Shooter > WarRock > WarRock Guides, Tutorials & Modifications
You last visited: Today at 10:34

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



WarRock C&P Hacks mal wirklich verstehen

Discussion on WarRock C&P Hacks mal wirklich verstehen within the WarRock Guides, Tutorials & Modifications forum part of the WarRock category.

Reply
 
Old   #1
 
elite*gold: 0
Join Date: May 2008
Posts: 132
Received Thanks: 120
WarRock C&P Hacks mal wirklich verstehen

Habe in den letzten Tagen folgendes geschrieben:

ist knapp 11 Seiten lang geworden.



WarRock C&P Hacks mal wirklich verstehen

Hey ho, ich habe mich in der letzten Zeit ein wenig mit dem Gamehacking beschäftigt und mich vor allem mit WarRock auseinandergesetzt. Es gibt sehr viele Hacks für dieses Spiel und alle sind verdächtig ähnlich aufgebaut. Als wäre das nicht genug findet man auch immer mehr Beiträge von Usern die sich bescheren, dass der kopierte Code nicht(mehr) funktioniert, weil sie nicht wissen wie sie den Code anpassen müssen, geschweige denn wissen, wie der kopierte Code überhaupt funktioniert. An solche User richtet sich dieser Text, ich werde versuchen alle Funktionen, die man in den üblichen Sourcecodes findet zu erläutern, wie ich sie mir vor einigen Wochen angeeignet habe. Das hilft euch hoffentlich zu einem erweiterten Verständnis und mir hoffentlich den Stoff zu verinnerlichen.

WarRock ist wohl eins der besten Spiele, um ins Gamehacking einzusteigen, weil es sehr clientseitig programmiert wurde. Das heißt, dass ein Großteil der Berechnungen auf dem eigenen Computer getätigt werden und kaum vom Gameserver überprüft werden. Diese Berechnungen kann man ganz einfach zu eigenen Gunsten manipulieren. So ist es relativ einfach einen Teleporter zu schreiben, der in Spielen wie Counter-Strike und Metin2 wohl nicht so leicht realisierbar wäre.
Wir werden uns in diesem Text mit den einfachen NonMenü WarRock Hacks beschäftigen, da ich erst seit einigen Wochen in C++ programmiere und wenig Erfahrung mit der 3D3-Programmierung habe.
Speicheradressen und deren Werte
Jede hier verwendete Adresse ist wahrscheinlich nicht mehr aktuell!
Fangen wir mal ganz von vorne an. Ein Programm (auch WarRock) besteht aus mehreren Segmenten (genau genommen 5 Stück: Text-,Daten-,BSS- und Heap- und Stacksegment). Jedes Segment hat eine andere Aufgabe und ist in Adressen unterteilt. An jeder Adresse befindet sich ein Wert. Im Textsegment steht z.B der Programmcode, der auch als Opcode bezeichnet wird. Im BSS- und Datensegment befinden sich z.B. globale Variablen des Programmes. Betrachtet man eine bestimmte Adresse, die sich im Textsegment befindet, so erhält man einen Ausschnitt der Assemblerinstruktionen des Programmes. Betrachtet man jedoch eine Adresse innerhalb des Datensegments, so erhält man irgend einen Wert, den das Programm gerade gespeichert hat, z.B. die Anzahl der Lebenspunkte, oder der Name eines Spielers.
Wichtig für uns zu wissen ist, dass eine Adresse immer einen Wert hat. Dieser Wert kann ein Buchstabe, ein Text oder eine Zahl sein. Später dazu mehr.
Die DLL Injection
Viele WarRock Hacks verwenden eine DLL Injection, um das Spiel zu beeinflussen. Eine DLL Injection macht die Speichermanipulation um einiges leichter, da man sozusagen in den Spielprozess rein programmieren kann. Der Sourcecode wird vom Compiler in Maschinensprache übersetzt und in der DLL gespeichert. Anschließend wird die DLL mit einem Injector oder einem Loader in den Spielprozess injiziert und dieser wird gezwungen die DLL auszuführen. Komischerweise werden fast alle NonMenü WarRock Hacks in DLLs verpackt, obwohl man das ganze auch einfach extern mit Writeprocessmemory o.ä. gestalten könnte, somit wäre eine Manipulation auch ohne DLL Injectior/Loader möglich.

Der C&P Code
Gut, (fast)jede DLL Injection baut auf einer bestimmten Funktion auf, der DllMain() Funktion. Diese Funktion wird immer aufgerufen, wenn die DLL geladen wird. Eventuell kennt ihr ja die main() Funktion aus C/C++ oder Java Programmen. Diese main() Funktion wird immer als erstes beim Programmstart ausgeführt und ähnlich verhält es sich mit der DllMain Funktion in DLL Dateien. Diese Funktion findet man in fast jedem WarRock Hack und so sieht sie meistens aus:
Code:
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved)
{
	if(dwReason == DLL_PROCESS_ATTACH)
	{
		CreateThread(0, 0, (LPTHREAD_START_ROUTINE)HackThread, 0, 0, 0);
	}
	return TRUE;
}
Alleine die Tatsache, dass die Hackfunktion bei einem Großteil der Hacks immer wieder „HackThread“ heißt, spricht für sich. Nun ja, diese Funktion wird also beim Laden der DLL aufgerufen und wir schauen uns alles genau an.
BOOL das heißt einfach, dass die Funktion einen boolischen Wert zurück gibt. Ein boolischer Wert kann nur zwei Zustände annehmen: Wahr (true) oder Falsch (false).
Wie wir sehen wird in der vorletzten Zeile mit dem return Befehl einfach der Wert TRUE zurück gegeben. Was das WINAPI macht weiß ich selber garnicht so genau. Eventuell gibt es auf anderen Systemen solche DllMain() Funktionen nicht und es ist ein Hinweiß für den Compiler, ich weiß es ehrlich gesagt nicht.
So, nun kommt der Name der Funktion, DllMain(). Die Funktion muss einfach so heißen, damit sie beim Start ausgeführt wird, würden wie sie anders nennen, würde das ganze nicht funktionieren. Vlt. kann man die DllMain Funktion bei einigen Compiler umbenennen, im Normalfall bleibt man jedoch bei diesem Namen.
Nach dem Funktionsnamen werden 3 Parameter übergeben. Ähnliches kennt man aus der main() Funktion in C/C++ und Java, dort werden die Kommandozeilenargumente übergeben (int argc und char *argv[]). Die DllMain() Funktion bekommt also 3 Parameter. Der erste Parameter heißt hModule und ist vom Datentype HINSTANCE. Dieser Parameter beinhaltet das Handle der DLL, für den Hack nicht wichtig.
Der zweige Parameter heißt dwReason und ist vom Datentype DWORD. Dieser Parameter ist schon interessanter. Er sagt uns, wie die DLL geladen wurde. Was der dritte Parameter für eine Funktion hat weiß ich nicht so genau, das ist für den Hack aber auch nicht relevant.
So, das war soweit der sogenannte Funktionskopf, nun folgt in geschweiften Klammern der Funktionsrumpf, also das, was ausgeführt werden soll, wenn die Funktion aufgerufen wird.

Die Funktion beginnt mit einer If-Abfrage. Hier wird überprüft, ob der Parameter dwReason den Wert DLL_PROCESS_ATTACH besitzt. DLL_PROCESS_ATTACH ist eine Konstante, die den Wert 1 hat. Konstanten werden in C++ meistens komplett groß geschrieben, das dient einfach der Übersicht. Da diese Konstante für den Wert 1 steht könnte man die If-Abfrage auch einfach so verwirklichen:
Code:
if(dwReason == 1)
Das ist zwar kürzer, aber nicht so ersichtlich, wie der Vergleich mit der Konstanten. Nach dem Kopf der If-Abfrage folgt der Rumpf der Abfrage. Hier steht der Quellcode, der ausgeführt wird, wenn die Bedingung im Kopf war ist. Der Rumpf ist wieder durch geschweifte Klammern definiert.
Einige Hacks verwenden hier auch die Switsh-Case Operation, finde ich eigendlich total schwachsinnig. Die If-Abfrage überprüft also einfach, ob die DLL von einem DLL Injector/Loader in einen Prozess injiziert wurde.
So, nun wird mit der CreateThread() Funktion ein neuer Thread erstellt, aber warum ?
Threading
Jedes Programm hat, wenn es gestartet wird, einen Mainthread, einen Hauptthread, dort beginnt das Programm. Zum Glück gibt es das sogenannte Multithreading, es erlaubt einem Programm mehrere Operationen gleichzeitig auszuführen. Wenn man die Operationen eines Programmes auf 10 Threads verteilt, wird das Programm fast 10 mal so schnell.
Also, wenn wir die DLL in einen Prozess injizieren, dann wird diese in einen Thread des Prozesses injiziert. Wenn wir durch unseren Hack den Verlauf dieses Threads stören würden, dann könnte es zu großen Großen Problemen kommen. Deshalb erstellen wir sobald die DLL Injiziert wurde einen neuen Thread, der unseren Opferprozess nicht weiter stört.
Zurück zum Hack
Zurück zum C&P Code. Die CreateThread() Funktion hat 6 Parameter. Ich weiß nicht genau, welche Parameter welche Funktion sie erfüllen. Einige dienen der Überwachung des erstellten Threads, andere übergeben Parameter an den Thread. In unserem Falle soll die HackThread Funktion in einem Thread gestartet werden. Dies wird im 3. Parameter festgelegt. Da CreateThread allerdings einen Pointer auf die auszuführende Funktion erwartet, müssen wir den übergebenen Wert noch in den richtigen Type casten, das macht man in C/C++ in dem man den Datentype, in den man casten möchte in Klammern davor schreibt, das macht also das (LPTHREAD_START_ROUTINE). So, das return True hatten wir ja bereits diskutiert. Ich denke man kann auch False zurückgeben. Bei einigen Compiler muss man auch keinen Rückgabewert definieren, andere wiederum verlangen ihn.
Gut, unsere Funktion mit dem Namen HackThread() wird also in eine Thread ausgeführt und interessiert den Prozess (WarRock) nicht die Bohne. Also betrachten wir mal die HackThread() Funktion:
Code:
void HackThread()
{
	for(;; )
	{
		if(*ingame)
		{
			PlayerHacks();
		}
		if(*outgame)
		{
			ServerHacks();
		}
	}
	Sleep( 200 ); // Prevent for overloading CPU!
}
So, Wir sehen oben den Funktionskopf. Die Funktion heißt HackThread, sie ist vom Datentype Viod, das heißt, dass sie keinen Rückgabewert braucht. Da die Klammern nach dem Funktionsnamen leer sind, müssen keine Parameter beim Funktionsaufruf übergeben werden. Wir erinnern uns: beim Starten der Funktion in einem Thread haben wir der Funktion auch keinen Parameter mitgegeben.
Im Funktionsbauch sehen wir eine For-Schleife. Zu beachten ist, dass der Kopf der For-Schleife leer ist. Normalerweise sieht der Kopf einer For-Schleife in C++ so aus:
Code:
for(int i = 0;i<20;i++)
Der Kopf enthält eine eine Deklaration (int i = 0), eine Bedingung (i<20) und eine Instruktion (i++), alles steuert den Schleifenablauf.
Lässt man alle diese Instruktionen und Anweisungen im Funktionskopf weg, so erhält man eine Endlosschleife, also eine Schleife, die unendlich durchläuft. Es wäre wohl schöner gewesen, eine While-True Schleife zu verwenden. Eventuell war der Programmierer ein Feind der While-Schleife, oder er war so ein Scriptkiddy, dass er um deren Existenz nicht wusste.
Eine While-True Schleife sieht wie folgt aus und macht genau das selbe:
Code:
while (true){
	Anweisungen...
}
Da der Wert, der dem Schleifenkopf übergeben wird, immer True ist, läuft die Schleife endlos. Am ende der Schleife wird die Sleep Funkion aufgerufen:
Sleep( 200 ); // Prevent for overloading CPU!
Die Sleep Funktion lässt das Programm einfach warten, in diesem Falle 200 Millisekunden, also 0,2 Sekunden. Das macht man, um die CPU in einer Endlosschleife zu entlasten.
Der englische Kommentar zeigt auch hier wieder, das der Code einfach kopiert wurde.
Die Includs, Addys und Pointer in C++
Um die Addys zu verstehen, braucht es ein Weilchen.
Dazu betrachten wir uns mal alle Sachen, die Global deklariert wurden:
Code:
#include <Windows.h>
#include <stdio.h>
#define	Addr_Playerpointer	0xC62388
#define	Addr_Serverpointer	0xB5D0F8
#define	Ofs_Z			0x102D8
#define	Ofs_NoFallDamage	0x103A4
DWORD *ingame = (DWORD*)Addr_Playerpointer;
DWORD *outgame = (DWORD*)Addr_Serverpointer;
Als erstes sehen wir die Includes.
Man fügt dem Programm sogenannte Header-Dateien an, um mehr Funktionen zu erhalten. Die Windows Header-Datei (Windows.h) stellt , wie der Name schon sagt, viele Windowsfunktionen zur Verfügung, darunter die WindowsAPI Funktionen (z.B. CreateThread()).
Die stdio.h stellt uns ältere C-Funktionen zur Verfügung. Da diese Funktionen im Hack nicht gebraucht werden, hat der Programmierer dies wohl übersehen, ein erneutes Zeichen dafür, dass er wenig Ahnung von dem hat, was er da eigentlich macht.
Unter den Includes werden die Addys und Offsets per #define Makro definiert. Ich weiß nicht, warum alle die Addys immer so ins Programm integrieren. Man könnte sie auch einfach als Variablen oder Konstanten definieren. Eventuell hat die #define Methode bestimmte Vorteile denen ich mir nicht bewusst bin, vlt. hat der Programmierer den Code auch einfach kopiert und sich keinen Kopf drum gemacht. Wir stellen uns also vor es wären Variablen und sie wären anstatt des #defind durch:
Code:
DWORD Addr_Playerpointer = 0xc62388;
DWORD Addr_Serverpointer = 0xb5d0f;
deklariert. Gleiches kann man auch für die Offsets machen, das erspare ich mir jetzt mal.
Was machen diese Addys überhaupt ?
Diese Adressen sind Speicheradressen im Speicher. Erinnert ihr euch noch an den Anfrang ? Jede Speicheradresse hat einen Wert. In der Adresse 0xc62388 befindet sich also im WarRock Prozess und beinhaltet einen Wert. Nun wird es ein wenig kompliziert.
Der Wert dieser Adresse ist ebenfalls eine Adresse. Man nennt so was Pointer(Zeiger). Also der PlayerPointer befindet sich an der Adresse 0xc62388 im Speicher und hat einen Wert, dieser Wert ist selbst eine Adresse. An dieser Adresse befindet sich die Player-Struktur oder das Playerobjekt eurer WarRock Spielfigur. Gleiches gilt für die Adresse des Serverpointers.
kleiner Exkurs C++ Pointerarithmetik
In C++ werden Pointer oft verwendet und es ist wichtig den Prozess zu verstehen, ein einfaches Beispiel:
Code:
int i=1337;
int *IchZeigeAuf_i = &i;
In dem Beispiel wird als erstes eine Variable mit dem Namen i deklariert, sie hat den Wert 1337. Die Variable hat auch eine Speicheradresse. Die Speicheradresse einer Variavlen kann man in C++ durch das &-Zeichen abfragen. Unter der i-Variablen haben wir einen Pointer deklariert, das erkennt man an dem Sternchen vor dem IchZeigeAuf_i. Anschließend sagen wir dem Pointer, auf welche Adresse er zeigen soll, nämlich die Adresse der Variablen i. Über den Pointer kann man nun auf die den Inhalt der i-Variablen zugreifen.
Code:
*IchZeigeAuf_i = 6;
Damit weisen wir der i-Variablen den Wert 6 zu. Diese einfache Schreibweise macht man sich zu Nutze, um den Speicher von WarRock zu manipulieren.
Der Programmierer des Codes macht dies ebenfalls:
Code:
DWORD *ingame =  (DWORD*)Addr_Playerpointer;
DWORD *outgame =  (DWORD*)Addr_Serverpointer;
Er erstellt 2 Pointer, mit den Namen ingame und outgame, nicht gerade treffende Namen, naja egal. Also die beiden Pointer zeigen auf die Speicheradressen 0xc62388 und 0xb5d0f. Damit die Pointer wissen, wie sie den Inhalt der Adressen, auf die sie zeigen, behandeln müssen, benötigen Pointer ebenfalls einen Datentype und die Adressen müssen auf den Pointer Dword Type gecastet werden.
Um nun an die Werte zu kommen, die in den Adressen gespeichert sind, verwendet man die Pointer wie folgt:
Code:
DWORD InhaltDesPlayerPointers = *ingame;
DWORD InhaltDesServerPointers = *outgame;
So einfach geht das.
Back to the Hack
Gut, dann schauen wir mal weiter den Sourcecode an. Wir sind immer noch in der HackThread() Funktion, bzw. in deren For-Schleife. Wir sehen, dass in einer If-Abfrage der Inhalt der Adressen abgefragt wird, auf die die jeweiligen ingame und outgame Pointer zeigen.
Code:
if(*ingame)
und
Code:
if(*outgame)
Der Programmierer möchte damit erfahren, ob der Benutzer gerade im Hauptmenü des Spieles oder in einem Spiel ist. Man sollte wissen, dass es in C noch keine boolischen Werte (true/false) gab. Man verwendete einfach Zahlen: 0 = falsch und 1 = wahr.
Hinzu kommt, dass jeder Wert, der nicht 0 ist immer für wahr steht. Diese Eigenschaft hat C++ geerbt. Das bedeutet also, wenn einer der beiden Pointer einen Wert zurückgibt, der nicht 0 ist, so wird der Bauch/Rumpf der If-Abfrage ausgeführt.
Ob der ingame Pointer immer dann auf eine Adresse zeigt, deren Wert 0 ist, wenn man gerade nicht im Spiel ist und der outgame Pointer immer dann auf eine Adresse zeigt, deren Wert 0 ist, wenn man im Spiel ist, sei mal dahin gestellt. Ich habe es auch nicht getestet, es scheint aber sehr fehleranfällig.
Nun gut, diese beiden If-Abfragen haben wir hinter uns gelassen. Wenden wir uns der ersten Funktion zu, die ausgeführt wird, wenn der ingame Pointer einen Wert zurückgibt, der nicht 0 ist:
Code:
void PlayerHacks()
{
	DWORD dwPlayerPtr = *(DWORD*)Addr_Playerpointer;
	if(dwPlayerPtr != 0)
	{
		//Super Jump
		{
			if(GetAsyncKeyState(VK_CONTROL) &1)
			{
				*(float*)(dwPlayerPtr + Ofs_Z) = 2000;
			}
		}
		//No Fall Damage
		{
			*(float*)(dwPlayerPtr + Ofs_NoFallDamage) = -20000;
		}
	}
}
Als erstes die PlayerHacks() Funktion. Sie ist vom Type Void, verlangt also keinen Rückgabewert. Sie besitzt auch keine Parameter. Als erste Instruktion in der Funktion sehen wir, wie eine DWORD Variable mit dem Namen dwPlayerPtr erstellt wird. Diese Variable erhält den Inhalt, auf den der Playerpointer zeigt, das ist eine sehr verkürzte Schreibweise. Ich wusste das selber gar nicht, aber es scheint zu funktionieren:
Code:
*(DWORD*)Addr_Playerpointer;
In Addr_Playerpointer befindet sich ja die Adresse des Playerpointers. Dieser Playerpointer beinhaltet die Adresse der Player-Struktur oder des Playerobjektes der Spielfigur im Speicher. Mit dem (DWORD*) cast wird der Pointer erstellt, er hat keinen Namen. Mit dem Sternchen vor der Castinstruktion wird auf den Inhalt der Speicheradresse zugegriffen, auf die der Pointer zeigt, also die Adresse, an der die Player-Struktur/Objekt beginnt.
Ist euch was aufgefallen ? Das ganze ist doppeltgemoppelt. Der Programmierer hat doch bereits den *ingame Pointer erstellt, der auf den Playerpointer zeigt, es wäre wohl sinnvoller den erwähnten Code so zu schreiben:
Code:
DWORD dwPlayerPtr = *ingame;
Ich finde das einleuchtender, nur der Name ingame passt nicht ganz so gut. Wozu wurde der globale Pointer denn erstellt, wenn er nur einmal benutzt wird ? Ist mir nicht schlüssig.

Okay nun geht es weiter. Der Programmierer überprüft, ob der Inhalt der dwPlayerPtr Variablen ungleich 0 ist.
Code:
if(dwPlayerPtr != 0)
Das wäre auch nicht schlimm, wenn er es nicht schon einige Zeilen davor gemacht hätte. In der HackThread() Funktion, erinnert ihr euch an den Code hier ?
Code:
		if(*ingame)
Der macht genau das selbe, solch eine doppelte Überprüfung direkt nacheinander ist eigentlich schwachsinnig und lässt auf mangelnde Programmierkenntnisse oder C&P schließen.
Als nächstes schauen wir uns mal folgenden Codeabschnitt an:
Code:
if(GetAsyncKeyState(VK_CONTROL) &1)
Mit einer If-Abfrage wird überprüft, ob eine bestimmte Taste gedrückt wird. Die Taste wird durch die Konstante VK_CONTROLL definiert, die der GetAsyncKeyState Funktion übergeben wird. Erinnert euch, eine Konstante steht immer für einen konstanten Wert. Ich weiß nicht genau, welche Taste das ist.
Das &1 ist ein wenig komplizierter, ich bin mir auch nicht so ganz sicher. Es legt wohl fest, dass noch eine andere Taste zusätzlich gedrückt werden muss. Dazu sollte man sich mit dem Binärsystem und dessen Gesetzen auskennen:
(Und-Gesetz)
Code:
0 und 0 = 0
1 und 0 = 0
0 und 1 = 0
1 und 1 = 1
Wenn man andere Tasten verwenden möchte, muss man sich die jeweiligen Konstanten raus suchen, bei Google sollten diese leicht zu finden sein. Eine Möglichkeit wäre z.B. folgende:
Code:
if(GetAsyncKeyState(VK_UP))
Die Konstante VK_UP steht repräsentiert hier die Pfeiltaste Oben. Es ist keine weitere Taste erforderlich. Wenn die Pfeiltaste Oben gedrückt wurde, wird der nachfolgende Code im Bauch/Rumpf der Abfrage ausgeführt.
Player Hacks
Der Superjump
Wie funktioniert der Superjump eigentlich ? Das ist ganz einfach. Irgendwo im Speicher sind die Koordinaten der Spielfigur gespeichert. Diese Koordinaten bestehen mindestens aus 3 Werten:
X,Y und Z. Genau wie in einem 3D Koordinatensystem (Vektorrechnung FTW!).
Nun jede Koordinate steht für eine Dimension. Die Z Koordinate gibt an, auf welcher Höhe sich die Spielfigur befindet. Da der Gameserver das nicht überprüft können wir diese Koordinate nach belieben verändern und somit auch die Höhe der Spielfigur verändern, denn genau das macht der Superjump. Die Spielfigur springt nicht, sondern ihre Position in der Höhe wird einfach verändert.
Gut, folgende Pointerverkettung soll den Superjump auslösen:
Code:
*(float*)(dwPlayerPtr + Ofs_Z) = 2000;
Kleiner Exkurs in den Speicher

Ihr wisse ja noch, dass in dwPlayerPtr die Adresse ist, an der die Player-Struktur/Objekt anfängt. Stellen wir uns mal vor die Adresse wäre 0x01.
Dann könnte der Speicher der Player-Struktur ca. so aussehen:

Code:
0x01	0
0x02	0
0x03	K
0x04	R
0x05	U
0x06	S
0x07	T
0x08	Y
0x09	0
0x0A	1
0x0B	3
0x0C	3
0x0D	7
0x0E	0
0x0F	0
Nun, die ausgedachte Player-Struktur beginnt erst mal mit 2 Nullen. Anschließend folgt der Ingamename, daraufhin folgt die Z Position der Spielfigut im Spiel. Durch den Pointer, der auf den Anfang der Player-Struktur zeigt können wir noch nicht erkennen, welchen Namen die Spielfigur hat, oder welche Z-Koordinate sie besitzt. Deshalb addiert sogenannte Offsets. Wenn wir also einen Pointer haben, der auf 0x01 zeigt, wir aber den Namen haben wollen, müssen wir noch 0x02 addieren, um an 0x03 zu gelangen:
Code:
0x01 + 0x02 = 0x03
Ähnlich läuft es im WarRock Prozess ab (natürlich viel mehr Speicher). Die Z-Koordinate befindet sich nicht am Anfang der Player-Struktur, sondern weiter hinten, genau gesagt 0x102D8 Bytes nach ihrem Anfang. Also was machen wir ? Richtig! Wir addieren das Offset zur Adresse, an der die Player-Struktur startet. Der Wert des Offsets wurde vom Programmierer global mit dem #define Makro und dem Namen Ofs_Z definiert.
Gut:
Code:
dwPlayerPtr + Ofs_Z
Addieren wir also das Offset der Z-Koordinate zur Startadresse der Player-Struktur/Objekt. Mit dem *(float*) greift der Programmierer auf den Inhalt der neu entstandenen Adresse zu, die aus der Startadresse der Player-Struktur und dem Offset besteht. Aber warum casten wir auf einen Float-Pointer ?
Float ist ein Datentype, genauso wie Int oder DWORD. Float verwendet ebenfalls 4 Bytes, desshalb kann man diese Datentypen auch so gut hin und her casten. Float kann, im Gegensatz zu den anderen beiden Datentypen, Fließkommazahlen darstellen. Die Koordinaten werden für gewöhnlich immer in float Variablen abgelegt, sie ermöglichen eine genaue Lokalisierung der Spielobjekte im Spiel mit Nachkommastellen.

Der Programmabschnitt
Code:
*(float*)(dwPlayerPtr + Ofs_Z) = 2000;
Ändert also den Wert der Z-Koordinate unserer Spielfigur auf 2000, das ist ziemlich hoch.

NoFallDamage

Kommen wir zum NoFallDamage. Es läuft nach dem gleichen Prinzip ab. Irgendwo im Speicher steht, wie viel Schaden die Spielfigur bekommt. Wenn sie von einem hohen Punkt auf den Boden springt. Um an diese Stelle im Speicher zu gelangen, muss das Offset 0x103A4 zur Startadresse der Player-Struktur/Objekt addiert werden.
Mit:
Code:
*(float*)(dwPlayerPtr + Ofs_NoFallDamage) = -20000;
setzt der Programmierer den Wert dieser Adresse auf -20000, also ein negativer Schaden, der nicht angerechnet wird.
Server Hacks
So, mit den Playerhacks sind wir fertig, nun folgen die Serverhacks. Der Name Serverhack ist auch hier irreführend, da wir keinen Server hacken, geschweige denn etwas am Server ändern. Alle Manipulationen laufen auf unserem Computer ab. Der Programmierer, dessen Code wir einfach kopiert haben ruft in der HackThread() Funktion durch eine If-Abfrage eine weitere Funktion auf:
Code:
if(*outgame)
		{
			ServerHacks();
		}
und zwar die ServerHacks() Funktion, diese sieht wie folgt aus:
Code:
void ServerHacks()
{
	DWORD dwSrvrPtr = *(DWORD*)Addr_Serverpointer;
	if(dwSrvrPtr != 0)
	{		
		//Slot Stuff
		//5 Slot
		{
			*(long*)(dwSrvrPtr + Ofs_5Slot) = 1;
		}
		//6 Slot
		{
			*(long*)(dwSrvrPtr + Ofs_6Slot) = 1;
		}
		//7 Slot
		{
			*(long*)(dwSrvrPtr + Ofs_7Slot) = 1;
		}
		//8 Slot
		{
			*(long*)(dwSrvrPtr + Ofs_8Slot) = 1;
		}
	}
}
Auch der sogenannte ServerPointer scheint auf ein Objekt oder eine Struktur im Speicher zu zeigen, ähnlich wie beim Playerpointer. In dieser Struktur/Objekt ist wohl auch festgelegt, ob der Spieler den 5. bis 8. Slot verwenden darf oder nicht.
Auch hier wird eine DWORD Variable mit dem Namen dwSrvrPtr erstellt, die die Startadresse der Server-Struktur beinhaltet. Als erstes wird diese wieder auf „ungleich null“ überprüft, ebenfalls eine überflüssige Abfrage. Auch hier hätte man wieder den globalen *outgame Pointer verwenden können, dem Programmierer war dies wohl nicht bewusst. Diese Abfrage soll sicherstellen, dass wir uns momentan nicht im Spiel befinden. Unterhalb der If-Abfrage sehen wir mehrere Blöcke, die mit einer geschweiften Klammer eingeleitet und beendet werden, z.B.:
Code:
//5 Slot
		{
			*(long*)(dwSrvrPtr + Ofs_5Slot) = 1;
		}
Man kann diese Blöcke auch weglassen, ich finde sie verwirren eher, als dass sie helfen. Der Aufbau ähnelt dem der Playerhacks nur, dass die Funktionen nicht durch das Drücken von Tasten aktiviert werden. Das Offset eines Slots wird zur Adresse der Server-Struktur/Objekt addiert, somit ergibt sich die Adresse, an der festgelegt ist, ob der Spieler den jeweiligen Slot verwenden darf oder nicht. Anschließend wird der Inhalt dieser Speicheradresse auf 1 gesetzt (wir erinnern uns 1=true(wahr) und 0=false(falsch)). Hier wird der Datententype Long verwendet, dieser Datentype ist 8 Bytes lang. Das heißt, dass einfach von der Slot Speicheradresse an die 8 nachfolgenden Bytes überschrieben werden.
Ich denke die Funktionsweise der anderen Slots sollte klar sein.
Der Teleporter
Der Programmierer des Hacks stellt zusätzlich noch weitere Funktionen zur Verfügung, unter anderem eine Teleport Funktion.
Die Teleport Funktion ähnelt dem Superjump. Wir verändern einfach die Koordinaten der Spielfigur und setzen sie so an einen anderen Punk im Spiel. Dazu benötigen wir die Offsets der jeweiligen X und Y Koordinate, die der Z Koordinate haben wir ja bereits vom Superjump her. Beim Teleportieren erstellt man zwei Funktionen: eine, um einen bestimmten Punkt zu speichern und eine zweite Funktion, um sich später wieder zu diesem Punkt zu teleportieren. Um dies zu verwirklichen, verwendet der Programmierer folgenden Code:
Code:
//Teleport
		{
			if(GetAsyncKeyState(VK_F2)) 
			{
				CoordX = *(float*)(dwPlayerPtr+Ofs_X);
				CoordY = *(float*)(dwPlayerPtr+Ofs_Y);
				CoordZ = *(float*)(dwPlayerPtr+Ofs_Z);
			}
			
if (GetAsyncKeyState(VK_F3))
			{
				*(float*)(dwPlayerPtr + Ofs_X) = CoordX;
				*(float*)(dwPlayerPtr + Ofs_Y) = CoordY;
				*(float*)(dwPlayerPtr + Ofs_Z) = CoordZ;
			}
		}
Der äußerste Block der geschweiften Klammern ist wieder unnötig und kann entfernt werden.
Anschließend folgt eine If-Abfrage, die überprüft, ob die F2 Taste gedrückt wird. Wenn das der Fall ist, dann werden die Koordinaten der Spielfigur aus der Player-Struktur/Objekt ausgelesen, dazu werden wieder die jeweiligen Offsets addiert. Diese Koordinaten werden in den Variablen CoordX,CoordY und CoordZ gespeichert. Diese Variablen müssen noch global als float deklariert werden
Code:
float CoordX,CoordY,CoordZ;
Wenn man in C++ mehrere Variablen des gleichen Datentype deklariert, kann man sie hintereinander schreiben und durch Kommata trennen. Hinzu kommt, dass die einzelnen Offsets noch definiert werden müssen:
Code:
#define Ofs_X 0x00102D4 
#define Ofs_Y 0x00102DC 
#define Ofs_Z 0x00102D8 //gibts ja bereis von Superjump
Oder ohne das #define Makro:
Code:
DWORD Ofs_X = 0x00102D4;
DWORD Ofs_Y = 0x00102DC;
DWORD Ofs_Z = 0x00102D8; //gibts ja bereis von Superjump
Der zweite teil der Teleportinstruktion sollte auch klar sein. Mit der If-Abfrage
Code:
if (GetAsyncKeyState(VK_F3))
wird überprüft, ob die F3 Taste gedrückt wird. Anschließend werden die Koordinaten der Spielfigur auf die Koordinaten gesetzt, die wir in den CoordX, CoordY und CoordZ Variablen gespeichert haben, genau so kennen wir es ja noch aus Superjump Funktion.
Ende
Wie ihr gesehen habt, war der programmierte Code nicht gerade sauber und ordentlich. Jeder sollte sich ab und zu mal einen kleinen Teil bei anderen abschauen, um ein Verständnis zu entwickeln. Jemand anderem die komplette Arbeit zu stehlen und dann zu behaupten es wäre die eigene ist jedoch verantwortungslos und vor allem beschämend, wenn man mit dem Diebesgut nicht umgehen kann.
Mit freundlichen Grüßen Krusty.
krustx is offline  
Thanks
21 Users
Old 01/07/2011, 00:44   #2
 
elite*gold: 0
Join Date: Sep 2010
Posts: 139
Received Thanks: 63
~50Min gebraucht um es durch zu lesen ;D


[Du hast Post!!!]

Bald kommt mein Hack raus :P

B2t: Sehr ausführliche Anleitung / Aufklärung über einen Hack.

Danke
xMusicBeatzzx is offline  
Old 01/07/2011, 07:58   #3
 
elite*gold: 0
Join Date: Feb 2010
Posts: 53
Received Thanks: 8
thx..das ist ein verdammt gutes tutorial.
so etwas habe ich gebraucht.!!!
wasserbett is offline  
Old 01/07/2011, 09:08   #4
 
elite*gold: 0
Join Date: Mar 2010
Posts: 231
Received Thanks: 48
allein wegen der mühe schon ein THX

Sehr nice TuT vlt sticky reif^^

Ich habe ürbings nur 10 min gebraucht bis ich es durch hatte,

#Vote4Sticky!!!
xXGamesty1eXx is offline  
Old 01/07/2011, 23:53   #5
 
elite*gold: 1
Join Date: Mar 2010
Posts: 344
Received Thanks: 520
#vote für sticky
Mirko.aka.Ocki is offline  
Old 01/08/2011, 00:07   #6
 
elite*gold: 0
Join Date: Dec 2010
Posts: 78
Received Thanks: 32
#Vote4Sticky
Ruben™ is offline  
Old 01/08/2011, 00:39   #7
 
sImpleDream's Avatar
 
elite*gold: 7
Join Date: Nov 2009
Posts: 663
Received Thanks: 200
Wenn es dein Werk ist, denke ich sollte das sticked werden. Echt sehr gute Beschreibeung und ich denke soetwas sieht man nicht alle Tage. Klasse
sImpleDream is offline  
Old 01/09/2011, 13:51   #8
 
.Aless™'s Avatar
 
elite*gold: 261
Join Date: Oct 2010
Posts: 632
Received Thanks: 4,473
Ohh mmeiinn Goootttt xD
Ich hätte garnicht soviel Geduld sowas zu schreiben

Hast nen Thanks für die Mühe und nen vote4sticky für das Thread xD
.Aless™ is offline  
Old 01/09/2011, 14:01   #9
 
elite*gold: 0
Join Date: Mar 2009
Posts: 3,963
Received Thanks: 1,584
Echt übelst Hoffentlich finde cih das nirgends auf ner anderen Website...

Lg Algaten™
Algaten™ is offline  
Reply


Similar Threads Similar Threads
Warrock nix verstehen Deutsch Problem...
01/05/2011 - WarRock - 19 Replies
Hey Leute, ich hab n Problem, das ich bis jetzt noch nie hatte, und noch nie davon gehört hab... Beim Updater kann man doch immer einstellen, ob die Ingame-Sprache Englisch, Deutsch oder Türkisch sein soll. :rolleyes: Ich wähl natürlich Deutsch aus. Das Game startet, Tastenkonfiguration und Ingame-Sprache alles auf Englisch... Wenn ich Türkisch einstell hab ich Türkisch, bei Englisch isses Englisch, nur bei Deutsch bleibts dann Englisch...
[Little TuT]Skill_proto verstehen
12/18/2010 - Metin2 PServer Guides & Strategies - 5 Replies
Hey, als ich grad ein Fernninja Skill für Majestic mache und mir aufgefallen ist das es sowas hier noch nicht gibt wollt ich einfach mal ein Thread dazu eröffnen ^^ Hier eine Beispiel : 1 Skillname 1 1 1 0 HP -( 1.1*atk + (0.5*atk + 1.5 * str)*k) 40+100*k 12 -( 1.1*atk + (0.5*atk + 1.5 * str)*k) ATTACK,USE_MELEE_DAMAGE NONE 40+10 0*k 0 0 MELEE 5 1 0 200 1 | Skill-Id Skillname | Skillname 1 | Typ also für wen der Skill ist (1 = Krieger 2 = Ninja 3 =...
[Neues Gewinnspiel von WarRock]Muss man wirklich nur spielen?
10/21/2010 - WarRock - 16 Replies
Es gibts ja eine Neuigkeit(siehe spoiler) Einloggen und GEWINNEN! Posted By War Rock Game Team | 20.10.2010 Achtung Soldaten! Playspan und GamersFirst haben sich nochmals zusammengetan um Dir eine ultimative neue Promo-Aktion zu bieten! Ab heute bis 10. November, erhalte die Chance, tolle Preise zu gewinnen! Diese Preise können sein: Ultimate Points, G1 Credits, AW50F, XM8, Barrett M82N, PSG-1 20B, Glock 17C, oder die Bizon für 30 Tage. Die Gewinner werden via E-Email bekanntgegenen...



All times are GMT +1. The time now is 10:35.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.