Was bedeutet ((void (*) ()) buf) (); bedeuten?

59

Ich löse eine binäre Exploitation-Herausforderung auf picoCTF und bin auf diesen Code gestoßen:

((void (*)())buf)();

Wo bufist ein Zeichenarray?

Ich habe die Herausforderung gelöst, kann aber nicht verstehen, was genau es tut. Ich habe mir diesen Thread angesehen, konnte ihn aber nicht erkennen.

Was heißt ((void (*)())buf)();das

sh.3.ll
quelle
14
Was heißt ((void (*)())buf)();das Es bedeutet, dass der Autor nicht versteht typedef. typedef void (*voidFuncPtrType)();würde diesen Code klar machen.
Andrew Henle
33
@AndrewHenle Bei der Gestaltung von CTF-Herausforderungen ist Klarheit nicht das oberste Ziel, und im Rahmen der Herausforderung ist sogar eine gewisse Verschleierung zu erwarten. Höchstwahrscheinlich war sich der Autor bewusst, dass dies nicht die am besten lesbare Art ist, Dinge zu tun.
ManfP
2
Es bedeutet, dass Ihr Programm UB hat.
R .. GitHub STOP HELPING ICE
4
Dies bedeutet, dass die Deklarationsregel vom Typ "Spirale" von C viel zu kompliziert ist. Es gibt einen Grund, warum praktisch jede andere statisch typisierte Sprache, die nicht direkt von C abstammt, stattdessen Regeln von links nach rechts verwendet.
Mason Wheeler
2
@ MasonWheeler "Spiral" ist ein urbaner Mythos. Die Deklaration ist so viel oder so wenig "Spirale" wie der entsprechende Ausdruck wäre. Operatoren werden einfach in der Rangfolge und von links nach rechts angewendet (was Ihnen hier natürlich nichts Neues sagt): "Ich muss sie dereferenzieren und dann aufrufen, und das Ergebnis hat den Typ void": voila, Zeiger auf die Funktion void .
Peter - Monica

Antworten:

129

void (*)() ist ein Typ, wobei der Typ "Zeiger auf eine Funktion ist, die unbestimmte Argumente akzeptiert und keinen Wert zurückgibt".

(void (*)()) ist eine Typumwandlung zum obigen Typ.

(void (*)())bufwirft bufauf den oben genannten Typ.

((void (*)())buf)() ruft die Funktion auf (ohne Argumente).

Kurz gesagt: Er weist den Compiler an, bufals Zeiger auf eine Funktion zu behandeln und diese Funktion aufzurufen.

Ein Programmierer
quelle
15
Ich finde das cdeclDienstprogramm (oder die Website ) hilfreich, um die komplexeren C-Ausdrücke ins Englische zu übersetzen.
bta
3
@bta cdecl ist hier nicht nützlich, da die Syntax keine Deklaration ist. Es ist ein Funktionsaufruf über eine Besetzung eines zuvor deklarierten Symbols
Bolov
3
@bolov - Auf der gesamten Aussage, nein, aber es tut dem erklärt komplexeste Teil davon. Von dort aus ist das Decodieren des Restes ziemlich einfach.
Bis zum
5
@AvD Wenn sich irgendwo bufoder copyan einer ausführbaren Adresse befindet und der Code selbst positionsunabhängig ist, funktioniert dies. Es ist natürlich so nicht portabel wie es nur geht, aber dies sollte in vielen Bare-Metal-Umgebungen sowie in älteren x86-Betriebssystemen funktionieren, in denen das No-Execute-Bit (NX) für Stack und Heap nicht gesetzt ist.
Wrtlprnft
4
@ AvD: Es wird nicht unbedingt abstürzen. Sofern der Datenbereich nicht vor Ausführung geschützt ist (was von der Architektur und der Laufzeitumgebung abhängt), können Sie mit diesem Trick eine Funktion zur Laufzeit in ein Array kompilieren und im laufenden Betrieb aufrufen. Ich habe diesen Trick vor 35 Jahren zum ersten Mal auf einem DEC Vax verwendet, um Turing-Maschinen für ein fehlgeschlagenes Experiment in der Turing-Maschinen-Evolution zu kompilieren.
TonyK
11

Der Zeiger bufwird unter Verwendung einer nicht spezifizierten Anzahl von Parametern in die Zeigerfunktion für ungültig konvertiert und dann dereferenziert (dh die aufgerufene Funktion).

P__J__
quelle
9

Es ist eine Typumwandlung, gefolgt von einem Funktionsaufruf. Zunächst bufwird auf den Zeiger auf eine Funktion umgewandelt, die zurückgibt void. Das letzte Klammerpaar bedeutet, dass die Funktion dann aufgerufen wird.

lukeg
quelle
7

Es wandelt das Zeichenarray in einen Zeiger auf eine Funktion um, die keine Argumente akzeptiert und zurückgibt void, und ruft es dann auf. Eine Dereferenzierung des Zeigers ist aufgrund der Funktionsweise von Funktionszeigern nicht erforderlich.

Eine Erklärung:

Dieses "Zeichenarray" ist eigentlich ein Array von Maschinencode. Wenn Sie das Array in a void (*)()umwandeln und es aufrufen, wird der Maschinencode innerhalb des Arrays ausgeführt. Wenn Sie den Inhalt des Arrays bereitstellen würden, könnte ich es für Sie zerlegen und Ihnen sagen, was es tut.

SS Anne
quelle