2011-06-03 20 views
13

Estoy trabajando en la aplicación (escrita en C++), que genera código de máquina en tiempo de ejecución (Linux, x86-64 ahora, pero planeo migrar en ARM). A continuación, almacena el código generado en la memoria y lo ejecuta saltando a la ubicación de la memoria. Durante mucho tiempo he tenido un problema con la asignación de memoria ejecutable, pero finalmente lo solucioné usando:Inyectando código en ejecutable en tiempo de ejecución

uint8_t *memory = mmap (NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 

Hasta ahora funciona, pero no estoy seguro si es manera elegante de hacer tales cosas. Me pregunto cómo el cargador ejecutable hace esto?

+1

Así se hace. –

+0

posible duplicado de [Asignar ejecutable ram en c en Linux] (http://stackoverflow.com/questions/3125756/allocate-executable-ram-in-c-on-linux) – ninjalj

Respuesta

13

Esto es esencialmente cómo los cargadores ejecutables hacen cosas; en su caso, realizan un mmap de un archivo, no un mapeo anónimo, pero aparte de eso, es esencialmente el mismo.

Tenga en cuenta que es una buena idea no tener acceso de escritura y ejecución al mismo tiempo, ya que hace que ciertos tipos de ataques de seguridad sean más fáciles. Puede usar mprotect para ajustar los indicadores de protección después de la asignación inicial.

13

Su solución es principalmente lo que se debe hacer: hacer que el sistema operativo considere las páginas como ejecutables. Sin embargo, algunos sistemas operativos harán cumplir la llamada política W^X, en la que una página puede ser editable o ejecutable, pero no ambas simultáneamente. Para dichos sistemas (es decir, OpenBSD, pero existen versiones de Linux modificadas que también lo hacen), su mmap() anterior fallará. Por lo tanto, la solución completa implicaría asignar primero algunas páginas con mmap() y PROT_READ | PROT_WRITE, luego usar mprotect() para cambiar las páginas a PROT_READ | PROT_EXEC cuando se haya generado el código.

Incluso si el sistema operativo no aplica W^X, se recomienda encarecidamente llamar a mprotect() debido a los efectos de caché (el acceso y la ejecución de los datos están bastante separados en la CPU; asegúrese de que la CPU utilice sus códigos de operación recién escritos y no lo que estaba en RAM inmediatamente antes; mprotect() contiene la magia necesaria para eso).

Cuestiones relacionadas