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
    

Anmelden zum Antworten