Que fait ((void (*) ()) buf) (); signifier?

59

Je suis en train de résoudre un défi d'exploitation binaire sur picoCTF et suis tombé sur ce morceau de code:

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

bufest un tableau de caractères.

J'ai résolu le défi, mais je n'arrive pas à comprendre ce qu'il fait exactement. J'ai regardé ce fil mais je n'ai pas pu le comprendre.

Que veut ((void (*)())buf)();dire?

sh.3.ll
la source
14
Que veut ((void (*)())buf)();dire? Cela signifie que l'auteur ne comprend pas typedef. typedef void (*voidFuncPtrType)();rendrait ce code clair.
Andrew Henle
33
@AndrewHenle dans la conception des défis de la FCE, la clarté n'est pas vraiment l'objectif principal, et une certaine obscurcissement peut même être attendue dans le cadre du défi. Plus vraisemblablement qu'autrement, l'auteur savait que ce n'était pas la façon la plus lisible de faire les choses.
ManfP
2
Cela signifie que votre programme a UB.
R .. GitHub STOP STOPINGING ICE
4
Cela signifie que la règle de déclaration de type "spirale" de C est beaucoup trop compliquée. Il y a une raison pour laquelle pratiquement tous les autres langages de type statique qui ne descendent pas directement de C utilisent à la place des règles de gauche à droite.
Mason Wheeler
2
@MasonWheeler "Spiral" est un mythe urbain. La déclaration est autant ou aussi peu "spirale" que le serait l'expression correspondante. Les opérateurs sont simplement appliqués dans l'ordre de priorité et de gauche à droite (sans vous dire quoi que ce soit de nouveau ici, bien sûr): "Je dois le déréférencer, puis l'appeler, et le résultat a le type void": voila, pointeur vers la fonction void .
Peter - Rétablir Monica

Réponses:

129

void (*)() est un type, le type étant "pointeur vers une fonction qui accepte des arguments indéterminés et ne renvoie aucune valeur".

(void (*)()) est une conversion de type vers le type ci-dessus.

(void (*)())buflance bufle type ci-dessus.

((void (*)())buf)() appelle la fonction (sans passer d'arguments).

En bref: il indique au compilateur de traiter bufcomme un pointeur vers une fonction et d'appeler cette fonction.

Un mec programmeur
la source
15
Je trouve l' cdeclutilitaire (ou le site Web ) utile pour traduire les expressions C les plus complexes en anglais.
BTA
3
@bta cdecl n'est pas utile ici car la syntaxe n'est pas une déclaration. C'est un appel de fonction via un cast sur un symbole précédemment déclaré
bolov
3
@bolov - Sur toute la déclaration, non, mais il n'explique la majeure partie complexe de celui - ci. De là, décoder le reste est assez simple.
bta
5
@AvD Si n'importe où bufou copyse trouve à une adresse exécutable et que le code lui-même est indépendant de la position, cela fonctionnera. Il est bien sûr aussi non portable que possible, mais cela devrait fonctionner dans de nombreux environnements bare-metal ainsi que dans les anciens systèmes d'exploitation x86 qui ne définissent pas le bit de non-exécution (NX) sur la pile et le tas.
wrtlprnft
4
@AvD: il ne se bloquera pas nécessairement. Sauf si la zone de données est protégée contre l'exécution (qui dépend de l'architecture et de l'environnement d'exécution), vous pouvez utiliser cette astuce pour compiler une fonction dans un tableau au moment de l'exécution et l'appeler à la volée. J'ai utilisé cette astuce pour la première fois il y a 35 ans sur un DEC Vax pour compiler des machines de Turing pour une expérience ratée dans l'évolution des machines de Turing.
TonyK
11

le pointeur bufest converti en pointeur pour annuler la fonction en prenant un nombre non spécifié de paramètres, puis est déréférencé (c'est-à-dire la fonction appelée).

P J__
la source
9

Il s'agit d'un transtypage, suivi d'un appel de fonction. Tout d'abord, bufest converti en pointeur vers une fonction qui retourne void. La dernière paire de parenthèses signifie que la fonction est alors appelée.

lukeg
la source
7

Il convertit le tableau de caractères en un pointeur vers une fonction ne prenant aucun argument et retournant void, puis l'appelle. Il n'est pas nécessaire de déréférencer le pointeur en raison du fonctionnement des pointeurs de fonction.

Une explication:

Ce "tableau de caractères" est en fait un tableau de code machine. Lorsque vous convertissez le tableau en un void (*)()et l'appelez, il exécute le code machine à l'intérieur du tableau. Si vous fournissiez le contenu du tableau, je pourrais le démonter pour vous et vous dire ce qu'il fait.

SS Anne
la source