¿Cómo determinar si un ensamblado .NET fue desarrollado para x86 o x64?

Tengo una lista arbitraria de ensamblados .NET.

Necesito comprobar programáticamente si cada DLL se construyó para x86 (a diferencia de x64 o cualquier CPU). es posible?

Mire System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Puede examinar los metadatos del ensamblado a partir de la instancia de AssemblyName devuelta:

Usando PowerShell :

 [36] C: \> [reflection.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") |  Florida

 Nombre: Microsoft.GLEE
 Versión: 1.0.0.0
 CultureInfo:
 CodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ...
 EscapedCodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ...
 ProcesadorArquitectura: MSIL
 Banderas: PublicKey
 HashAlgorithm: SHA1
 VersionCompatibility: SameMachine
 Par de claves :
 FullName: Microsoft.GLEE, Version = 1.0.0.0, Culture = neut ... 

Aquí, ProcessorArchitecture identifica la plataforma objective.

Estoy usando PowerShell en este ejemplo para llamar al método.

Puede usar la herramienta CorFlags CLI (por ejemplo, C: \ Archivos de progtwig \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) para determinar el estado de un ensamblaje, en función de su salida y abrir un ensamblaje como un activo binario, usted debería poder determinar dónde necesita buscar para determinar si el indicador 32BIT está establecido en 1 ( x86 ) o 0 ( Cualquier CPU o x64 , dependiendo de PE ):

 Option | PE | 32BIT ----------|-------|--------- x86 | PE32 | 1 Any CPU | PE32 | 0 x64 | PE32+ | 0 

La publicación de blog x64 Development with .NET contiene información sobre corflags .

Incluso mejor, puede usar Module.GetPEKind para determinar si un ensamblado es PortableExecutableKinds value PE32Plus (64 bits), Required32Bit (32 bits y WOW), o ILOnly (cualquier CPU) junto con otros atributos.

Solo por aclaración, CorFlags.exe es parte del .NET Framework SDK . Tengo las herramientas de desarrollo en mi máquina, y la forma más simple para mí de determinar si una DLL es de 32 bits es:

  1. Abra el símbolo del sistema de Visual Studio (en Windows: menú Inicio / Progtwigs / Microsoft Visual Studio / Visual Studio Tools / Símbolo del sistema de Visual Studio 2008)

  2. CD al directorio que contiene el archivo DLL en cuestión

  3. Ejecutar corflags como este: corflags MyAssembly.dll

Obtendrás una salida como esta:

  Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 3.5.21022.8 Copyright (c) Microsoft Corporation. All rights reserved. Version : v2.0.50727 CLR Header: 2.5 PE : PE32 CorFlags : 3 ILONLY : 1 32BIT : 1 Signed : 0 

Según los comentarios, los indicadores anteriores se deben leer de la siguiente manera:

  • Cualquier CPU: PE = PE32 y 32BIT = 0
  • x86: PE = PE32 y 32BIT = 1
  • 64 bits: PE = PE32 + y 32BIT = 0

¿Qué tal si solo te escribes? El núcleo de la architecture PE no ha cambiado mucho desde su implementación en Windows 95. Aquí hay un ejemplo de C #:

  public static ushort GetPEArchitecture(string pFilePath) { ushort architecture = 0; try { using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream)) { if (bReader.ReadUInt16() == 23117) //check the MZ signature { fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew. fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header. if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature. { fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header, architecture = bReader.ReadUInt16(); //read the magic number of the optional header. } } } } } catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */} //if architecture returns 0, there has been an error. return architecture; } } 

Ahora las constantes actuales son:

 0x10B - PE32 format. 0x20B - PE32+ format. 

Pero con este método permite las posibilidades de nuevas constantes, simplemente valide la devolución como mejor le parezca.

Intenta usar CorFlagsReader desde este proyecto en CodePlex . No tiene referencias a otros ensambles y puede usarse tal cual.

 [TestMethod] public void EnsureKWLLibrariesAreAll64Bit() { var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(x => x.FullName.StartsWith("YourCommonProjectName")).ToArray(); foreach (var assembly in assemblies) { var myAssemblyName = AssemblyName.GetAssemblyName(assembly.FullName.Split(',')[0] + ".dll"); Assert.AreEqual(ProcessorArchitecture.MSIL, myAssemblyName.ProcessorArchitecture); } } 

A continuación se muestra un archivo de proceso por lotes que ejecutará corflags.exe contra todos los dlls corflags.exe y exes en el directorio de trabajo actual y todos los subdirectorios, analizará los resultados y mostrará la architecture de destino de cada uno.

Dependiendo de la versión de corflags.exe que se use, las líneas de pedido en la salida incluirán 32BIT o 32BITREQ (y 32BITPREF ). Cualquiera de estos dos incluidos en la salida es la línea crítica que se debe verificar para diferenciar entre Any CPU y x86 . Si está utilizando una versión anterior de corflags.exe (anterior a Windows SDK v8.0A), solo la línea de pedido de 32BIT estará presente en el resultado, como otros han indicado en las respuestas anteriores. De 32BITREQ contrario, 32BITREQ y 32BITPREF reemplazan.

Esto supone que corflags.exe está en %PATH% . La forma más sencilla de garantizar esto es utilizar un Developer Command Prompt . Alternativamente, puede copiarlo desde su ubicación predeterminada .

Si el archivo de proceso por lotes a continuación se ejecuta en un dll o exe no administrado, lo mostrará incorrectamente como x86 , ya que el resultado real de Corflags.exe será un mensaje de error similar al siguiente:

corflags: error CF008: el archivo especificado no tiene un encabezado administrado válido

 @echo off echo. echo Target architecture for all exes and dlls: echo. REM For each exe and dll in this directory and all subdirectories... for %%a in (.exe, .dll) do forfiles /s /m *%%a /c "cmd /c echo @relpath" > testfiles.txt for /f %%b in (testfiles.txt) do ( REM Dump corflags results to a text file corflags /nologo %%b > corflagsdeets.txt REM Parse the corflags results to look for key markers findstr /C:"PE32+">nul .\corflagsdeets.txt && ( REM `PE32+` indicates x64 echo %%~b = x64 ) || ( REM pre-v8 Windows SDK listed only "32BIT" line item, REM newer versions list "32BITREQ" and "32BITPREF" line items findstr /C:"32BITREQ : 0">nul /C:"32BIT : 0" .\corflagsdeets.txt && ( REM `PE32` and NOT 32bit required indicates Any CPU echo %%~b = Any CPU ) || ( REM `PE32` and 32bit required indicates x86 echo %%~b = x86 ) ) del corflagsdeets.txt ) del testfiles.txt echo. 

DotPeek de JetBrians proporciona una forma rápida y sencilla de ver msil (anycpu), x86, x64 dotPeek

Otra forma de comprobar la plataforma de destino de un ensamblado .NET es inspeccionar el ensamblaje con .NET Reflector …

@ # ~ # € ~! ¡Me acabo de dar cuenta de que la nueva versión no es gratis! Entonces, corrección, si tiene una versión gratuita de .NET reflector, puede usarla para verificar la plataforma de destino.

cfeduke nota la posibilidad de llamar a GetPEKind. Es potencialmente interesante hacer esto desde PowerShell.

Aquí, por ejemplo, está el código de un cmdlet que podría usarse: https://stackoverflow.com/a/16181743/64257

Alternativamente, en https://stackoverflow.com/a/4719567/64257 se señala que “también está el cmdlet Get-PEHeader en las extensiones de comunidad de PowerShell que se puede usar para probar imágenes ejecutables”.

Una aplicación más avanzada para que pueda encontrar aquí: CodePlex – ApiChange

Ejemplos:

 C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\winhlp32.exe File Name; Type; Size; Processor; IL Only; Signed winhlp32.exe; Unmanaged; 296960; X86 C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\HelpPane.exe File Name; Type; Size; Processor; IL Only; Signed HelpPane.exe; Unmanaged; 733696; Amd64 

Una forma más sería usar dumpbin desde las herramientas de Visual Studio en DLL y buscar el resultado apropiado

 dumpbin.exe /HEADERS  FILE HEADER VALUE 14C machine (x86) 4 number of sections 5885AC36 time date stamp Mon Jan 23 12:39:42 2017 0 file pointer to symbol table 0 number of symbols E0 size of optional header 2102 characteristics Executable 32 bit word machine DLL 

Nota: Por encima de o / p es para dbit de 32 bits

Una opción más útil con dumpbin.exe es / EXPORTS, le mostrará la función expuesta por el DLL

 dumpbin.exe /EXPORTS  

De forma más genérica: use la estructura de archivos para determinar el bitness y el tipo de imagen:

 public static ComstacktionMode GetComstacktionMode(this FileInfo info) { if (!info.Exists) throw new ArgumentException($"{info.FullName} does not exist"); var intPtr = IntPtr.Zero; try { uint unmanagedBufferSize = 4096; intPtr = Marshal.AllocHGlobal((int)unmanagedBufferSize); using (var stream = File.Open(info.FullName, FileMode.Open, FileAccess.Read)) { var bytes = new byte[unmanagedBufferSize]; stream.Read(bytes, 0, bytes.Length); Marshal.Copy(bytes, 0, intPtr, bytes.Length); } //Check DOS header magic number if (Marshal.ReadInt16(intPtr) != 0x5a4d) return ComstacktionMode.Invalid; // This will get the address for the WinNT header var ntHeaderAddressOffset = Marshal.ReadInt32(intPtr + 60); // Check WinNT header signature var signature = Marshal.ReadInt32(intPtr + ntHeaderAddressOffset); if (signature != 0x4550) return ComstacktionMode.Invalid; //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24); var result = ComstacktionMode.Invalid; uint clrHeaderSize; if (magic == 0x10b) { clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4); result |= ComstacktionMode.Bit32; } else if (magic == 0x20b) { clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4); result |= ComstacktionMode.Bit64; } else return ComstacktionMode.Invalid; result |= clrHeaderSize != 0 ? ComstacktionMode.CLR : ComstacktionMode.Native; return result; } finally { if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr); } } 

Enumeración del modo de comstackción

 [Flags] public enum ComstacktionMode { Invalid = 0, Native = 0x1, CLR = Native < < 1, Bit32 = CLR << 1, Bit64 = Bit32 << 1 } 

Código fuente con explicación en GitHub

He clonado una herramienta muy práctica que agrega una entrada del menú contextual para ensambles en el explorador de Windows para mostrar toda la información disponible:

Descargue aquí: https://github.com/tebjan/AssemblyInformation/releases

enter image description here