c++ - Redirección de DLL utilizando manifiestos
windows manifest (3)
Es posible que pueda solucionar esto utilizando Desvíos , envolviendo LoadLibrary
. El contenedor de LoadLibrary podría reconocer los intentos de cargar su DLL y reescribir la ruta de manera apropiada.
Necesito redirigir de manera confiable una búsqueda de aplicaciones de una DLL específica. El uso del enfoque app.exe.local no funciona porque los archivos locales se ignoran si la aplicación tiene un manifiesto (archivo incrustado o separado). Así que estoy tratando de hacer una redirección de DLL definiendo el archivo DLL como un ensamblado privado en los manifiestos.
Tengo una aplicación de prueba, LoadDll.exe que simplemente llama
LoadLibrary("C://EmptyDll.dll");
LoadDll.exe tiene el manifiesto (como un archivo separado, LoadDll.exe.manifest)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.1"
processorArchitecture="x86"
name="LoadDll"
type="win32"
/>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="EmptyDll"
version="1.0.0.1"
processorArchitecture="x86"
/>
</dependentAssembly>
</dependency>
</assembly>
La carpeta de la aplicación que contiene LoadDll.exe (NO c: /) contiene EmptyDll.dll con el manifiesto incrustado.
<?xml version=''1.0'' encoding=''UTF-8'' standalone=''yes''?>
<assembly xmlns=''urn:schemas-microsoft-com:asm.v1'' manifestVersion=''1.0''>
<assemblyIdentity
type="win32"
name="EmptyDll"
version="1.0.0.1"
processorArchitecture="x86"
/>
</assembly>
Sin embargo, LoadDll.exe continúa y carga C: / EmptyDll.dll, y no EmptyDll.dll en la carpeta de la aplicación.
Si rompe cualquiera de los manifiestos (por ejemplo, cambie el número de versión en la identidad del manifiesto EmptyDll.dll), LoadDll.exe no se carga, por lo que los archivos de manifiesto son leídos y procesados por Windows, pero simplemente se ignoran.
¿Alguien tiene alguna idea?
¡Gracias!
Toby
Por lo tanto, parece imposible redireccionar las llamadas a LoadLibrary con rutas absolutas usando manifiestos.
Después de jugar con los manifiestos, parece que una vez que pasas todos los manifiestos de mala documentación son en realidad estúpidamente simples.
Básicamente, cuando se carga el archivo ejecutable, Windows recopila todos los manifiestos relacionados que están vinculados con la identidad y los elementos de dependencia. Luego, para cada elemento de archivo contenido en los archivos de manifiesto, agrega una entrada en el contexto de activación:
''name attribute of file element'' -> ''absolute path of manifest file'' + ''name attribute of file element''
Ahora cuando se realiza una llamada a la biblioteca de carga, busca en el mapa de contexto de activación una clave que coincida con el argumento de ruta de la biblioteca de carga, y luego carga la biblioteca con el valor de esa clave.
Entonces, si mi aplicación c: / foo / foo.exe tiene una dependencia al manifiesto en c: / foo / baa / baa.manifest, y baa.manifest contiene un elemento de <file name="empty.dll"/>
, entonces el contexto de activación tendrá una asignación: "empty.dll" -> "c:/foo/baa/empty.dll"
Entonces cualquier llamada a LoadLibrary("empty.dll")
se redirigirá a LoadLibrary("C:/foo/baa/empty.dll")
.
Sin embargo, LoadLibrary("c:/anotherpath/empty.dll")
no será redirigido.
Ahora para demostrar mi punto de lo estúpidamente simple que son los archivos manifiestos y los contextos de activación. Si el elemento de archivo de baa.manifest era <file name="c:/anotherpath/empty.dll"/>
e hizo una LoadLibrary("C:/anotherpath/empty.dll")
a LoadLibrary("C:/anotherpath/empty.dll")
, se redireccionará la llamada LoadLibrary a LoadLibrary("C:/foo/baa/C:/anotherpath/empty.dll")
, sí, una ruta de acceso mal formada ...
El elemento de archivo tiene un atributo no documentado llamado "loadFrom", que hace lo que parece, y parece que es perfecto para resolver este problema. Usando loadFrom, pude redirigir una ruta de acceso absoluta loadlibrary llamada, pero parecía arruinar otras dependencias en el ejecutable de maneras extrañas. Si alguien sabe más acerca de cómo funciona "loadFrom", estaría muy interesado.
Entonces, ¿cómo resolví mi problema al final? Mediante el uso de un enfoque increíblemente pesado de DLL Trojaning descrito en Ethical Hacker . Básicamente, crea un kernel32.dll ficticio que redirige todas las llamadas al kenerl32.dll original, a excepción de las llamadas LoadLibrary, en las que coloca su propia lógica de redirección. Luego, en el manifiesto de aplicaciones, coloca un elemento de archivo que redirige el Kernel32.dll a su variable ficticia. Divertido.
Todo esto describe mis experimentos en Windows Xp Sp2. Para mayor diversión, me hacen creer que los manifiestos se comportan de manera diferente en casi todas las versiones de Windows.
Ok, necesitas configurarlo de esta manera:
-
c:/apppath/testapp.exe
- el archivo exe de la aplicación de prueba -
c:/apppath/testapp.exe.manifest
- el - archivo de manifiesto de aplicación potencialmente incrustado -
c:/apppath/EmptyAssm/EmptyAssm.manifest
- Un manifiesto que describe su nuevo conjunto. -
c:/apppath/EmptyAssm/empty.dll
- el dll de ensamblaje -
c:/apppath/EmptyAssm/empty.dll.2.manifest
- el manifiesto incrustado en el dll
Por lo tanto, tiene su aplicación de prueba que contiene un manifiesto de aplicación: que contiene referencias de ensamblaje dependientes para la aplicación, incluida una que agrega a su ensamblado dll personalizado.
En la subcarpeta assm de la carpeta de aplicaciones de la carpeta de la aplicación, tiene el manifiesto de ensamblaje del ensamblado "EmptyAssm", que contiene un nodo de archivo que hace referencia al dll real, "empty.dll".
empty.dll incorpora su propio manifiesto, que contiene referencias de ensamblado dependientes en cualquier ensamblado público o privado que requiera.
Este es el punto importante: el manifiesto de ensamblaje "EmptyAssm" y los manifiestos dll "vacíos" son potencialmente diferentes. El archivo de manifiesto del ensamblado ("EmptyAssm") NO DEBE incrustarse, pero puede compartir el nombre del manifiesto dll SI elige nombrar su manifiesto por el nombre de la dll.
Ahora, cuando el cargador carga su EXE, carga el manifiesto de su EXE y lo agrega al contexto de activación. Cuando se procesa la tabla de importación del EXE, o se llama a LoadLibrary, el cargador primero busca en el contexto de activación un manifiesto de ensamblaje con un nodo de archivo coincidente. Si encuentra un ensamblado correspondiente, ENTONCES procesa y carga el dll desde la ubicación del ensamblaje (la carpeta que contiene los ensamblajes .manifest) y puede, en este momento, si no hay un manifiesto incrustado en el dll Y el dll y el manifiesto tienen el mismo nombre, reutiliza el mismo archivo de manifiesto para configurar el contexto de activación de la dll.
SI desea colocar el manifiesto "emptyassm", y dll, en una carpeta diferente a la carpeta de la aplicación, Y si está orientando Windows Server 2008, o Windows 7, o posterior, puede agregar un archivo de configuración para su aplicación: -
-
c:/apppath/testapp.exe.config
- archivo de configuración de la aplicación
El archivo de configuración de la aplicación puede contener un nodo de sondeo debajo del nodo assemblyBinding
(los archivos de configuración se parecen mucho a los archivos de manifiesto), con privatePath="some relative path"
. En tal caso, se buscará ensamblados en la carpeta relativa.
Mi última respuesta aquí tiene archivos de ejemplo que cubren el proceso de crear un ensamblado desde un dll, y hacer referencia a él desde un exe: - Una forma de cargar DLL desde el repositorio central
Solo para aclarar: Un ensamblaje de win32 es (en su forma más simple) un archivo de manifiesto que describe el ensamblado y un dll. Siempre están, en este modelo, ubicados en la misma carpeta, por lo que el nodo de archivo del manifiesto no puede contener ninguna información de ruta: solo el nombre de la DLL.
Los ensambles se pueden compartir, dándoles una versión fuerte (y alguna firma digital) e instalándolos en Windows / WinSxS, o en privado.
Las versiones de Windows anteriores a la 5.1 (Win XP) no buscarán ensambles ya que esta tecnología solo se agregó en XP. Windows 5.1 a 6.0 (XP y Vista) solo buscará ensamblajes privados en la carpeta del objeto con el contexto de activación activo: - Si un exe hace referencia a un ensamblado, entonces la carpeta que contiene el exe. Si el código en un dll hace referencia a un ensamblaje, se busca en la carpeta del dll.
Si desea almacenar su dll en una ubicación privada compartida por varias aplicaciones (por ejemplo) DEBE tener un requisito de Windows 7 o posterior: -
Windows versión 6.1 (también conocido como Windows Server 2008 o Windows 7) y más tarde, además de la carpeta del módulo, buscará en la ruta especificada como el elemento privatePath del elemento de prueba en un archivo de configuración de la aplicación. Los archivos de configuración de la aplicación siempre están en la misma carpeta que el exe o dll, y se nombran:
<exename>.exe.config
, o <dllname>.dll.2.config
(La razón para el .2 es que hay potencialmente muchos manifiestos y configuraciones integrados como recursos, y el cargador se reserva los recursos de los identificadores 1 ... 15. Al buscar en el disco un manifiesto de archivo de configuración, si el ID del recurso del el recurso incrustado hubiera sido 1, se omite la identificación, pero cualquier otro número significa que se convierte en parte del nombre del archivo).