Los humanos retienen el conocimiento en su memoria, similar
a lo que hace un ordenador. Los ordenadores almacenan en
la memoria todos los programas mientras se ejecutan y luego, un análisis de memoria es esencial para comprender cómo funcionan los programas cuando el código no está disponible. La estructura de la memoria de un programa en C se representa aquí. La memoria se divide en segmentos que tienen diferentes propósitos. En este curso, cuando presentamos una imagen de memoria, asumiremos que las direcciones de memoria altas están en la parte superior y las direcciones de memoria baja en la parte inferior. Pero, esto es solo una convención. En la parte superior, se ubican las variables de entorno y los argumentos. Luego, se coloca la pila. Aunque explicaremos este elemento en detalle más adelante, ahora digamos que es un espacio variable que crece de direcciones altas a direcciones bajas. El siguiente segmento se corresponde con el montículo, que crece en la dirección opuesta a la pila (de direcciones bajas a las altas). Otro segmento se llama .bss en el que se almacenan todas las variables no inicializadas. Por el contrario, el segmento .data almacena las variables inicializadas. Finalmente, en el último segmento, .text, se almacenan las instrucciones del programa y sus constantes. En otras palabras, en este último segmento se encuentra el código a ejecutar. Solo como un breve resumen, describamos el papel de la pila y el montículo. La pila es, de hecho, una parte muy importante, de gran ayuda en el proceso de ingeniería inversa. La pila se encarga de almacenar variables de tamaño limitado. Además, cada vez que un programa cambia de una función a otra, usa la pila para guardar valores importantes, como explicaremos más adelante. Por otro lado, el montículo almacena variables dinámicas, es decir, aquellas variables cuyos tamaños deben reservarse. Con esto en mente, hay que resaltar la importancia de la pila y el montículo, como las partes más relevantes de la memoria de un ordenador para realizar ingeniería inversa. Aquí podemos identificar algunos pequeños programas en C que manejan variables inicializadas y no inicializadas. En el primer ejemplo, a la izquierda, las variables "var" y "a" se inicializan y, por lo tanto, se almacenan en el segmento .data. Por el contrario, el ejemplo de la derecha muestra las variables "buf" y "b" que no se inicializan y se ubican en el segmento .bss. Ahora se presenta el ejemplo que involucra al montículo. En este caso, la variable "var" reserva memoria para n caracteres. Como es una reserva dinámica de la memoria de almacenamiento dinámico, no podemos olvidar liberar esa memoria, es decir, llamar a la función free, de lo contrario, la memoria en el almacenamiento dinámico permanecerá reservada y puede producir problemas en algún momento. Ahora es el turno de la pila. Aquí se proporciona una breve descripción general. En la pila se llevan a cabo dos operaciones principales, PUSH y POP. La operación PUSH consiste en almacenar algo en la pila, mientras que la operación POP hace lo contrario. Nuevamente, es importante identificar la dirección de crecimiento de la pila. PUSH coloca elementos en la parte superior de la pila, mientras que POP recupera elementos también desde la parte superior. Si hacemos PUSH de los elementos 1, 2, 3 y 4, se ubican en orden inverso, es decir, el elemento 1 se ubica en las direcciones de memoria más altas y 4 en las direcciones más bajas. Como resultado, el comportamiento de la pila sigue la estrategia LIFO, Last In First Out, el último que llega es el primero en salir. Aquí tenemos un ejemplo de un pequeño código que realiza una suma de un par de números. Como se llama a la función "sumar", los argumentos de esta función se almacenan en la pila para posteriormente realizar la operación de suma. Pero, cuando se ejecutan los programas, ¿cómo funciona la pila? ¡Lo aprenderás en el siguiente video!