El infierno de las DLL es un término general para las complicaciones que surgen al trabajar con bibliotecas de vínculos dinámicos (DLL) utilizadas con sistemas operativos Microsoft Windows antiguos , [ 1 ] particularmente las ediciones heredadas de 16 bits , que se ejecutan en un único espacio de memoria. El infierno de las DLL puede aparecer de muchas maneras diferentes, en las que los programas afectados pueden no ejecutarse correctamente, o directamente no ejecutarse. Es la forma específica del ecosistema Windows del concepto general de infierno de dependencias .
Problemas
Las DLL son la implementación de Microsoft de las bibliotecas compartidas . Estas bibliotecas permiten agrupar código común en un contenedor, la DLL, que cualquier aplicación del sistema puede utilizar sin necesidad de cargar múltiples copias en la memoria. Un ejemplo sencillo es el editor de texto con interfaz gráfica , ampliamente utilizado por muchos programas. Al colocar este código en una DLL, todas las aplicaciones del sistema pueden usarlo sin consumir memoria adicional. Esto contrasta con las bibliotecas estáticas , que son funcionalmente similares, pero copian el código directamente en la aplicación. En este caso, el tamaño de cada aplicación aumenta en función del tamaño de todas las bibliotecas que utiliza, lo que puede ser considerable para los programas modernos.
El problema surge cuando la versión de la DLL en el equipo difiere de la versión utilizada al crear el programa. Las DLL no cuentan con un mecanismo integrado de retrocompatibilidad , e incluso cambios menores pueden alterar su estructura interna de tal manera que intentar utilizarlas generalmente provoca el fallo de la aplicación. Las bibliotecas estáticas evitan este problema, ya que incluyen la versión utilizada para compilar la aplicación; por lo tanto, aunque exista una versión más reciente en otra parte del sistema, esto no afecta a la aplicación.
Una razón clave para la incompatibilidad de versiones es la estructura del archivo DLL. Este archivo contiene un directorio con los métodos (procedimientos, rutinas, etc.) que contiene, así como los tipos de datos que reciben y devuelven. Incluso cambios menores en el código de la DLL pueden provocar que este directorio se reorganice. En ese caso, una aplicación que llame 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 provocaría que la aplicación fallara.
Existen varios problemas comunes con las DLL, especialmente después de instalar y desinstalar numerosas aplicaciones en un sistema. Entre las dificultades se incluyen conflictos entre versiones de DLL, dificultades para obtener las DLL necesarias y la existencia de muchas copias innecesarias de DLL.
Las soluciones a estos problemas ya se conocían cuando Microsoft estaba desarrollando el sistema DLL. Estas soluciones se han incorporado a la biblioteca que lo reemplaza en .NET , denominada "Assemblys".
Versiones incompatibles
Una versión específica 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 el enlace dinámico 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 compilados con una versión anterior. OLE tiene reglas muy estrictas para evitar esto: las interfaces deben ser estables y los administradores de memoria no se comparten. Sin embargo, esto es insuficiente, ya que 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 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 con 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 en ese momento. Como resultado, la instalación de un programa que instala una nueva versión de un objeto común podría, sin querer, dañar otros programas que se hayan instalado previamente.
Eliminación de DLL
Un problema común y molesto ocurre cuando un programa recién instalado sobrescribe una DLL del sistema que funciona correctamente con una versión anterior e incompatible. Ejemplos tempranos de esto fueron las ctl3d.dllbibliotecas ctl3dv2.dllpara Windows 3.1 : bibliotecas creadas por Microsoft que los editores externos distribuían con su software, pero cada uno distribuía la versión con la que lo desarrollaron en lugar de la versión más reciente. [ 2 ] La sobrescritura de DLL ocurre porque:
- En el pasado, Microsoft distribuía las 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 las distribuían de esta manera.
- Los instaladores de aplicaciones suelen ejecutarse en un entorno de seguridad privilegiado que permite 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 antiguas de Windows, donde 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 modificar las bibliotecas principales del sistema operativo.
- Las aplicaciones de Windows podían 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 dichas bibliotecas.
- Antes de Windows Installer , los instaladores de Windows eran históricamente productos comerciales; muchas personas intentaban escribir sus propios instaladores, pasando por alto o gestionando incorrectamente los problemas de versiones en el proceso.
- Algunos entornos de desarrollo no añadían automáticamente un recurso de versión a 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 un correcto control de versiones.
- En ocasiones, el propio sistema operativo eliminaba o reemplazaba las DLL con versiones más antiguas u obsoletas. Por ejemplo, Windows 2000 instalaba las DLL de impresoras en blanco y negro sobre las DLL compatibles con color, si la impresora en blanco y negro se instalaba 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 ensamblados sin registro en paralelo , [ 5 ] el Registro se utilizaba para determinar qué DLL subyacente usar. Si se registraba una versión diferente de un módulo, se cargaba esta DLL en lugar de la esperada. Esta situación podía deberse a instalaciones conflictivas que registraban versiones diferentes de las mismas bibliotecas, en cuyo caso prevalecía la última instalación.
Módulos compartidos en memoria
Las versiones de 16 bits de Windows (y Windows on Windows ) cargan solo una instancia de cada DLL; todas las aplicaciones hacen referencia a la misma copia en memoria hasta que ninguna aplicación la utiliza y se descarga de la memoria. (En las versiones de 32 y 64 bits de Windows, el uso compartido entre procesos solo ocurre cuando diferentes ejecutables cargan un módulo desde el mismo directorio; el código, pero no la pila, se comparte entre procesos mediante un proceso llamado "mapeo de memoria"). Por lo tanto, incluso cuando la DLL deseada se encuentra en un directorio donde se espera que esté, 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 desde un tercer directorio. Este problema puede manifestarse como un error de aplicación de 16 bits que solo ocurre cuando las aplicaciones se inician en un orden específico.
Falta de funcionalidad
En conflicto directo con el problema de la sobreexposición de DLL: si las actualizaciones de una DLL no afectan a todas las aplicaciones que la utilizan, resulta mucho más difícil "darle mantenimiento", es decir, eliminar los problemas existentes en las versiones actuales de la DLL. (Las correcciones de seguridad son un caso particularmente complejo y problemático). En lugar de corregir solo la última versión de la DLL, lo ideal es que el desarrollador aplique las correcciones y las pruebe para comprobar su compatibilidad con todas las versiones publicadas de la DLL.
Causas
La incompatibilidad de DLL se debe a:
- Limitaciones de memoria, combinadas con la falta de separación del espacio de memoria de procesos en las versiones de 16 bits de Windows;
- Falta de esquemas estandarizados y obligatorios para el versionado, la nomenclatura y la ubicación en el sistema de archivos de las DLL;
- Falta de un método estándar obligatorio para la instalación y eliminación de software ( gestión de paquetes );
- La falta de soporte centralizado y autorizado para la gestión y las medidas de seguridad de la interfaz binaria de las aplicaciones DLL 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 a los usuarios y administradores identificar las DLL modificadas o problemáticas;
- Los desarrolladores están rompiendo la compatibilidad con versiones anteriores de las funciones en los módulos compartidos;
- Microsoft lanza actualizaciones fuera de banda para los componentes de tiempo 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 la
%PATH%variable de entorno , ambos variables con el tiempo y de un sistema a otro, para encontrar las DLL dependientes (en lugar de cargarlas desde un directorio configurado explícitamente); - Los desarrolladores reutilizan los ClassID de las aplicaciones de ejemplo para las interfaces COM de sus aplicaciones, en lugar de generar sus propios GUID nuevos .
El problema de las DLL era 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, impidiendo así que cargaran su propia versión de un módulo compartido compatible. Se esperaba que los instaladores de aplicaciones verificaran la información de la versión de las DLL antes de sobrescribir las DLL del sistema. Microsoft y otros proveedores de herramientas de terceros ofrecían herramientas estándar para simplificar la implementación de aplicaciones (que siempre implicaba el envío de las DLL del sistema operativo dependientes). Microsoft incluso exigía 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 poder usar el logotipo de Microsoft. Sin embargo, este enfoque de instaladores que verificaban la versión no solucionó el problema, ya que el auge de Internet facilitó la obtención de aplicaciones no compatibles.
Uso por malware
Windows busca en varias ubicaciones DLL ambiguas, es decir, aquellas que no están completamente calificadas. El malware puede explotar este comportamiento de varias maneras, en un proceso conocido como secuestro del orden de búsqueda de DLL . Un método es la precarga de DLL o un ataque de inserción de binarios . Este método coloca archivos DLL con el mismo nombre en una ubicación que se buscó anteriormente, como el directorio de trabajo actual . Cuando el programa vulnerable intenta cargar la DLL, se ejecuta la versión maliciosa, posiblemente con altos privilegios si el programa se ejecuta a ese nivel. [ 6 ]
Otro método es el secuestro de DLL mediante ruta relativa , que mueve el programa vulnerable a una ubicación junto con la DLL maliciosa. La DLL se carga porque el directorio de la aplicación se busca al principio. Según CrowdStrike , este método es el más común. [ 7 ] La carga lateral de DLL entrega tanto el programa legítimo como la biblioteca maliciosa. Puede evitar la detección porque la ejecución parece la de un programa legítimo. [ 8 ]
Otros métodos incluyen el secuestro de DLL fantasma , donde se crea un archivo DLL malicioso a partir de referencias a una biblioteca inexistente, y la modificación de los valores del registro para abusar de la redirección de DLL , lo que cambia el orden de búsqueda de DLL. [ 6 ]
El secuestro de DLL fue utilizado por grupos patrocinados por el estado, incluidos Lazarus Group y Tropic Trooper . [ 8 ]
Soluciones
A lo largo de los años, se han resuelto o mitigado diversas formas del problema de las DLL.
Enlace estático
Una solución simple al problema de las DLL en una aplicación es enlazar estáticamente todas las bibliotecas, es decir, incluir la versión de la biblioteca requerida en el programa, en lugar de seleccionar una biblioteca del sistema con un nombre específico. [ 9 ] 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 enlazarse estáticamente con las mismas bibliotecas. Esto elimina por completo las DLL y es posible en aplicaciones independientes que solo utilizan bibliotecas que ofrecen una opción estática, como 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; duplicar el 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 recientes del software dependiente.
Protección de archivos de Windows
El problema de sobrescritura de DLL (conocido como DLL stomping por Microsoft) se redujo en cierta medida con la Protección de archivos de Windows (WFP), [ 10 ] que se introdujo en Windows 2000. [ 11 ] Esto impide que las aplicaciones no autorizadas sobrescriban las DLL del sistema, a menos que utilicen las API específicas de Windows que lo permiten. 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 sobrescribir archivos del sistema operativo a menos que incluyan actualizaciones legítimas de Windows en su instalador, o que deshabiliten el servicio de Protección de archivos de Windows durante la instalación. En Windows Vista o versiones posteriores, además, deben tomar posesión de los archivos del sistema y otorgarse acceso a ellos. La utilidad SFC puede revertir estos cambios en cualquier momento.
Ejecutar DLL conflictivas simultáneamente
Las soluciones propuestas consisten en tener copias diferentes de las mismas DLL para cada aplicación, tanto en el disco como en la memoria.
Una solución manual sencilla para los conflictos consistía en colocar las distintas versiones de la DLL problemática en las carpetas de las aplicaciones, en lugar de en una carpeta común del 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 pueden ejecutarse simultáneamente en una plataforma de 16 bits ni en la misma máquina virtual de 16 bits bajo un sistema operativo de 32 bits. OLE lo impedía antes de Windows 98 SE/2000, ya que 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 , [ 12 ] que carga copias separadas de DLL para cada aplicación que las requiere (y por lo tanto permite que las aplicaciones que requieren DLL conflictivas 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, mientras que preserva el beneficio principal de compartir DLL entre aplicaciones (es decir, reducir el uso de memoria) mediante el uso de técnicas de asignación 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 usar este enfoque. [ 13 ] 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 portátiles pueden ser una forma eficaz de reducir algunos problemas con las DLL, ya que cada programa incluye sus propias copias privadas de las DLL que necesita. [ 11 ] El mecanismo se basa en que las aplicaciones no califiquen completamente las rutas a las DLL dependientes al cargarlas, y en que el sistema operativo busque en el directorio ejecutable antes que en cualquier ubicación compartida. [ 14 ] Sin embargo, esta técnica también puede ser explotada por malware, [ 15 ] y la mayor flexibilidad también puede ir en detrimento 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 permite que estas se ejecuten en un entorno aislado, lo que evita la instalación de archivos DLL directamente en el sistema operativo.
Otras contramedidas
Existen otras contramedidas para evitar el infierno de las DLL, algunas de las cuales pueden tener que utilizarse simultáneamente; otras características que ayudan a mitigar el problema son:
- Las herramientas de instalación ahora vienen integradas en Microsoft Visual Studio , uno de los principales entornos para el desarrollo de Windows. Estas herramientas realizan comprobaciones de 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 dichos componentes.
- La función Restaurar sistema puede recuperar un sistema tras una instalación defectuosa, incluso si el daño se ha producido en el registro. Si bien esto no evita el problema, facilita la recuperación.
- El directorio WinSxS ( Windows Side-by-Side ) permite que coexistan varias versiones de las mismas bibliotecas.
- Ejecute aplicaciones de 16 bits en un espacio de memoria separado en una versión de Windows de 32 bits para permitir que dos aplicaciones utilicen versiones conflictivas de la misma DLL al mismo tiempo.
- Utilice una versión de Windows que incluya la Protección de archivos de Windows . Windows Me y Windows 2000 , ambos lanzados en el año 2000, son compatibles con esta forma de protección de archivos del sistema, al igual que Windows XP y Windows Server 2003. Su sustituto, la 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 necesaria en el directorio de la propia aplicación, en lugar de en el registro global del sistema. De este modo, proporciona un mecanismo para que varias aplicaciones registren simultáneamente múltiples versiones de la misma DLL (Microsoft lo denomina " Ensamblaje en paralelo " [ 16 ] ). El infierno de las DLL se puede evitar en gran medida 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 ni componentes de todo el sistema como MDAC , MSXML , DirectX o Internet Explorer .
- El sistema operativo incluye un sistema de gestión de paquetes capaz de rastrear las dependencias de las DLL, lo que fomenta el uso del gestor de paquetes y desalienta la instalación manual de las DLL. Windows Installer , incluido en Windows Me , Windows 2000 y todas las versiones posteriores, ofrece esta funcionalidad.
- Disponer de 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 pueden enviarse a esta autoridad, lo que garantiza 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 o incluir la versión anterior como un paquete independiente.
- Si los desarrolladores de software necesitan personalizar una biblioteca y es improbable que la versión principal de la biblioteca incorpore los cambios que necesitan, pueden distribuir la DLL personalizada para uso privado del programa (normalmente colocándola en el directorio privado del programa) o enlazar estáticamente el programa con la biblioteca personalizada.
- Si bien las DLL son ideales para modularizar aplicaciones y componentes del sistema, así como para funcionar como bibliotecas de terceros, su uso no es imprescindible en todos los casos en sistemas modernos donde la memoria ya no es un factor limitante. Por ejemplo, si una aplicación necesita una biblioteca que no se utilizará en ningún otro lugar, se puede enlazar estáticamente, sin penalización de espacio y con una mejora en el rendimiento.
- Windows Vista y versiones posteriores utilizan un servicio especial llamado TrustedInstaller para instalar los archivos del sistema operativo. Otras cuentas de usuario, incluida la del sistema, no tienen acceso para sobrescribir los archivos binarios principales del sistema. Windows 7 amplía esta funcionalidad a algunas partes críticas del Registro.
Véase también
Referencias
- ↑ "Evitando el infierno de las DLL: Introducción a los metadatos de las aplicaciones en Microsoft .NET Framework" . Microsoft. Octubre de 2000. Archivado del original el 10 de enero de 2015. Consultado el 27 de junio de 2011 .
- ↑ "Resumen de los artículos sobre CTL3D.DLL en la base de conocimientos de soporte técnico de Microsoft" . Microsoft. Archivado del original el 29 de junio de 2011.
- ↑ Redistribución del componente de tiempo de ejecución C compartido en Visual C++ 2005 y en Visual C++ .NET .
- ↑ KB 830490: La impresora HP Color LaserJet imprime solo en escala de grises o en blanco y negro en su equipo con Windows 2000 SP4 .
- ↑ Leslie Muller; Steve White (julio de 2005). "Activación sin registro de componentes COM: una guía paso a paso" . Microsoft . Archivado del original el 22 de marzo de 2018.
- 1 2 Holston, Ami; Liang, Marina; Kanthak, Stefan; Smith, Travis; Alexander, Will (30 de septiembre de 2024). "Flujo de ejecución de secuestro: secuestro del orden de búsqueda de DLL, subtécnica T1574.001 - Enterprise" . ATT&CK . Versión 1.3. MITRE. T1574.001 . Recuperado el 7 de diciembre de 2024 .
- ↑ Falcon OverWatch Team (30 de diciembre de 2022). "4 maneras en que los adversarios secuestran DLLs" . CrowdStrike . Consultado el 7 de diciembre de 2024 .
- 1 2 "10 años de secuestro de DLL y qué podemos hacer para prevenir 10 más" . Check Point Research . 25 de septiembre de 2024. Recuperado el 7 de diciembre de 2024 .
- ↑ Pfeiffer, Tim (1998-06-01). "DLL de Windows: ¿Amenaza o peligro?" . Dr. Dobb's Journal. Archivado del original el 7 de agosto de 2010. Consultado el 7 de julio de 2010 .
- ↑ Protección de archivos de Windows y Windows .
- 1 2 Anderson, Rick (11 de enero de 2000). "El fin del infierno de las DLL" . microsoft.com. Archivado del original el 5 de junio de 2001. Recuperado el 7 de julio de 2010 .
- ↑ "Implementación del uso compartido de componentes en paralelo en aplicaciones (versión ampliada)" . Microsoft. Archivado del original el 10 de diciembre de 2006. Consultado el 3 de enero de 2013 .
- ↑ "¿Cómo comparto datos en mi DLL con una aplicación o con otras DLL?" . Microsoft . Archivado del original el 29/06/2017 . Consultado el 11/11/2008 .
- ↑ "Carga segura de bibliotecas para prevenir ataques de precarga de DLL" . Microsoft . Consultado el 16 de febrero de 2013 .
- ↑ Ensamblajes en paralelo (Windows)
Enlaces externos
- Cómo salir del infierno de las DLL en Microsoft TechNet
- Simplificando la implementación y solucionando el problema de las DLL con .NET Framework en MSDN
- Cómo evitar el infierno de las DLL: Introducción a los metadatos de las aplicaciones en Microsoft .NET Framework por Matt Pietrek
- Dr. Dobb está en el infierno de DLL (detalles en LoadLibraryEx)
- Discusión sobre software de Joel archivada el 30/10/2018 en Wayback Machine.
- Artículo sobre el infierno de las DLL
- Bibliotecas informáticas
- Administración de Windows
- jerga informática