Cuando agrega el argumento /gs
al compilador de microsoft, colocaría una copia de args debajo de la variable del búfer.
Entonces, ¿cuál es el punto de guardar una copia de arg?
La opción / GS es una protección heurística contra el desbordamiento de búfer - algunos tipos de búfer desbordamientos, y solo si se desbordan de la "forma habitual". Visual C supone que cualquier variable que "parezca similar a una matriz" puede estar sujeta a un tratamiento similar a una matriz y, por lo tanto, posiblemente desbordarse. Quiere detectar si se ha producido un desbordamiento y hacerlo antes de regresar de la función, ya que los desbordamientos de búfer tradicionales intentan sobrescribir la dirección de retorno . Para detectar tal ocurrencia, el compilador escribe un valor de "cookie" entre la variable potencialmente desbordada y la dirección de retorno; y el código comprueba que la cookie todavía está allí cuando está a punto de salir de la función.
El compilador hará eso para todas las "variables locales", y los argumentos son tales variables locales. El sistema de detección solo funciona siempre que la cookie se encuentre entre la dirección de retorno y la variable , por lo que esto puede implicar que se muevan las cosas, de eso se trata.
Considera esto:
struct foo { int a; int b; int c; int d; };
void f(struct foo arg)
{
char buf[20];
// ...
}
En esta función, tanto buf
como arg
se consideran "como una matriz" ( arg
se considera como una matriz porque es más grande que 8 bytes). Recuerda que cuando pasas un struct
a una función C (el mismo struct
, no un puntero a un struct
), la función recibe una copia de la estructura con la que jugar. En la pila, encontrarás cosas como esta:
buf
return address
arg
(aumentando las direcciones en orden de arriba a abajo; la pila x86 crece hacia direcciones bajas, por lo que "arriba" en el esquema anterior.)
El código "/ GS" querrá agregar una cookie y colocar esa cookie entre cualquier variable similar a una matriz y la dirección de retorno. Dado que los bytes más allá (abajo) de la dirección de retorno pertenecen a la persona que llama, la función no puede jugar con ellos tanto como quisiera, por lo que tiene que hacer su trabajo en el espacio de pila libre. Por lo tanto, el código querrá esto:
buf
arg (copy of the received structure)
cookie
return address
arg (structure passed as parameter by the caller)
Esto implica copiar la estructura arg
en la entrada de la función. Dado que la estructura es, semánticamente, ya una copia, con la que la función puede jugar a voluntad, la copia no cambia el comportamiento observable de la función. Con esta copia, cualquier desbordamiento "normal" en arg
llegará a la cookie antes de sobrescribir la dirección de retorno y, por lo tanto, se detectará (con suerte) cuando la función se cierre.
Por supuesto, debo señalar que dicha protección es efectiva solo si todas las siguientes afirmaciones son verdaderas:
Por lo tanto, no debe poner demasiado crédito en la efectividad de dicho sistema.
Lea otras preguntas en las etiquetas windows compiler buffer-overflow