DLL Hell - DLL Hell

En informática , DLL Hell es un término para las complicaciones que surgen cuando se trabaja con bibliotecas de vínculos dinámicos (DLL) que se utilizan con los sistemas operativos Microsoft Windows , en particular las ediciones heredadas de 16 bits , que se ejecutan en un solo espacio de memoria.

DLL Hell puede manifestarse de muchas formas diferentes en las que las aplicaciones no se inician ni funcionan correctamente.

DLL Hell es la forma específica del ecosistema de Windows del concepto general de dependencia del infierno .

Problemas

Las DLL son la implementación de Microsoft de bibliotecas compartidas . Las bibliotecas compartidas permiten agrupar código común en un contenedor, el DLL, y utilizarlo cualquier software de aplicación en el sistema sin cargar varias 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 del 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 la computadora es diferente a la versión que se usó cuando se creó el programa. Los archivos DLL no tienen un mecanismo incorporado para la compatibilidad con versiones anteriores, e incluso los cambios menores en el archivo DLL pueden hacer que su estructura interna sea tan diferente de las versiones anteriores que intentar usarlos generalmente hará que la aplicación se bloquee. Las bibliotecas estáticas evitan este problema porque la versión que se usó para construir 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 la aplicación.

Una razón clave de la incompatibilidad de versiones es la estructura del archivo DLL. El archivo contiene un directorio de los métodos individuales (procedimientos, rutinas, etc.) contenidos dentro de la DLL y los tipos de datos que toman y devuelven. Incluso cambios menores en el código DLL pueden hacer 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 podría terminar llamando a una rutina completamente diferente e incompatible, lo que normalmente hace que la aplicación se bloquee.

Hay varios problemas que se encuentran comúnmente con las DLL, especialmente después de que se han instalado y desinstalado numerosas aplicaciones en un sistema. Las dificultades incluyen conflictos entre las versiones de DLL, dificultad para obtener las DLL necesarias y tener muchas copias de DLL innecesarias.

Las soluciones a estos problemas se conocían incluso cuando Microsoft estaba escribiendo el sistema DLL. Estos se han incorporado en el reemplazo de .NET , "Ensamblados".

Versiones incompatibles

Una versión particular de una biblioteca puede ser compatible con algunos programas que la usan e incompatible con otros. Windows ha sido particularmente vulnerable a esto debido a su énfasis en la vinculación dinámica de bibliotecas de C ++ y objetos de vinculación e incrustación de objetos (OLE). Las clases de C ++ exportan muchos métodos, y un solo cambio en la clase, como un nuevo método virtual, puede hacer que sea incompatible con programas que se crearon con una versión anterior. La vinculación e incrustación de objetos 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 es insuficiente porque la semántica de una clase puede cambiar. Una corrección de errores para una aplicación puede resultar en la eliminación de una función 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 se puede declarar que un objeto COM en una DLL / EXE tiene 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 actual registrada centralmente. Como resultado, la instalación de un programa que instaló una nueva versión de un objeto común podría romper inadvertidamente otros programas que estaban instalados previamente.

DLL pisando fuerte

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 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 distribuirían con su software, pero cada una distribuía la versión con la que desarrollaron en lugar de la versión más reciente. El stomping de DLL ocurre porque:

  • Microsoft en el pasado distribuía DLL en tiempo de ejecución como componentes de sistema compartidos (originalmente C: \ WINDOWS y C: \ WINDOWS \ SYSTEM), como una forma de compartir código de manera eficiente en un SO de memoria compartida con RAM y espacio en disco limitados. En consecuencia, los desarrolladores de terceros también los distribuyeron 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 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 heredadas de Windows, en las que Windows File Protection o Windows Resource Protection no revierte el cambio. En Windows Vista y versiones posteriores, solo la cuenta del "instalador de confianza" puede realizar cambios en las bibliotecas del sistema operativo principal.
  • 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 eran históricamente productos comerciales; muchas personas intentaron escribir sus propios instaladores, pasando por alto o manejando mal los problemas de versiones en el proceso.
  • Algunos entornos de desarrollo no agregaron automáticamente un recurso de versión en sus bibliotecas compiladas, por lo que muchos desarrolladores pasaron por alto este aspecto. Verificar 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 del control de versiones correcto.
  • A veces, el propio sistema operativo eliminó o reemplazó las DLL con versiones más antiguas u obsoletas. Por ejemplo, Windows 2000 instalaría archivos DLL de impresora en blanco y negro sobre los archivos DLL que reconocen el color, si se instalara una impresora en blanco y negro después de la impresora en color.

Registro COM incorrecto

En COM y otras partes de Windows, antes de la introducción de ensamblados sin registro en paralelo , el Registro se usó para determinar qué DLL subyacente usar. Si se registrara una versión diferente de un módulo, esta DLL se cargaría en lugar de la esperada. Este escenario podría deberse a instalaciones en conflicto que registran diferentes versiones de las mismas bibliotecas, en cuyo caso prevalecería la última instalación.

Módulos compartidos en memoria

Las versiones de Windows de 16 bits (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 utilice y se descargue de la memoria. (Para las versiones de Windows de 32 y 64 bits, el intercambio entre procesos se produce solo cuando diferentes ejecutables cargan un módulo desde exactamente el mismo directorio; el código, pero no la pila, se comparte entre procesos a través de un proceso llamado "asignación 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 en 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 facilidad de servicio

En conflicto directo con el problema de stomping de DLL: si las actualizaciones de una DLL no afectan a todas las aplicaciones que la usan, 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 arreglar solo la última versión de la DLL, el implementador idealmente debe hacer las correcciones y probar su compatibilidad en cada versión publicada de la DLL.

Causas

La incompatibilidad de DLL ha sido causada por:

  • Limitaciones de memoria, combinadas con la falta de separación del espacio de memoria de proceso en versiones de Windows de 16 bits
  • Falta de control de versiones estándar, nombres y esquemas de ubicación del sistema de archivos para 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 la aplicación DLL , lo que permite que se publiquen DLL incompatibles con el mismo nombre de archivo y números de versión internos;
  • Herramientas de administración demasiado simplificadas, que evitan la identificación de DLL cambiadas o problemáticas por parte de usuarios y administradores;
  • Desarrolladores rompiendo la compatibilidad con versiones anteriores de funciones en módulos compartidos;
  • Microsoft lanza actualizaciones fuera de banda para componentes de tiempo de ejecución del sistema operativo;
  • Incapacidad de versiones anteriores de Windows para ejecutar versiones en conflicto de la misma biblioteca una al lado de la otra;
  • Dependencia del directorio actual o %PATH%variable de entorno, los cuales varían con el tiempo y de un sistema a otro, para encontrar archivos DLL dependientes (en lugar de cargarlos 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 .

DLL Hell 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 eran compatibles. Se esperaba que los instaladores de aplicaciones fueran buenos ciudadanos y verificaran la información de la versión de DLL antes de sobrescribir las DLL del sistema existentes. Microsoft y otros proveedores de herramientas de terceros proporcionaron herramientas estándar para simplificar la implementación de aplicaciones (que siempre implica el envío de las DLL del sistema operativo dependientes). Microsoft incluso exigió a los proveedores de aplicaciones que utilizaran un instalador estándar y que su programa de instalación estuviera certificado para funcionar correctamente, antes de que se les concediera el uso del logotipo de Microsoft. El enfoque de instalador de buen ciudadano no mitigó el problema, ya que el aumento de la popularidad de Internet brindó más oportunidades para obtener aplicaciones no conformes.

Utilizado por malware

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

Soluciones

Varias formas de infierno DLL se han resuelto o mitigado a lo largo de los años.

Enlace estático

Una solución simple para DLL Hell en una aplicación es vincular estáticamente todas las bibliotecas, es decir, incluir la versión de biblioteca requerida en el programa, en lugar de elegir una biblioteca del sistema con un nombre específico. Esto es común en las aplicaciones C / C ++, donde, en lugar de tener que preocuparse por qué versión de MFC42.DLLestá instalada, la aplicación se compila para vincularse 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 bibliotecas en tiempo de ejecución entre programas para reducir la sobrecarga de memoria); la duplicación del código de la biblioteca en varios programas crea un exceso de software y complica la implementación de correcciones de seguridad o versiones más nuevas del software dependiente.

Protección de archivos de Windows

El problema de sobrescritura de DLL (conocido como DLL Stomping por Microsoft) se redujo algo con Windows File Protection (WFP), que se introdujo en Windows 2000 . Esto evita que las aplicaciones no autorizadas sobrescriban las DLL del sistema, a menos que utilicen las API de Windows específicas que lo permitan. Aún puede existir el riesgo de que las actualizaciones de Microsoft sean incompatibles con las aplicaciones existentes, pero este riesgo generalmente se reduce en las versiones actuales de Windows mediante el uso de ensamblados en paralelo .

Las aplicaciones de terceros no pueden pisotear los archivos del sistema operativo a menos que incluyan actualizaciones legítimas de Windows con su instalador, o si deshabilitan el servicio de Protección de archivos de Windows durante la instalación, y en Windows Vista o posterior también se apropian de los archivos del sistema y se otorgan acceso. La utilidad SFC podría revertir estos cambios en cualquier momento.

Ejecutar archivos DLL en conflicto 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 fácil a los conflictos fue colocar las diferentes versiones de la DLL problemática en las carpetas de las aplicaciones, en lugar de en una carpeta común de 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 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 con un sistema operativo de 32 bits. OLE impidió 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 en paralelo , 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 conserva el beneficio principal de compartir archivos DLL entre aplicaciones (es decir, reduce 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 lo hacen. utilizar el mismo módulo. Sin embargo, las DLL que utilizan datos compartidos entre varios procesos no pueden adoptar este enfoque. Un efecto secundario negativo es que es posible que las instancias huérfanas de DLL no se actualicen durante los procesos automatizados.

Aplicaciones portátiles

Dependiendo de la arquitectura de la aplicación y el entorno de ejecución, las aplicaciones portátiles pueden ser una forma eficaz de reducir algunos problemas de DLL, ya que cada programa incluye sus propias copias privadas de cualquier DLL que necesite. El mecanismo se basa en que las aplicaciones no califiquen completamente las rutas a las DLL dependientes al cargarlas y que el sistema operativo busque el directorio ejecutable antes que cualquier ubicación compartida. Sin embargo, esta técnica también puede ser explotada por malware, y la mayor flexibilidad también puede producirse 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 la instalación de archivos DLL directamente en el sistema operativo.

Otras contramedidas

Existen otras contramedidas para evitar DLL Hell, 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 verificación de la versión 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 mala instalación, incluido el daño del registro. Si bien esto no evita el problema, facilita la recuperación.
  • Directorio WinSxS ( Windows Side-by-Side ), que permite que coexistan varias versiones de las mismas bibliotecas.
  • Ejecute aplicaciones de 16 bits en un espacio de memoria independiente en una versión de Windows de 32 bits para permitir que dos aplicaciones utilicen versiones en conflicto 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 para evitar cambios.
  • COM sin registro: Windows XP introdujo un nuevo modo de registro de objetos COM llamado " COM sin registro ". Esta característica hace posible 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 del sistema global. Por lo tanto, proporciona un mecanismo para que múltiples versiones de la misma DLL sean registradas al mismo tiempo por múltiples aplicaciones (Microsoft lo llama " Ensamblado en paralelo "). El infierno de DLL se puede evitar sustancialmente usando COM sin registro, la única limitación es que requiere al menos Windows XP o versiones posteriores de Windows y que no debe usarse para servidores COM EXE o componentes de todo el sistema como MDAC , MSXML , DirectX o Internet Explorer .
  • Enviar el sistema operativo con un sistema de administración de paquetes capaz que pueda rastrear las dependencias de DLL, fomentando el uso del administrador de paquetes y desalentando la instalación manual de DLL. Windows Installer , incluido con Windows Me , Windows 2000 y todas las versiones posteriores, proporciona esta funcionalidad.
  • Tener una base de datos central o autoridad 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; por lo tanto, 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 proporcionarle una interfaz de compatibilidad o agrupar la versión anterior como un paquete distinto.
  • Si los desarrolladores de software necesitan personalizar una biblioteca, y si es poco probable que la versión de la biblioteca principal 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 enlazar estáticamente el programa contra la biblioteca personalizada.
  • Si bien las DLL son 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 restricción. Por ejemplo, si una aplicación necesita una biblioteca que no se utilizará en ningún otro lugar, se puede vincular estáticamente, sin penalización 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, incluido el SISTEMA, no tienen acceso para sobrescribir los archivos binarios del sistema principal. Windows 7 amplía esta funcionalidad a algunas partes críticas del Registro.
  • Las aplicaciones basadas en web evitan muchos problemas paralelos al ejecutar la mayor parte del código en un servidor y utilizar una interfaz de navegador en el cliente.

Ver también

Referencias

enlaces externos