Definido por Microsoft para su uso en versiones recientes de Windows , un ensamblado en Common Language Infrastructure (CLI) es una biblioteca de código compilado que se utiliza para la implementación, el control de versiones y la seguridad. Hay dos tipos: ensamblados de proceso ( EXE ) y ensamblados de biblioteca ( DLL ). Un ensamblado de proceso representa un proceso que utilizará clases definidas en ensamblados de biblioteca. Los ensamblados CLI contienen código en CIL , que generalmente se genera a partir de un lenguaje CLI y luego se compila en lenguaje de máquina en tiempo de ejecución por el compilador Just-in-Time . En la implementación de .NET Framework , este compilador es parte de Common Language Runtime (CLR).
Un ensamblaje puede estar formado por uno o más archivos. Los archivos de código se denominan módulos. Un ensamblaje puede contener más de un módulo de código. Y dado que es posible utilizar distintos lenguajes para crear módulos de código, técnicamente es posible utilizar varios lenguajes diferentes para crear un ensamblaje. Sin embargo, Visual Studio no admite el uso de distintos lenguajes en un ensamblaje.
El nombre de una asamblea consta de cuatro partes
El token de clave pública se utiliza para hacer que el nombre del ensamblado sea único. Por lo tanto, dos ensamblados con un nombre seguro pueden tener el mismo nombre de archivo PE y, sin embargo, la CLI los reconocerá como ensamblados diferentes. El sistema de archivos de Windows ( FAT32 y NTFS ) solo reconoce el nombre de archivo PE, por lo que dos ensamblados con el mismo nombre de archivo PE (pero con diferente cultura, versión o token de clave pública) no pueden existir en la misma carpeta de Windows. Para resolver este problema, la CLI presenta la GAC ( caché de ensamblados global ) que se trata como una sola carpeta en tiempo de ejecución, pero que en realidad se implementa utilizando carpetas del sistema de archivos anidadas.
Para evitar ataques de suplantación de identidad , en los que un pirata informático intentaría hacer pasar un ensamblaje como algo distinto, el ensamblaje se firma con una clave privada. El desarrollador del ensamblaje previsto mantiene en secreto la clave privada, por lo que un pirata informático no puede tener acceso a ella ni simplemente adivinarla. Por lo tanto, el pirata informático no puede hacer que su ensamblaje se haga pasar por otra cosa, sin la posibilidad de firmarlo correctamente después del cambio. Firmar el ensamblaje implica tomar un hash de partes importantes del ensamblaje y luego cifrar el hash con la clave privada. El hash firmado se almacena en el ensamblaje junto con la clave pública. La clave pública descifrará el hash firmado. Cuando el CLR carga un ensamblaje con un nombre seguro, generará un hash a partir del ensamblaje y luego lo comparará con el hash descifrado. Si la comparación tiene éxito, significa que la clave pública en el archivo (y, por lo tanto, el token de clave pública) está asociada con la clave privada utilizada para firmar el ensamblaje. Esto significará que la clave pública en el ensamblaje es la clave pública del editor del ensamblaje y, por lo tanto, se evita un ataque de suplantación de identidad.
Los ensambles CLI pueden tener información de versión, lo que les permite eliminar la mayoría de los conflictos entre aplicaciones causados por ensambles compartidos. [2] Sin embargo, esto no elimina todos los posibles conflictos de versiones entre ensambles. [3]
La seguridad de acceso al código CLI se basa en ensamblajes y evidencia . La evidencia puede ser cualquier cosa deducida del ensamblaje, pero normalmente se crea a partir de la fuente del ensamblaje, ya sea que el ensamblaje se haya descargado de Internet, una intranet o instalado en la máquina local (si el ensamblaje se descarga de otra máquina, se almacenará en una ubicación aislada dentro del GAC y, por lo tanto, no se tratará como si se hubiera instalado localmente). Los permisos se aplican a ensamblajes completos y un ensamblaje puede especificar los permisos mínimos que requiere a través de atributos personalizados (consulte los metadatos de CLI ). Cuando se carga el ensamblaje, el CLR usará la evidencia del ensamblaje para crear un conjunto de permisos de uno o más permisos de acceso al código. Luego, el CLR verificará para asegurarse de que este conjunto de permisos contenga los permisos requeridos especificados por el ensamblaje.
El código CLI puede ejecutar una demanda de seguridad de acceso al código. Esto significa que el código ejecutará alguna acción privilegiada solo si todos los ensambles de todos los métodos en la pila de llamadas tienen el permiso especificado. Si un ensamble no tiene el permiso, se genera una excepción de seguridad.
El código CLI también puede ejecutar una demanda vinculada para obtener el permiso de la pila de llamadas. En este caso, el CLR buscará solo un método en la pila de llamadas en la posición TOP para el permiso especificado. Aquí, el recorrido por la pila está vinculado a un método en la pila de llamadas por el cual el CLR supone que todos los demás métodos en la PILA DE LLAMADAS tienen el permiso especificado. El ensamblaje es una combinación de METADATA y archivo MSIL.
En general, los ensamblados deben contener recursos neutrales en cuanto a la cultura. Si desea localizar su ensamblado (por ejemplo, usar diferentes cadenas para diferentes configuraciones regionales), debe usar ensamblados satélite: ensamblados especiales que solo contienen recursos. Como sugiere el nombre, un satélite está asociado con un ensamblado llamado ensamblado principal. Ese ensamblado (por ejemplo, lib.dll) contendrá los recursos neutrales (que Microsoft dice que es inglés internacional , pero implica que es inglés de EE. UU.). Cada satélite tiene el nombre de la biblioteca asociada adjunto con .resources (por ejemplo, lib.resources.dll). Al satélite se le asigna un nombre de cultura no neutral, pero como los sistemas de archivos de Windows existentes (FAT32 y NTFS) lo ignoran, esto significaría que podría haber varios archivos con el mismo nombre de PE en una carpeta. Como esto no es posible, los satélites deben almacenarse en subcarpetas dentro de la carpeta de la aplicación. Por ejemplo, un satélite con recursos en inglés del Reino Unido tendrá un nombre CLI de "lib.resources Version=0.0.0.0 Culture=en-GB PublicKeyToken=null", un nombre de archivo PE de lib.resources.dll y se almacenará en una subcarpeta llamada en-GB.
Los satélites se cargan mediante una clase CLI llamada System.Resources.ResourceManager
. El desarrollador debe proporcionar el nombre del recurso e información sobre el ensamblaje principal (con los recursos neutrales). La clase ResourceManager leerá la configuración regional de la máquina y utilizará esta información y el nombre del ensamblaje principal para obtener el nombre del satélite y el nombre de la subcarpeta que lo contiene. ResourceManager
Luego, puede cargar el satélite y obtener el recurso localizado.
Se puede hacer referencia a una biblioteca de código ejecutable utilizando el indicador /reference del compilador de C#.
Los ensamblajes compartidos deben tener un nombre seguro para identificar de forma única el ensamblaje que se puede compartir entre las aplicaciones. El nombre seguro consta del token de clave pública, la cultura, la versión y el nombre del archivo PE. Si es probable que se utilice un ensamblaje para fines de desarrollo que sea un ensamblaje compartido, el procedimiento de nombre seguro solo incluye la generación de clave pública. La clave privada no se genera en ese momento. Se genera solo cuando se implementa el ensamblaje.
El ensamblado se construye con el código CIL, que es un lenguaje intermedio. El framework convierte internamente el CIL ( bytecode ) en código ensamblador nativo . Si tenemos un programa que imprime "Hola mundo", el código CIL equivalente para el método es:
. método privado hidebysig static void Main ( string [] args ) cil administrado { . punto de entrada . instancia personalizada void [ mscorlib ] System . STAThreadAttribute ::. ctor () = ( 01 00 00 00 ) // Tamaño del código 11 (0xb) . maxstack 1 IL_0000 : ldstr "Hola mundo" IL_0005 : llamada void [ mscorlib ] System . Console :: WriteLine ( string ) IL_000a : ret } // fin del método Class1::Main
El código CIL carga la cadena en la pila, luego llama a la función WriteLine y regresa.