Positions-Struktur auftreiben
-
Hallo C++ - Community,
nach nun gefühlten 4 Wochen und realen 2 Wochen Sucherei wende ich mich jetzt doch ziemlich frustriert an euch.
Ich suche in meinem Spiel zur Zeit die Strukturen für die Spielerpositionen.
Ich kann in meinem Spiel 'status' eingeben und es wird ausgegeben, auf welcher Position ich mich auf der auf der Map befinde.Diese Position (als Beispiel) X: 1002. Dann gebe ich diesen Wert in CheatEngine ein und suche nach einem Floatwert. Ausgegeben werden mir eine Menge Werte, die sich alle verändern, wenn ich mich bewege.
Ich hab nun viele Adressen, die ich irgendwie in IDA versuchen will zu finden.
Nur leider sind diese weder in Game.dll, engine.dll, noch client.dll auf!
Es gibt irgendwas mit Modulbasen berechnen? Also ich habe z.B.
Imagebase : 42000000
Was kann ich damit jetzt machen? Habt ihr Ideen. Ich bitte darum!
-
Prinzipiell waere ein moegliches Vorgehen, on access breakpoints auf die ermittelten Adressen zu legen und zu schauen, wo darauf zugegriffen wird. Vielleicht findest du dabei ja eine Stelle, die dich interessiert.
Ich kann dir aber gleich sagen: Einfach wird das nicht. OOP sei dank stecken die engines voll Massen an dynamischen Strukuren, die selbst waehrend das Spiel laeuft sich aendernde Adressen und eine variable Anzahl an Kopien haben koennen. Durch diesen Wust kannst du nur mit viel Erfahrung durchsteigen...
-
ich rate dir zur lösung deines problems das Cheat Engine forum zu besuchen, cheat engine bietet dir die funktion pointer zu suchen. Mein vor-schreiber hat recht mit den x kopien der dynamischen objekte, jedoch hat jedes objekt ürgentwo eine statische basis so das du vom Wert aus eine statische basis ermitteln musst. Das geht hauptsächlich übers lesen / auswerten von assembler code oder die funktion Pointer suchen von CE.
Für genauere anleitungen hierzu siehe das CE-Forum.
-
Es gibt irgendwas mit Modulbasen berechnen? Also ich habe z.B.
Imagebase : 42000000
mal ein beispiel:
#include <iostream> using namespace std; class Coords{ public: Coords(int x, int y ){ this->x = x; this->y = y; } const int * getX() const { return &x; } const int * getY() const { return &y; } private: int x;// Gesuchter wert int y; }; class World{ // Beispiel Klasse }; class Player{ public: Player(){ C = new Coords(100,200); } ~Player(){ delete C; } Coords * getC() const { return C; } private: Coords * C; }; class Game{ public: Game(){ P = new Player(); W = new World(); } ~Game(){ delete P; delete W; } Player * getP() const { return P; } private: Player * P; World * W; }; int main() { Game * G = new Game();// &G ist die Statische Basis cout << "Static Base: " << hex << &G << " !! Dieser Wert aendert sich nicht !!" << endl; cout << "Static Base Value: " << hex << G << endl; // Ermittlung des Werts über Offsets! unsigned GtoP = ((unsigned)G->getP()) - (unsigned)G; unsigned PtoC = (unsigned)(G->getP())->getC() - (unsigned)G->getP(); unsigned CtoX = (unsigned)((G->getP())->getC()->getX()) - (unsigned)(G->getP())->getC(); unsigned CtoY = (unsigned)((G->getP())->getC()->getY()) - (unsigned)(G->getP())->getC(); cout << "Offset von Game zu Player: " << hex << GtoP << " Game : " << G << " Player " << G->getP() << endl; cout << "Offset von Player zu Coords: " << hex << PtoC << endl; cout << "Offset von Coords zu X: " << hex << CtoX << endl; cout << "Offset von Coords zu Y: " << hex << CtoY << endl; cout << "Player:" << endl; cout << "\tReal: " << hex << G->getP() << endl; cout << "\tBy Offset: " << hex << (unsigned)G + GtoP <<endl; cout << "Coords:" << endl; cout << "\tReal: " << hex << (G->getP())->getC() << endl; cout << "\tBy Offset: " << hex << (((unsigned)G + GtoP) + PtoC) << endl; cout << "X:" << endl; cout << "\tReal: " << hex << ((G->getP())->getC())->getX() << endl; cout << "\tBy Offset: " << hex << (((unsigned)G + GtoP) + PtoC) + CtoX << endl; cout << "Value of X:" << endl; cout << "\tReal: " << dec << *(((G->getP())->getC())->getX()) << endl; cout << "\tBy Offset: " << dec << *(int*)((((unsigned)G + GtoP) + PtoC) + CtoX) << endl; return 0; }
warum ist die adresse von Coords und X jetzt gleich?
weil die information der klassen nur im compiller gespeichert wird. alle verweise der klassen werden über offsets im programmcode festgehalten.
also wird die information wo die klasse XY beginnt einfach wegreduziert und nur noch gespeichert wo die erste variable beginnt ( Coords * ) und dann das Offset zu Jeder weiteren ( Coords * + 4 = Y )
-
Hey,
vielen Dank, ich denke das kann mir helfen. Ich habe jetzt auch wieder die Zeit daran weiter zu arbeiten.
Ich habe mich auch bei Cheat Engine angemeldet. Mal schauen, ob ich da weiterkomme.
Hab ich die Möglichkeit dich irgendwie schneller zu erreichen, als über dieses Forum? Ich habe wohl noch ein paar Verständnisfragen. Mir geht es hier weniger um das Endprodukt sondern um erlangtes Wissen.
-
Eigentlich, nein, ich bin ungefär 1x am tag wenn es gut kommt im forum, und dann eher von der arbeit aus.
Wichtig ist das du in diesem Gebiet die gängingen Grundlagen beherscht.
Zum Beispiel : Offset = Addr - Basis;
ich empfehle erst C zu verstehen und dann wenn du dir sicher bist das du das prinzip der pointer ( http://de.wikipedia.org/wiki/Zeiger_(Informatik) ) verinnerlicht hast dich assembler zu nähern. Zusätzlich solltest du OOP beherschen um es in Assembler erkennen und verstehen zu können.
So gibt es im gegensatz zu C in OOP ( C++ ) codestellen die mehrfach aufgerufen werden aber mit anderen Objektreferenzen.
Sprich viele Objekte greifen auf eine Codestelle zu, unterscheiden sich aber dann durch einen Parameter der auf das Objekt verweist. ( This-Zeiger http://en.wikipedia.org/wiki/This_(computer_science) )
Die konkrete Umsetzung variiert dann noch von Compiller zu Compiller. Dazu empfehle ich Lenas Tutourials ( Tuts4You )
Dein konkretes spiel zu knacken wird dir am anfang nur schwer gelingen, du solltest vielleicht etwas niedriger ansiedeln, das ganze hat viel mit cracken ( den code verstehen und umsetzen ) zu tun desshalb helfen auch oft die tutourials dieser szene.
-
Ich beherrsche ja C++.
Ich verstehe soweit alles, aber ich habe ein wenig Angst vor Assembler, da es doch ziemlich cryptisch in meinen Augen ist und ich nicht weiß, wie ich solche Structs in dem Code verstehen soll.
-
die umsetzung der struct / class konstrukte ist teilweise sehr direkt, was verwirren kann sind die VMT's ( http://en.wikipedia.org/wiki/Virtual_method_table ) ab diesem punkt musst du die struktur der OOP programmierung innehaben.
ein einfaches beispiel für die umsetzung eines structs :
struct myS{ int x; int y; int z; }; int main(int argc, char* argv[]) { myS S; S.x = 4; S.y = 8; S.z = 12; return 0; }
würde in assembler ungefär so aussehen:
push ebp mov ebp, 0x22f112 mov [ebp], 0x4 mov [ebp+0x4], 0x8 mov [ebp+0x8], 0xC
natürlich ist das ein reines beispiel. Und die realität differenziert wiedereinmal vom Beispiel, in dem Quellcode befindet sich das Objekt im Stack. das heißt der Compiller würde die Basisadresse des Objekts wohl über den Adressen der Variablen bestimmen. Um genau zu sehen wie dein Compiller es umsetzt öffne doch einfach mal das CPU Fenster während du den Quellcode debuggst.
-
myS S;
geht so nicht
struct myS { int x; int y; int z; }; int main(int argc, char* argv[]) { struct myS S; S.x = 4; S.y = 8; S.z = 12; return 0; }
00401318 push ebp 00401319 mov ebp,esp 0040131B and esp,0xfffffff0 0040131E sub esp,0x10 00401321 call 0x401740 <__main> 00401326 mov DWORD PTR [esp+0x4],0x4 0040132E mov DWORD PTR [esp+0x8],0x8 00401336 mov DWORD PTR [esp+0xc],0xc 0040133E mov eax,0x0 00401343 leave 00401344 ret
-
[quote="Erhard Henkes"]
myS S;
geht so nicht
myS S;
Wird durchaus von so manchem Compiller zugelassen, auch wenn es syntax technisch nicht astreich ist.
akzeptiert
habe in meinem ansatz einiges ausgelassen, aber ich denke der ansatz kam rüber.
0040131B and esp,0xfffffff0 0040131E sub esp,0x10
ausmaskieren halte ich für einsteiger noch zu kompliziert.
hier ein funktionierender ansatz mit kommentaren:
push ebp // erniedrigen des stack pointers um 4 ( stack wächst nach unten ), sichern des base pointers auf dem stack mov ebp,esp // derzeitige stack adresse in ebp speichern add esp, -0x0c //Stack pointer um C erniedrigen ( es bleiben C Bytes frei zum arbeiten ), C Bytes auf dem Stack reservieren mov [ebp-0x0c],0x04 // X mit 4 belegen mov [ebp-0x08],0x08 // Y mit 8 belegen mov [ebp-0x04],0x0c // Z mit 12 belegen mov esp,ebp // alten stack pointer wiederherstellen. Lokale Variablen verwerfen ( freigeben ) pop ebp // gesicherten base pointer wiederherstellen xor eax,eax // selbe wie mov eax,0 .. setzt den rückgabewert der funktion auf 0 ret