Pointer verfälschen



  • Mitlesender schrieb:

    volkard schrieb:

    ...
        *((int(**)())&12[buf])=&function_two;
        ...
    }
    

    Wie darf man das mit &12[buf] verstehen?

    http://de.wikipedia.org/wiki/Nonsens



  • Ey, psst. Brauchst du gefälsches Pointer? Kommst du heute Nacht in Park. Bring ich billiges Pointer mit.



  • Mitlesender schrieb:

    volkard schrieb:

    ...
        *((int(**)())&12[buf])=&function_two;
        ...
    }
    

    Wie darf man das mit &12[buf] verstehen?

    Ein Scherzchen. 🤡

    12[buf] == *(12+buf) == *(buf+12) == buf[12]
    


  • Meine Frage war ernst gemeint!! Ich kriege es leider nicht hin, einfach mal "pointer" mit der Adresse der anderen Funktion durch einen Bufferoverflow zu überschreiben.



  • freakC++ schrieb:

    Meine Frage war ernst gemeint!! Ich kriege es leider nicht hin, einfach mal "pointer" mit der Adresse der anderen Funktion durch einen Bufferoverflow zu überschreiben.

    Mein Code läuft bei mir und erzeugt die Ausgabe 2.
    Allerdings nur im Debug-Modus.

    Im Release-Modus klappt er nicht. Vielleicht ist die Funktion da inline-expandiert.



  • mmhh...vielleicht liegt da auch der Fehler bei mir. Ich stell mal alle Optimierungen aus.



  • welchen Compiler verwendest Du und wie rufst Du ihn auf?



  • freakC++ schrieb:

    welchen Compiler verwendest Du und wie rufst Du ihn auf?

    unter windows den gcc, der bei mingw dabei war.
    -g -Wall -std=c++11 -fexceptions



  • schad...bei mir wird auch mit gcc sets 1 ausgeben. HAt jemand ne Idee?



  • freakC++ schrieb:

    schad...bei mir wird auch mit gcc sets 1 ausgeben. HAt jemand ne Idee?

    Schau mal den assemblercode an.
    (Mit -save-temps compilieren, dann taucht die Datei auf.)
    Lass die beiden Funktionen sonderliche Zahlen returnen wie 4711 und 0815 (/*haha, einer meiner Lieblingswitze*/), damit man die magic numbers besser im Assembler-Code findet.



  • Der Compiler von ideone(C++11) legt mir den Funktionszeiger immer 'unten' auf den Stack, unabhängig von der Reihenfolge der Deklarationen (erst buf[] oder erst pointer ist egal), so daß ein Überlauf von buf ihn nicht erreichen kann. (Sicherheitsfeature?)
    Wenn man buf[-4] nimmt funktioniert es nur, wenn man den manipulierten pointer vor Benutzung einmal ausliest (bspw. cout << (void*) pointer; ). Der liegt da wohl schon in einem Register. Ich hatte für die Tests übrigens aus buf[12] ein buf[16] gemacht. Keine Ahnung, ob das nötig war. EDIT: da es sich wohl um einen 32-Bit-Compiler handelt, dürfte das hier keine Bedeutung haben.



  • aufklär0r schrieb:

    http://de.wikipedia.org/wiki/Nonsens

    http://de.wiktionary.org/wiki/Kommutativität* (nur für skalare Typen natürlich.)

    Im Release-Modus klappt er nicht. Vielleicht ist die Funktion da inline-expandiert.

    Edit³: Versteh jetzt erst den Trick 😃





  • Ich habs: Der Stack wächst nach unten.

    Das liegt wohl an der GCC-ABI.

    volkard schrieb:

    freakC++ schrieb:

    schad...bei mir wird auch mit gcc sets 1 ausgeben. HAt jemand ne Idee?

    Schau mal den assemblercode an.
    (Mit -save-temps compilieren, dann taucht die Datei auf.)
    Lass die beiden Funktionen sonderliche Zahlen returnen wie 4711 und 0815 (/*haha, einer meiner Lieblingswitze*/), damit man die magic numbers besser im Assembler-Code findet.

    Ich hab den Assembler-Code nicht angeschaut, aber wahrscheinlich wolltest du genau darauf hinaus, oder?



  • Und die Lösung lautet:

    int main()
    {
        char buf[12];
        int (*pointer)();
    
        pointer = function_one;
    
        std::cout << &buf << &pointer << '\n';
    
        *((int(**)())&buf[-sizeof(pointer)]) = function_two;
    
        std::cout << pointer();
    }
    

    Edit²: Wtf? Es klappt nur, wenn man die Adressen nimmt und ausgibt. Auch volatile gilt nicht (as-if)!



  • Sone schrieb:

    Wtf?

    Wir bewegen uns außerhalb des Standards.
    Siehe "nasal demons".
    Da muss man halt fummeln uns ausprobieren. Und die nächste Compilerversion macht es ganz anders.

    edit: Bitte die demnächst vollständige main.cpp posten, damit man leichter damit experimentieren kann.



  • Caligulaminus schrieb:

    Der Compiler von ideone(C++11) legt mir den Funktionszeiger immer 'unten' auf den Stack, unabhängig von der Reihenfolge der Deklarationen (erst buf[] oder erst pointer ist egal), so daß ein Überlauf von buf ihn nicht erreichen kann. (Sicherheitsfeature?)

    Kann ich mir nicht vorstellen, da der Compiler ja nicht in die Zukunft schauen kann. Was macht er denn, wenn noch n bissl Code dazwischen steht? Oder ist das libsafe?

    Sone schrieb:

    Und die Lösung lautet:

    Cool danke! Klappt bei mir ohne die Ausgabe der Adressen. Ich schau mir aber morgen auch erst noch einmal den Assemblercode an 🙂

    Viele Grüße
    freakC++



  • freakC++ schrieb:

    Was macht er denn, wenn noch n bissl Code dazwischen steht?

    Das hat damit nichts zu tun. Es geht um die lokalen Variablen auf dem Stack.



  • Also bei mir geht

    int main(void) { 
    
        char buf[12]; 
        int (*pointer)(void); 
    
        pointer = function_one; 
        sprintf(buf,"1234567890ab\x10\x10\x40\x00");
        std::cout << pointer(); 
    
        return 0; 
    }
    

    Bei Visual Studio und

    - Puffersicherheitsüberprüfung deaktivert
    - Funktionslevellinking deaktiviert
    - Optimierungen deaktiviert
    - Zufällige Basisadresse (ASLR) deaktiviert

    Der Compiler von ideone(C++11) legt mir den Funktionszeiger immer 'unten' auf den Stack, unabhängig von der Reihenfolge der Deklarationen (erst buf[] oder erst pointer ist egal), so daß ein Überlauf von buf ihn nicht erreichen kann. (Sicherheitsfeature?)

    Ja das ist ein Sicherheitsfeature dass manche Compiler Arrays immer so angelegt werden dass keine Pointer oder andere lokale Variablen überschrieben werden können.



  • Caligulaminus schrieb:

    Das hat damit nichts zu tun. Es geht um die lokalen Variablen auf dem Stack.

    Vielleicht vertehe ich dich falsch, aber stell dir vor, dass ganz oben auf dem Stack ein Pointer liegt. Jetzt im Nachhinein will ich irgendeinen Buffer drauflegen. Die Reihenfolge kann nur geändert werden, wenn bereits zur Compilierzeit bekannt ist, welche Pointer und überlauffähigen Konstrukte es geben wird. Sonst müsste der Compiler zur Laufzeit den Pointer erst wieder vom Stack runternehmen, dann den Buffer drauflegen und erneut den Zeiger pushen. Das bezweifel ich.

    Sone schrieb:

    Ich habs: Der Stack wächst nach unten.

    Wie rum man den Stack betrachtet, ist eigentlich egal. In meinem Kopf wächst er immer nach oben. Hauptsache deine Vorstellung ist konsistent. Wenn Du vom Stack also subtrahierst, wächst er noch weiter nach oben bzw. bei dir nach unten.

    Sone schrieb:

    Und die Lösung lautet:

    //...
    
        *((int(**)())&buf[-sizeof(pointer)]) = function_two;
    //...
    

    Ehrlich gesagt, habe ich noch ein bisschen Schwierigkeiten mit diesem Ausdruck. Warum brauce ich den Dopelzeiger?

    Vielen Dank für eure Hilfe 🙂
    LG, freakC++


Anmelden zum Antworten