En lugar de darte una respuesta directa, porque en su mayoría será "depende", pensé que podría ser más interesante llevarte a través de un descubrimiento reciente que describe el comportamiento de la asignación de memoria en Windows, de modo que Tienes algún contexto detrás de todo esto. No sé lo suficiente sobre el modelo de administración de memoria de Linux, por lo que no comentaré ese lado de las cosas, aunque me dicen que es bastante similar.
Recientemente estuve pensando en las características de protección de memoria W ^ X que ofrece el kernel de Windows, conocido como " política de código dinámico ". La idea es que una vez que una página asignada a una aplicación se ha marcado como escribible, nunca se puede marcar como ejecutable. Esta es una poderosa mitigación de exploits porque previene casi todas las clases de exploits que involucran la entrega de shellcode. No puede simplemente hacer un desbordamiento del búfer, obtener el control del puntero de instrucción, ROP a VirtualProtect, marcar su carga útil como RWX y ejecutarla: la llamada a VirtualProtect falla porque la memoria no puede escribirse y ejecutarse.
Mi idea de un bypass genérico aquí era que se pudiera usar VirtualAlloc en la memoria de lectura y escritura, en VirtualFree, luego en VirtualAlloc nuevamente como lectura + ejecución, con la esperanza de que se vuelvan a asignar las mismas páginas. Como resultado, esto no funciona. La razón por la que es relevante para su pregunta.
Hay tres casos en los que la administración de memoria de Windows arrastrará las páginas a cero:
- Cuando una página está comprometida con un proceso
- Cuando una página se ha marcado como
MEM_RESET
- Cuando una página se ha liberado y está marcada como sucia
El primero frustra mi plan. A los procesos se les puede asignar espacio de direcciones virtuales sin comprometerlos, por ejemplo. a través de llamar a VirtualAlloc con MEM_RESERVE
. El espacio de direcciones reservado no se asigna directamente a ninguna memoria física o intercambio, pero el proceso lo mantiene para su uso en caso de que lo necesite. Para poder utilizar realmente la memoria, las páginas deben estar comprometidas, por ejemplo, llamando a VirtualAlloc con MEM_RESERVE | MEM_COMMIT
. Una vez confirmada, una página se pondrá a cero si aún no lo ha hecho por otros medios. Como tal, mi truco de asignar datos grabables, liberarlos y luego asignarlos como ejecutables se rompe porque el administrador de memoria pone a cero la página.
El segundo también es interesante. Si ha terminado de usar un bloque de memoria por ahora, pero lo usará de nuevo más tarde, puede restablecer la página usando MEM_RESET
. Esto le indica al administrador de memoria que no debe retirar la página del proceso, pero no debe molestar en intercambiarlas en el disco ya que los datos que contiene ya no son interesantes. El sistema pondrá a cero estas páginas en segundo plano cuando haya tiempo libre. Sin embargo, la aplicación puede solicitar deshacer el indicador de restablecimiento si el sistema aún no ha puesto a cero la página, utilizando el indicador MEM_RESET_UNDO
.
La tercera opción es que sueltes y sueltes una página, y el administrador de memoria puede reutilizar completamente cualquier otro proceso. Si la página contiene datos está marcada como sucia. El sistema lo limpiará en segundo plano o lo pondrá a cero de forma activa cuando se confirme nuevamente.
Este es el caso de la gestión de memoria de nivel del sistema . La gestión a nivel de proceso es muy diferente, por ejemplo, utilizando HeapAlloc, asignadores de biblioteca (malloc), o un asignador completamente personalizado. Estos diseños pueden asignar y asignar una página de memoria y realizar su propia administración del uso de la memoria por encima de ese bloque comprometido. Como tal, una llamada libc free () en realidad no puede anular las páginas de memoria subyacentes. También es totalmente posible que una llamada a malloc () devuelva páginas que no se hayan restablecido, por eso existe calloc ().
La siguiente parte de la pregunta es si los navegadores tienen defensas activas contra esto. No sé si lo hacen. Es ciertamente posible que sus asignadores de memoria pongan a cero explícitamente todas las nuevas páginas asignadas (o las establezcan en algún valor mágico, por ejemplo, 0xDEADBEEF) con el fin de limitar el potencial e identificar mejor los casos de lecturas de memoria sin inicializar. Además, por ejemplo, el asignador de memoria de Microsoft Edge está especialmente diseñado para ofrecer mayor seguridad contra la corrupción de la memoria, por lo que restablecer las asignaciones es parte de eso.
En resumen, depende!