El infierno de las DLL

Jerga informática

El infierno de las DLL es un término genérico para las complicaciones que surgen cuando se trabaja con bibliotecas de vínculos dinámicos (DLL) utilizadas con sistemas operativos Microsoft Windows más antiguos , [1] en particular las ediciones de 16 bits heredadas , que se ejecutan todas en un único espacio de memoria. El infierno de las DLL puede aparecer de muchas formas diferentes, en las que los programas afectados pueden no ejecutarse correctamente, si es que lo hacen. Es la forma específica del ecosistema de Windows del concepto general de infierno de dependencias .

Problemas

Las DLL son la implementación de Microsoft de las bibliotecas compartidas . Las bibliotecas compartidas permiten que el código común se agrupe en un contenedor, la DLL, que es utilizada por cualquier software de aplicación en el sistema sin cargar múltiples copias en la memoria. Un ejemplo simple podría ser el editor de texto GUI , que es ampliamente utilizado por muchos programas. Al colocar este código en una DLL, todas las aplicaciones en el sistema pueden usarlo sin usar más memoria. Esto contrasta con las bibliotecas estáticas , que son funcionalmente similares pero copian el código directamente en la aplicación. En este caso, cada aplicación crece según el tamaño de todas las bibliotecas que utiliza, y esto puede ser bastante grande para los programas modernos.

El problema surge cuando la versión de la DLL en el equipo es diferente a la versión que se utilizó cuando se creó el programa. Las DLL no tienen un mecanismo integrado de compatibilidad con versiones anteriores, e incluso cambios menores en la DLL pueden hacer que su estructura interna sea tan diferente de las versiones anteriores que intentar utilizarlas generalmente hará que la aplicación se bloquee. Las bibliotecas estáticas evitan este problema porque la versión que se utilizó para crear la aplicación está incluida dentro de ella, por lo que incluso si existe una versión más nueva en otra parte del sistema, esto no afecta a la aplicación.

Una de las razones principales de la incompatibilidad de versiones es la estructura del archivo DLL. El archivo contiene un directorio de los métodos individuales (procedimientos, rutinas, etc.) incluidos en la DLL y los tipos de datos que toman y devuelven. Incluso cambios menores en el código de la DLL pueden provocar que este directorio se reorganice, en cuyo caso una aplicación que llama a un método en particular creyendo que es el cuarto elemento del directorio puede terminar llamando a una rutina completamente diferente e incompatible, lo que normalmente provocaría el bloqueo de la aplicación.

Existen varios problemas que suelen surgir con las DLL, especialmente después de haber instalado y desinstalado numerosas aplicaciones en un sistema. Las dificultades incluyen conflictos entre versiones de DLL, dificultad para obtener las DLL necesarias y tener muchas copias de DLL innecesarias.

Las soluciones a estos problemas ya se conocían cuando Microsoft estaba escribiendo el sistema DLL. [ cita requerida ] Éstas se han incorporado al reemplazo de .NET , "Ensamblajes".

Versiones incompatibles

Una versión particular de una biblioteca puede ser compatible con algunos programas que la utilizan e incompatible con otros. Windows ha sido particularmente vulnerable a esto debido a su énfasis en la vinculación dinámica de bibliotecas C++ y objetos OLE ( Object Linking and Embedding ). Las clases C++ exportan muchos métodos y un solo cambio en la clase, como un nuevo método virtual, puede hacerla incompatible con programas que se crearon con una versión anterior. Object Linking and Embedding tiene reglas muy estrictas para evitar esto: se requiere que las interfaces sean estables y los administradores de memoria no se comparten. Sin embargo, esto no es suficiente porque la semántica de una clase puede cambiar. Una corrección de error para una aplicación puede resultar en la eliminación de una característica de otra. Antes de Windows 2000 , Windows era vulnerable a esto porque la tabla de clases COM se compartía entre todos los usuarios y procesos. Solo un objeto COM en una DLL/EXE podía declararse como que tenía un ID de clase COM global específico en un sistema. Si algún programa necesitaba crear una instancia de esa clase, obtenía la implementación registrada centralmente actual. Como resultado, una instalación de un programa que instala una nueva versión de un objeto común podría dañar inadvertidamente otros programas que se instalaron previamente.

Pisoteo de DLL

Un problema común y problemático ocurre cuando un programa recién instalado sobrescribe una DLL del sistema en funcionamiento con una versión anterior e incompatible. Los primeros ejemplos de esto fueron las bibliotecas ctl3d.dlly ctl3dv2.dllpara Windows 3.1 : bibliotecas creadas por Microsoft que los editores de terceros distribuían con su software, pero cada uno distribuía la versión con la que la desarrolló en lugar de la versión más reciente. [2] La sobreescritura de DLL ocurre porque:

  • En el pasado, Microsoft distribuía archivos DLL de tiempo de ejecución como componentes de sistema compartidos [3] (originalmente C:\WINDOWS y C:\WINDOWS\SYSTEM), como una forma de compartir código de manera eficiente en un sistema operativo de memoria compartida con RAM y espacio en disco limitados. En consecuencia, los desarrolladores externos también los distribuían de esa manera.
  • Los instaladores de aplicaciones se ejecutan normalmente en un contexto de seguridad privilegiado que tiene acceso para instalar archivos DLL en los directorios del sistema y para editar el registro del sistema para registrar nuevos archivos DLL como objetos COM . Por lo tanto, un instalador mal escrito o mal configurado puede degradar una biblioteca del sistema en versiones anteriores de Windows, en las que la Protección de archivos de Windows o la Protección de recursos de Windows no revierten el cambio. En Windows Vista y versiones posteriores, solo la cuenta de "instalador de confianza" puede realizar cambios en las bibliotecas principales del sistema operativo.
  • A las aplicaciones de Windows se les permitió incluir actualizaciones del sistema operativo en sus propios programas de instalación. Es decir, muchas DLL de Microsoft son redistribuibles , lo que significa que las aplicaciones pueden incluirlas si necesitan los servicios de las bibliotecas en particular.
  • Antes de Windows Installer , los instaladores de Windows históricamente eran productos comerciales; muchas personas intentaban escribir sus propios instaladores, pasando por alto o manejando incorrectamente los problemas de versiones en el proceso. [ cita requerida ]
  • Algunos entornos de desarrollo no añadían automáticamente un recurso de versión en sus bibliotecas compiladas, por lo que muchos desarrolladores pasaban por alto este aspecto. Comprobar las fechas de los archivos, sobrescribir los archivos existentes u omitir la operación de copia si la DLL ya estaba instalada eran las únicas opciones disponibles en lugar de la creación de versiones correcta. [ cita requerida ]
  • En ocasiones, el propio sistema operativo eliminaba o reemplazaba las DLL por versiones más antiguas u obsoletas. Por ejemplo, Windows 2000 instalaba las DLL de impresora en blanco y negro encima de las DLL que reconocían el color, si se instalaba una impresora en blanco y negro después de la impresora a color. [4]

Registro COM incorrecto

En COM y otras partes de Windows, antes de la introducción de los ensamblajes paralelos sin registro, [5] el Registro se utilizaba para determinar qué DLL subyacente utilizar. Si se registraba una versión diferente de un módulo, se cargaba esta DLL en lugar de la esperada. Este escenario podría deberse a instalaciones conflictivas que registran versiones diferentes de las mismas bibliotecas, en cuyo caso prevalecería la última instalación.

Módulos compartidos en memoria

Las versiones de 16 bits de Windows (y Windows en Windows ) cargan solo una instancia de cualquier DLL dada; todas las aplicaciones hacen referencia a la misma copia en memoria, hasta que ninguna aplicación la esté usando y se descargue de la memoria. (Para las versiones de 32 y 64 bits de Windows, el uso compartido entre procesos ocurre solo cuando diferentes ejecutables cargan un módulo exactamente desde el mismo directorio; el código, pero no la pila, se comparte entre procesos a través de un proceso llamado "mapeo de memoria"). Por lo tanto, incluso cuando la DLL deseada se encuentra en un directorio donde se puede esperar que se encuentre, como en el directorio del sistema o el directorio de la aplicación, ninguna de estas instancias se utilizará si otra aplicación se ha iniciado con una versión incompatible de un tercer directorio. Este problema puede manifestarse como un error de aplicación de 16 bits que ocurre solo cuando las aplicaciones se inician en un orden específico.

Falta de capacidad de servicio

En conflicto directo con el problema de la pisoteo de DLL: si las actualizaciones de una DLL no afectan a todas las aplicaciones que la utilizan, entonces se vuelve mucho más difícil "dar servicio" a la DLL, es decir, eliminar los problemas que existen en las versiones actuales de la DLL. (Las correcciones de seguridad son un caso particularmente convincente y doloroso). En lugar de reparar sólo la última versión de la DLL, el implementador idealmente debe hacer sus correcciones y probarlas para comprobar su compatibilidad en cada versión publicada de la DLL.

Causas

La incompatibilidad de DLL ha sido causada por:

  • Restricciones de memoria, combinadas con la falta de separación del espacio de memoria de proceso en las versiones de 16 bits de Windows;
  • Falta de esquemas de versiones, nombres y ubicación del sistema de archivos estándar aplicados para las DLL;
  • Falta de un método estándar obligatorio para la instalación y eliminación de software ( gestión de paquetes );
  • Falta de soporte autorizado centralizado para la gestión y protección de la interfaz binaria de aplicaciones DLL , lo que permite que se publiquen DLL incompatibles con el mismo nombre de archivo y números de versión internos;
  • Herramientas de gestión demasiado simplificadas que impiden que los usuarios y administradores identifiquen DLL modificadas o problemáticas;
  • Desarrolladores que rompen la compatibilidad con versiones anteriores de funciones en módulos compartidos;
  • Microsoft lanza actualizaciones fuera de banda para los componentes de ejecución del sistema operativo;
  • Incapacidad de las versiones anteriores de Windows para ejecutar simultáneamente versiones conflictivas de la misma biblioteca;
  • Dependencia del directorio actual o de %PATH%la variable de entorno, que varían con el tiempo y de un sistema a otro, para encontrar DLL dependientes (en lugar de cargarlas desde un directorio configurado explícitamente);
  • Los desarrolladores reutilizan los ClassID de las aplicaciones de muestra para las interfaces COM de sus aplicaciones, en lugar de generar sus propios GUID nuevos .

El infierno de las DLL era un fenómeno muy común en las versiones anteriores a Windows NT de los sistemas operativos de Microsoft. La causa principal era que los sistemas operativos de 16 bits no restringían los procesos a su propio espacio de memoria, por lo que no les permitían cargar su propia versión de un módulo compartido con el que fueran compatibles. Se esperaba que los instaladores de aplicaciones fueran buenos ciudadanos y verificaran la información de la versión de las DLL antes de sobrescribir las DLL del sistema existente. Microsoft y otros proveedores de herramientas de terceros proporcionaban herramientas estándar para simplificar la implementación de aplicaciones (que siempre implica el envío de las DLL dependientes del sistema operativo). Microsoft incluso exigía a los proveedores de aplicaciones que utilizaran un instalador estándar y que certificaran que su programa de instalación funcionaba correctamente antes de que se les concediera el uso del logotipo de Microsoft. El enfoque del instalador de buenos ciudadanos no mitigó el problema, ya que el aumento de la popularidad de Internet proporcionó más oportunidades para obtener aplicaciones no conformes.

Uso por parte de malware

La ambigüedad con la que se pueden cargar DLL que no están completamente calificadas en el sistema operativo Windows ha sido explotada por malware en los últimos años, [ ¿cuándo? ] abriendo una nueva clase de vulnerabilidad que afecta a aplicaciones de muchos proveedores de software diferentes, así como al propio Windows. [6]

Soluciones

Se han solucionado o mitigado varias formas de problemas de DLL a lo largo de los años.

Enlace estático

Una solución sencilla para el infierno de las DLL en una aplicación es vincular estáticamente todas las bibliotecas, es decir, incluir la versión de la biblioteca requerida en el programa, en lugar de elegir una biblioteca del sistema con un nombre específico. [7] Esto es común en aplicaciones C/C++, donde, en lugar de tener que preocuparse por qué versión MFC42.DLLestá instalada, la aplicación se compila para que se vincule estáticamente con las mismas bibliotecas. Esto elimina las DLL por completo y es posible en aplicaciones independientes que utilizan solo bibliotecas que ofrecen una opción estática, como lo hace Microsoft Foundation Class Library . Sin embargo, se sacrifica el propósito principal de las DLL (compartir la biblioteca en tiempo de ejecución entre programas para reducir la sobrecarga de memoria); duplicar el código de la biblioteca en varios programas crea una sobrecarga de software y complica la implementación de parches de seguridad o versiones más nuevas del software dependiente.

Protección de archivos de Windows

El problema de sobrescritura de DLL (al que Microsoft denomina DLL Stomping ) se redujo un poco con Windows File Protection (WFP), [8] que se introdujo en Windows 2000. [ 9] Esto evita que aplicaciones no autorizadas sobrescriban las DLL del sistema, a menos que utilicen las API específicas de Windows que lo permiten. Todavía puede existir el riesgo de que las actualizaciones de Microsoft sean incompatibles con las aplicaciones existentes, pero este riesgo se reduce normalmente en las versiones actuales de Windows mediante el uso de ensamblajes en paralelo .

Las aplicaciones de terceros no pueden manipular los archivos del sistema operativo a menos que incluyan actualizaciones legítimas de Windows en su instalación o deshabiliten el servicio de protección de archivos de Windows durante la instalación. En Windows Vista o posterior, también toman posesión de los archivos del sistema y se otorgan acceso a ellos mismos. La utilidad SFC podría revertir estos cambios en cualquier momento.

Ejecutar archivos DLL conflictivos simultáneamente

Las soluciones aquí consisten en tener diferentes copias de las mismas DLL para cada aplicación, tanto en disco como en memoria.

Una solución manual sencilla para los conflictos era colocar las distintas versiones de la DLL problemática en las carpetas de las aplicaciones, en lugar de en una carpeta común para todo el sistema. Esto funciona en general siempre que la aplicación sea de 32 o 64 bits y que la DLL no utilice memoria compartida. En el caso de las aplicaciones de 16 bits, las dos aplicaciones no se pueden ejecutar simultáneamente en una plataforma de 16 bits o en la misma máquina virtual de 16 bits bajo un sistema operativo de 32 bits. OLE impedía esto antes de Windows 98 SE/2000, porque las versiones anteriores de Windows tenían un único registro de objetos COM para todas las aplicaciones.

Windows 98 SE/2000 introdujo una solución llamada ensamblaje lado a lado [10], que carga copias separadas de DLL para cada aplicación que las requiere (y, por lo tanto, permite que las aplicaciones que requieren DLL en conflicto se ejecuten simultáneamente). Este enfoque elimina los conflictos al permitir que las aplicaciones carguen versiones únicas de un módulo en su espacio de direcciones, al tiempo que preserva el beneficio principal de compartir DLL entre aplicaciones (es decir, reducir el uso de memoria) mediante el uso de técnicas de mapeo de memoria para compartir código común entre diferentes procesos que aún usan el mismo módulo. Sin embargo, las DLL que usan datos compartidos entre múltiples procesos no pueden adoptar este enfoque. [11] Un efecto secundario negativo es que las instancias huérfanas de DLL pueden no actualizarse durante los procesos automatizados.

Aplicaciones portátiles

Dependiendo de la arquitectura de la aplicación y el entorno de ejecución, las aplicaciones portables pueden ser una forma efectiva de reducir algunos problemas de DLL, ya que cada programa incluye sus propias copias privadas de cualquier DLL que necesite. [9] El mecanismo se basa en que las aplicaciones no califiquen completamente las rutas a las DLL dependientes al cargarlas, y el sistema operativo busque el directorio ejecutable antes de cualquier ubicación compartida. [12] Sin embargo, esta técnica también puede ser explotada por malware, [13] y la mayor flexibilidad también puede venir a expensas de la seguridad si las DLL privadas no se mantienen actualizadas con parches de seguridad de la misma manera que las compartidas.

La virtualización de aplicaciones también puede permitir que las aplicaciones se ejecuten en una "burbuja", lo que evita instalar archivos DLL directamente en el sistema operativo.

Otras contramedidas

Existen otras contramedidas para evitar el problema de las DLL, algunas de las cuales pueden tener que usarse simultáneamente; algunas otras características que ayudan a mitigar el problema son:

  • Las herramientas de instalación ahora están incluidas en Microsoft Visual Studio , uno de los principales entornos para el desarrollo de Windows. Estas herramientas realizan la comprobación de versiones antes de la instalación de DLL y pueden incluir paquetes de instalación predefinidos en una instalación .MSI. Esto permite que las aplicaciones de terceros integren actualizaciones de componentes del sistema operativo sin tener que escribir sus propios instaladores para estos componentes.
  • Restaurar sistema puede recuperar un sistema de una instalación defectuosa, incluido el daño del registro. Aunque esto no evita el problema, facilita la recuperación.
  • Directorio WinSxS ( Windows Side-by-Side ), que permite que coexistan múltiples versiones de las mismas bibliotecas.
  • Ejecute aplicaciones de 16 bits en un espacio de memoria separado bajo una versión de 32 bits de Windows para permitir que dos aplicaciones usen versiones conflictivas de la misma DLL al mismo tiempo.
  • Utilice una versión de Windows que incluya Protección de archivos de Windows . Windows Me y Windows 2000 , ambos lanzados en 2000, admiten esta forma de protección de archivos del sistema, al igual que Windows XP y Windows Server 2003. Su reemplazo, Protección de recursos de Windows , se introdujo en Windows Vista y Windows Server 2008, y utiliza un método diferente para proteger los archivos del sistema contra modificaciones.
  • COM sin registro: Windows XP introdujo un nuevo modo de registro de objetos COM llamado " COM sin registro ". Esta característica permite que las aplicaciones que necesitan instalar objetos COM almacenen toda la información de registro COM requerida en el directorio propio de la aplicación, en lugar de en el registro global del sistema. De este modo, proporciona un mecanismo para que varias aplicaciones registren al mismo tiempo varias versiones de la misma DLL (Microsoft llama a esto " Ensamblaje en paralelo " [14] ). El infierno de las DLL se puede evitar sustancialmente utilizando COM sin registro, la única limitación es que requiere al menos Windows XP o versiones posteriores de Windows y que no debe utilizarse para servidores COM EXE o componentes de todo el sistema como MDAC , MSXML , DirectX o Internet Explorer .
  • El sistema operativo se entrega con un sistema de administración de paquetes capaz de rastrear las dependencias de las DLL, lo que fomenta el uso del administrador de paquetes y desalienta la instalación manual de las DLL. Windows Installer , incluido en Windows Me , Windows 2000 y todas las versiones posteriores, proporciona esta funcionalidad.
  • Disponer de una base de datos o autoridad central para la resolución de conflictos de DLL y la distribución de software. Los cambios en una biblioteca se pueden enviar a esta autoridad; de esta manera, puede asegurarse de que se mantenga la compatibilidad en las ramas desarrolladas. Si algún software antiguo es incompatible con la biblioteca actual, la autoridad puede proporcionar una interfaz de compatibilidad para él o agrupar la versión anterior como un paquete independiente.
  • Si los desarrolladores de software necesitan personalizar una biblioteca, y es poco probable que la versión principal de la biblioteca incorpore los cambios que necesitan, pueden enviar la DLL personalizada para el uso privado del programa (generalmente colocándola en el directorio privado del programa) o vincular estáticamente el programa con la biblioteca personalizada.
  • Si bien las DLL son las mejores para modularizar aplicaciones y componentes del sistema y como bibliotecas de terceros, su uso no es imperativo en todos los casos en los sistemas modernos donde la memoria ya no es una limitación. Por ejemplo, si una aplicación necesita una biblioteca que no se utilizará en ningún otro lugar, se puede vincular de forma estática, sin pérdida de espacio y con una ganancia de velocidad.
  • Windows Vista y versiones posteriores utilizan un servicio TrustedInstaller especial para instalar archivos del sistema operativo. Otras cuentas de usuario, incluida la de SYSTEM, no tienen acceso para sobrescribir los archivos binarios básicos del sistema. Windows 7 amplía esta funcionalidad a algunas partes críticas del Registro.

Véase también

Referencias

  1. ^ "Cómo evitar el infierno de las DLL: introducción de metadatos de aplicaciones en Microsoft .NET Framework". Microsoft. Octubre de 2000.
  2. ^ "Un resumen de los artículos de CTL3D.DLL en la Base de conocimientos de soporte técnico de Microsoft". Microsoft.
  3. ^ Redistribución del componente de tiempo de ejecución C compartido en Visual C++ 2005 y en Visual C++ .NET.
  4. ^ KB 830490: La impresora HP Color LaserJet sólo imprime en escala de grises o en blanco y negro en su computadora con Windows 2000 SP4.
  5. ^ Leslie Muller; Steve White (julio de 2005). "Activación de componentes COM sin necesidad de registro: guía paso a paso". Microsoft .
  6. ^ "Carga segura de bibliotecas para evitar ataques de precarga de DLL". Microsoft. 11 de junio de 2011. Consultado el 19 de julio de 2011 .
  7. ^ Pfeiffer, Tim (1998-06-01). "Windows DLLs: Threat or Menace?" (DLL de Windows: ¿amenaza o peligro?). Dr. Dobb's Journal. Archivado desde el original el 2010-08-07 . Consultado el 2010-07-07 .
  8. ^ Protección de archivos de Windows y Windows.
  9. ^ ab Anderson, Rick (11 de enero de 2000). "El fin del infierno de las DLL". microsoft.com. Archivado desde el original el 5 de junio de 2001. Consultado el 7 de julio de 2010 .
  10. ^ "Implementación de uso compartido de componentes en paralelo en aplicaciones (ampliado)". Microsoft. Archivado desde el original el 10 de diciembre de 2006. Consultado el 3 de enero de 2013 .
  11. ^ "¿Cómo puedo compartir datos de mi DLL con una aplicación o con otras DLL?". Microsoft . Consultado el 11 de noviembre de 2008 .
  12. ^ Desitter, Arnaud (15 de junio de 2007). "Uso de bibliotecas estáticas y compartidas en distintas plataformas; fila 9: ruta de la biblioteca". Recetas de Arnaud. Archivado desde el original el 1 de junio de 2008. Consultado el 7 de julio de 2010 .
  13. ^ "Carga segura de bibliotecas para evitar ataques de precarga de DLL". Microsoft . Consultado el 16 de febrero de 2013 .
  14. ^ Ensamblajes uno al lado del otro (Windows)
  • Cómo salir del infierno de las DLL en Microsoft TechNet
  • Simplificación de la implementación y solución de problemas con las DLL con .NET Framework en MSDN
  • Cómo evitar el infierno de las DLL: introducción de metadatos de aplicaciones en Microsoft .NET Framework por Matt Pietrek
  • Dr. Dobb está en el infierno de DLL (detalles en LoadLibraryEx)
  • Joel en una discusión sobre software Archivado el 30 de octubre de 2018 en Wayback Machine
  • Artículo sobre el infierno de las DLL
Retrieved from "https://en.wikipedia.org/w/index.php?title=DLL_Hell&oldid=1258002674"