Home of Gamehacking - Archiv
Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - Druckversion

+- Home of Gamehacking - Archiv (http://archiv-homeofgamehacking.de)
+-- Forum: Gamehacking (http://archiv-homeofgamehacking.de/forumdisplay.php?fid=3)
+--- Forum: Gamehacking (http://archiv-homeofgamehacking.de/forumdisplay.php?fid=6)
+--- Thema: Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? (/showthread.php?tid=2729)



Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - b4d-b0y - 07.03.2015

Hallo Leute, ich brauche eure Hilfe.
Versuche nun schon seit einer Woche an die im Betreff genannten Informationen zu kommen. Als Spiel verwende ich momentan "Assault Cube".

Ich habe bereits meine "Baseadress" gefunden mit Pointern und Offsets und kann somit auf die Daten meines Spielers zugreifen.

Dazu habe ich auch die "BaseAdress" des ersten Gegners und verfüge genauso über all seine Daten.

Ich möchte in C++ mittels einer Schleife (wie den sonst) aber alle "PlayerBaseAdressen" abfragen bzw. die Daten jeden Spielers zur Verfügung haben.
Die Anzahl der Spieler kann ich durch eine Adresse problemlos abfragen.

Das Problem: Ich kann die richtige Größe der Spieler-Liste/-Array nicht erkennen. Diese ändern sich bei jedem Neustart des Spiels.
D.h. ich kann zu meiner "Baseadress" nicht einfach den Abstand der Bytes hinzuaddieren, die zuletzt, noch vor dem Neustart, aktuell waren.

Wenn jetzt nicht nur zwei Spieler (Ich & ein Gegner) im Spiel sind, sondern zum Bsp. 32, dann ist die BaseAdresse des "ersten Gegners" nicht die erste, somit weiß ich nicht wo ich anfangen soll.

Frage an euch: wie würdet ihr vorgehen? Was empfehlt ihr mir noch zu versuchen?

Nachtrag:
Wenn ich zum Beispiel einen Breakpoint auf die "decrease health" Funktion setze mit "find out what address this code writes to", dann bekomme ich (nach und nach) alle Health-Adressen der Gegener (auch meine). Das Offset für Health ist "0xf8" wenn ich diesen von jeder Adresse abziehe habe ich somit alle PlayerBaseAdressen.

Das Problem ist es aber das ganze in C++ zu realisieren. Ich weiss nicht wie und ob sowas überhaupt möglich ist. Ich muss durch C++ quasi in das register eines "fremden" Processes eingreifen. Sowas wäre vielleicht noch möglich wenn ich einen Debugger in mein Code einbaue, das wäre aber keine gute Lösung für das Problem.
(Durch den Debuggereinsatz kommen dann, vom Spiel zu Spiel unterschiedlich, nur noch mehr Probleme, die umgangen werden müssen).

Nachtrag 2:
Habe folgendes noch herausgefunden:
Die ersten (1-4) Adressen und die letzten (1-4) Adressen haben immer einen anderen Abstand in Bytes von einander. Aber die mittleren haben immer 430 Bytes.

Nachtrag 3:
Wenn jemand Tutorials in irgendeiner Form kennt, die dieses Thema behandeln dann bitte her damit. Ich finde leider keine.

Nachtrag 4:
Vermutlich habe ich den Abstand falsch gerechnet, ich sollte den Abstand in Bytes vom Pointer (der auf die eine PlayerBase zeigt) zu nächsten Pointer nehmen und nicht den Abstand von PlayerBase zu PlayerBase. Ah und die 430 Bytes stimmen auch nicht immer, ab und zu sind es auch 448 Bytes und manchmal ganz durcheinander.
Irgendwo muss es doch mindestens einen Bereich mit Pointern geben, wo diese mehr oder weniger ordentlich mit gleichmäßigem Abstand zu einander zu sehen sind. ??
So einen Bereich kann ich nicht finden, vor allem finde ich keine Forenbeiträge (auf anderen Foren) mit selben oder ähnlichen Fragen, als wäre das was ich tun möchte für alle einfach und selbstverständlich nur nicht für mich.


RE: Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - Acubra - 08.03.2015

Hey,
wenn es soetwas wie eine Entity-Liste gibt dann muss es einen Speicherbereich mit den ganzen Pointern zu den jeweiligen Adressen der Spieler geben. Wie du schon richtig im Nachtrag 4 gesagt hast, müsstest du dann zum ersten Pointer (der auf die BaseAdresse des ersten Spielers zeigt) höchstwahrscheinlich 0x4*i hinzuaddieren um den Pointer des Spielers mit dem Index "i" zu erhalten. 0x4 musst du hinzuaddieren, da ja ein Pointer (DWORD) 4 bytes groß ist. Die 0x4 können aber von Spiel zu Spiel auch unterschiedlich sein, je nachdem ob der Pointer noch mit anderen Informationen in einer Struktur steht oder nicht.
Zu deinem ersten Nachtrag: Du solltest nicht gucken was in die Adresse schreibt (writes), sondern was auf sie zugreift (accesses), damit du die Adressen nicht erst hast wenn dem Gegner HP abgezogen wurde. Das in C++ ist über eine DLL Injektion sehr einfach zu realisieren. Du überschreibt des Befehl der die HP abzieht mit einem Sprung (Jump) zu deiner eigenen Funktion. Dort steht bei dir folgender (pseudo) code:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void GetAddys()
{
	DWORD dwBase = NULL;
	__asm
	{
		pushad //save registers
			pushfd //save flags
			mov dwBase, [eax] //jenachdem wie dein decrease befehl ist musst du evtl. das register anpassen
	}
	//struct definieren wäre wahrscheinlich klüger
	float fHp = (float)dwBase + 0xf8;

	if (dwBase != NULL && fHp < 10000 && fHp > 0)
	{
		//code
	}
	__asm
	{
		popfd 
			popad 
			jmp backToOrignalCode 
	}
}

Dafür braucht man noch lange keinen Debugger.

PS: Habe gelesen das der Sourcecode des Spiels frei verfügbar ist? Eventuell wäre der Spielcode einen Blick wert.
//EDiT: Da haben wir es doch schon: https://github.com/assaultcube/AC/blob/d5763d9f5b29a2e52ba41e888a6be02570cbf54c/source/src/clientgame.cpp

Code:
1
2
3
4
5
6
7
8
9
10
playerent *getclient(int cn) // ensure valid entity
{
if(cn == player1->clientnum) return player1;
return players.inrange(cn) ? players[cn] : NULL;
}
void initclient()
{
newname("unarmed");
player1->team = TEAM_SPECT;
}




RE: Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - Acubra - 08.03.2015

Hey,
habe die EntityListe und maxPlayers gefunden. Im Spoiler der Code:




RE: Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - b4d-b0y - 08.03.2015

Vielen Dank für die Hilfe, das bringt mich auf jeden Fall weiter. Habe leider erst in ein paar Tagen wieder Zeit mich damit weiter zu befassen.

Bei diesen "Methoden" gibt es aber einige Nachteile, könnte man vielleicht noch irgendwie anders vorgehen? Weil mich sowas generell interessiert, nicht unbedingt nur auf dieses Spiel bezogen.

- Das mit dem offenen Quellcode passt natürlich perfekt. Leider ist es bei den meisten Spielen nicht so.

- Deine erst beschriebene Methode mit dem Pseudocode: könnte man das irgendwie ähnlich aufbauen, aber ohne direkt den Assembler Code an der Stelle zu manipulieren? Es geht mir mehr ums Auslesen der Spielerdaten und das sollte möglichst unentdeckt sein. Bei den meisten Spielen wird es möglicherweise kein Problem darstellen, bei einigen aber wird das als Cheat erkannt. Bei online Spielen wirds sowieso erkannt, was hier aber eigentlich ir­re­le­vant ist, da es nicht meine Absicht ist. Also kann man die Adressen aus dem Register auch anders auslesen, ohne sich in den Codeverlauf einzumischen?


RE: Finden der Player-/Entity-Liste bzw. die Baseadresse von jedem Gegner ? - Acubra - 08.03.2015

Hey,
das nicht alle Spiele Opensource sind ist erschwert natürlich den Prozess. Assault Cube ist deswegen auch echt gut zum Lernen. Wenn du den Sourcecode des Spiels nicht hast, dann musst du es wohl oder übel "reversen". Das heißt mithilfe eines Debuggers den ASM Code des Spiels nachvollziehen und interpretieren.
Ich weiß jetzt nicht was du mit anders vorgehen meinst. Im Prinzip ist es bei jedem Spiel das Gleiche. Irgendwo steht was du wissen willst und den Ort musst du finden. Wie du den Ort findest, dafür gibt es keine Allround-Lösung und das hat sehr viel mit Erfahrung und Trial & Error zu tun. Es gibt auch oft viele verschiedene Ansätze für das gleiche Problem.

Zu dem Pseudocode. Wenn du die Register an der Stelle auslesen willst (von deinem Programm aus), dann musst du in der Tat einen Debugger attachen--> Breakpoint an der Stelle setzen--> Register auslesen--> Breakpoint entfernen. Das ist schon ziemlich kompliziert.
Wenn es dir nur ums Auslesen geht, dann musst du eigentlich immer die EntityListe oder den ObjectManager oder was auch immer finden. Das sind dann eben die PointerArrays, für die jeweiligen Objekte. Über ReadProcessMemory lässt sich dann ganz einfach extern alles auslesen, oder du greifst intern über eine .dll direkt auf den Speicher zu.
//EDiT: Hab mich nochmal mit ReClass kurz rangesetzt. So ist es meiner Meinung nach am Einfachsten auf die Player zuzugreifen wenn man keine SDK hat.
Du definierst zwei Klassen, die EntityListe und die Playerklasse:
[code=C]
class cEntityList;
class cPlayer;

class cEntityList
{
public:
cPlayer** m_ppEntities; //0x0000
char _0x0004[4];
__int32 m_iMaxPlayers; //0x0008
char _0x000C[52];

};//Size=0x0040

class cPlayer
{
public:
char _0x0000[248];
__int32 m_iHealth; //0x00F8
char _0x00FC[836];

};//Size=0x0440
[/code]
Und jetzt kannst du sehr einfach und elegant auf alle Member (Player) zugreifen:
[code=C]
cEntityList *pEntityList = (cEntityList *)(0x0050F4F8);
for (int i = 0; i < pEntityList->m_iMaxPlayers - 1;i++)
{
cPlayer *pCurrentPlayer = NULL;
pCurrentPlayer = pEntityList->m_ppEntities[i];
if (pCurrentPlayer != NULL)
{
printf("PlayerIndex: %i - BaseAddress :%x - Health :%i\n", i, pCurrentPlayer, pCurrentPlayer->m_iHealth);
}
}
[/code]