No llamas a funciones dentro del kernel. El kernel reside en otro nivel de privilegio; Sus páginas de memoria no son accesibles desde el código normal. Para saltar al código del kernel, el código de la aplicación realiza una llamada al sistema que implica el uso de una puerta específica que maneja la escalada temporal de privilegios. En un sistema x86 de 32 bits que ejecuta Linux, esto se hace con int 0x80
: una interrupción activada por software. El llamante proporciona los parámetros de llamada del sistema en algunos registros de CPU específicos; en particular, el registro %eax
contiene el identificador simbólico para la llamada del sistema que la aplicación desea realizar. El manejador de interrupciones (dentro del kernel) mira los registros de la CPU para saber qué quiere la aplicación que haga el kernel (si la llamada al sistema concedida es otro problema).
No hay ASLR para llamadas al sistema; Este no es un concepto relevante aquí. ASLR es para DLL . Una DLL es una parte del código de aplicación que se carga en el espacio de direcciones de la aplicación y es accesible para la aplicación bajo sus privilegios normales; en particular, el código de la aplicación puede "saltar" al código DLL con un opcode de "salto" normal (una llamada de función no es más que un salto glorificado).
Dado que la dirección real en la que se cargará la DLL es conocida solo cuando la DLL está realmente cargada, el código de la aplicación sigue convenciones especiales para que sus códigos de salto se puedan ajustar dinámicamente para que apunten a donde quiera que se cargue la DLL. Este ajuste dinámico lo realiza el enlazador dinámico . Este enlazador utiliza tablas de reubicación para realizar su trabajo: una entrada en dicha tabla describe un código de operación que debe ajustarse, y el nombre de la función que el código de operación intenta alcanzar. Cuando se carga la DLL (mediante el enlazador dinámico), se conoce el emplazamiento en la memoria de esa función, y se ajustan los códigos de operación de salto descritos en las tablas de reubicación.
Como puede ver, todo el concepto de DLL permite que la DLL se cargue en un emplazamiento arbitrario en la RAM; ese emplazamiento puede diferir en ejecuciones sucesivas de la aplicación. El emplazamiento real depende de dónde haya un "agujero" de memoria libre lo suficientemente grande para realizar la carga, por lo que puede cambiar dependiendo de lo que haga la aplicación, la cantidad de memoria que asigne previamente, etc. La carga de DLL "naturalmente" implica direcciones de carga no fijas. ASLR es solo voluntario de mover DLL: el vinculador dinámico elige una carga aleatoria (gratuita) dirección a propósito . Esto es (casi) completamente transparente para las aplicaciones.