¿Cuán importante es hoy en día asegurarse de que todas mis DLL tengan direcciones base no conflictivas?

Raymond

20 de enero, 2017

En su día, una de las cosas que se le exhortaba a hacer era cambiar la base de sus DLL para que todos tuvieran rangos de direcciones no superpuestos, evitando así el costo de la reubicación en tiempo de ejecución. ¿Esto sigue siendo importante hoy en día?

Esta situación es otra demostración de cómo es importante que un buen consejo venga con una justificación para que pueda saber cuándo se convierte en un mal consejo.

La justificación para el cambio de base es la siguiente: Si se carga una DLL en su dirección base preferida, la imagen se puede ubicar directamente desde el almacén de respaldo sin necesidad de correcciones. Esto significa que las páginas se pueden compartir entre procesos, ya que cada proceso obtiene una copia idéntica. (Por supuesto, el uso compartido se detiene una vez que alguien escribe en la página y hace que su copia sea diferente de la copia compartida.)

Si no se puede cargar una DLL en su dirección preferida, la imagen se reubicará y toda la DLL reubicada estará respaldada por el archivo de página.1 Esta es una operación relativamente costosa, ya que la DLL debe leerse desde el disco y arreglarse, y se incurre en un cargo de confirmación en el archivo de página para garantizar que haya espacio para escribir las páginas fijas. Además, si dos procesos reubican la DLL y, por casualidad, los reubican en el mismo lugar, Windows NT no intenta compartir las imágenes reubicadas. Habrá varias copias en el archivo de página.

El coste de esta reubicación dinámica es lo que intenta evitar el cambio de base. Llamemos a esto la “multa de reubicación”.”

Ingrese ASLR.

ASLR hace que las DLL se carguen en direcciones pseudo aleatorias. En consecuencia, una DLL se cargará en su dirección base preferida solo en el caso de una coincidencia asombrosa.

Bien, así que volvamos a la lógica para ver si todavía se aplica.

¿Una DLL que se cargue lejos de su dirección base preferida incurre en una penalización de reubicación? Si lo piensas bien, ASLR significa que ninguna DLL se carga en su dirección preferida, pero también vimos que el núcleo hace adaptaciones para esto de modo que las DLL sujetas a ASLR aún puedan compartir páginas, y lo hace sin forzar a que toda la DLL se reubique en la carga inicial. Por lo tanto, no hay penalización de reubicación en el caso de que la DLL haya sido reubicada por ASLR.

Pero, ¿qué pasa si la DLL se reubica por alguna otra razón? Por ejemplo, podría ser que la dirección base elegida por ASLR no esté disponible en el proceso, porque el proceso ya asignó algo más en esa ubicación. En ese caso, se debe llevar a cabo una reubicación tradicional, y usted paga la multa de reubicación.

Ah, pero aquí está la cosa: Cuando se carga una DLL, ASLR asignará una dirección base al azar de entre las direcciones base disponibles que no se estén utilizando ya.2 Por lo tanto, no va a entrar en el escenario “la dirección base elegida por ASLR no está disponible” porque ASLR elige la dirección base de la DLL de entre las direcciones base que están disponibles.3

De acuerdo, así que todavía puedes entrar en una situación de conflicto, pero tienes que trabajar realmente en ello. Por ejemplo, puede cargar una DLL en un proceso y obtener una dirección base asignada por ASLR. A continuación, inicia un segundo proceso, asigna memoria intencionalmente a esa dirección (para forzar la colisión) y, a continuación, carga la DLL. En este caso, habrá una reubicación porque te sentaste en cuclillas en el lugar donde ASLR quería poner la DLL. Pero esto no es peor de lo que tenías antes de ASLR: En el mundo pre-ASLR, ponerse en cuclillas en la dirección base preferida de una DLL habría obligado a una penalización de reubicación de todos modos.

Entonces, veamos cuál es la historia. Reajuste o no rebase?

En presencia de ASLR, el cambio de base de sus archivos DLL no tiene efecto porque ASLR ignorará su dirección base de todos modos y reubicará la DLL en una ubicación de su elección pseudoaleatoria.

Tenga en cuenta que, a pesar de que el cambio de base no tiene ningún efecto, tampoco duele.

Si está en un sistema sin ASLR (ya sea porque es anterior a ASLR, o porque ASLR se ha deshabilitado por cualquier razón), el cambio de base ayudará, por las razones tradicionales.

Tenga en cuenta que los sistemas sin ASLR son realmente difíciles de encontrar hoy en día, por lo que el cambio de base no proporciona ningún beneficio en la abrumadora mayoría de los casos. Pero en ese porcentaje diminuto de casos en los que no tienes ASLR, el cambio de base ayuda.

Conclusión: No está de más rebase, por si acaso, pero entiende que la recompensa será extremadamente rara. Cree su DLL con /DYNAMICBASE habilitado (y con /HIGHENTROPYVA para una buena medida) y deje que ASLR haga el trabajo de asegurarse de que no se produzca una colisión de direcciones base. Eso cubrirá casi todos los escenarios del mundo real. Si cae en uno de los casos muy raros en los que ASLR no está disponible, su programa seguirá funcionando. Simplemente puede correr un poco más lento debido a la penalización de reubicación.

1 Más precisamente, todas las páginas que contienen correcciones se colocan en el archivo de página. Discutimos este punto más fino la última vez.

2 Bien, hay un tercer caso, que es donde ASLR simplemente se ha quedado sin direcciones base. Pero de nuevo, esto no es peor que lo que tenías antes de ASLR: si te quedas sin direcciones básicas, entonces sálvese quien pueda. Cada vez que se carga una DLL nueva, el núcleo tiene que buscar un espacio de direcciones lo suficientemente grande como para cargar la DLL.

3 Como resultado, ASLR en realidad hace un mejor trabajo para evitar colisiones que el reajuste manual, ya que ASLR puede ver el sistema como un todo, mientras que el reajuste manual requiere que conozca todas las DLL que se cargan en su proceso, y la coordinación de direcciones base entre varios proveedores generalmente no es posible.

Raymond Chen

Seguir

Leave a Reply