Por supuesto, sé que solía generar un puntero con argumentos.
Leí el libro Writing Secure Code de Michael Howard y David LeBlanc.
Un programa en el libro demuestra cómo funciona el desbordamiento de pila mediante strcpy()
Tenga en cuenta printf() sin argumentos.
#include <stdio.h> #include <string.h> void foo(const char* input) { char buf[10]; //What? No extra arguments supplied to printf? //It's a cheap trick to view the stack 8-) //We'll see this trick again when we look at format strings. printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); //Pass the user input straight to secure code public enemy #1. strcpy(buf, input); printf("%s\n", buf); printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); } void bar(void) { printf("Augh! I've been hacked!\n"); } int main(int argc, char* argv[]) { //Blatant cheating to make life easier on myself printf("Address of foo = %p\n", foo); printf("Address of bar = %p\n", bar); if (argc != 2) { printf("Please supply a string as an argument!\n"); return -1; } foo(argv[1]); return 0; }El resultado es
C:\Secureco2\Chapter05>StackOverrun.exe Hello Address of foo = 00401000 Address of bar = 00401045 My stack looks like: 00000000 00000000 7FFDF000 0012FF80 0040108A <-- return address 00410EDE Hello Now the stack looks like: 6C6C6548 <-- 'l','l','e','h' 0000006F <-- 0, 0, 0, 'o' 7FFDF000 0012FF80 0040108A 00410EDE ¿Cuál es el significado de printf("%p") dentro del código? ¿Por qué puede imprimir el contenido de la pila?
En general, %p es un especificador de formato para imprimir el puntero (valor de dirección), el argumento que se espera es un puntero a tipo void .
Dicho esto, en tu código,
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n"); es un comportamiento indefinido . Según la descripción de printf() en el estándar, si no hay suficientes argumentos para el formato proporcionado, es UB.
Para citar la norma, C11 , capítulo §7.21.6.1
[...] Si no hay suficientes argumentos para el formato, el comportamiento no está definido. .[...]
El fragmento de código no tiene ninguna garantía de producir ningún resultado válido.
El comportamiento de printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n"); no está definido ya que su lista de argumentos no coincide con la cadena de entrada.
Los autores están conjeturando que este mal uso particular de printf inyectará variables de la pila actual y generará sus direcciones. A veces pueden ser correctos. Otras veces, el compilador podría comerse a tu gato.
Como han dicho otros, este es un comportamiento indefinido.
Pero lo que ves parece ser una cosa ciertamente ingenua pero "natural". En la mayoría de las implementaciones de C basadas en la pila de llamadas, la persona que llama coloca los argumentos de entrada de la función en la pila y la persona que llama los extrae [1] de la pila. En este caso particular, el receptor de la llamada ( printf ) parece abrir a ciegas elementos sucesivos del tamaño de un puntero, según la cantidad de directivas de formato %p que hay en la cadena de formato, sin ningún tipo de verificación. Entonces, en lugar de eliminar los argumentos de entrada (ausentes), atraviesa la pila y "ve" lo que se supone que no debe ver. Pero este no es siempre el caso para otras implementaciones.
[1] Por "salir" no me refiero a eliminarlos destructivamente de la pila; no lo tome literalmente;) Lo más probable es que lo que sucede bajo el capó es que los argumentos de entrada son referenciados por un desplazamiento desde un puntero. Pero aquí, aparentemente, no hay restricciones sobre qué tan lejos puede llegar este desplazamiento.