Como determinar se um assembly .NET foi criado para x86 ou x64?

Eu tenho uma lista arbitrária de assemblies .net.

Eu preciso verificar programaticamente se cada DLL foi criada para x86 (em oposição a x64 ou qualquer CPU). Isso é possível?

Olhe para System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Você pode examinar os metadados de assembly da instância do AssemblyName retornada:

Usando o PowerShell :

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

 Nome: Microsoft.GLEE
 Versão: 1.0.0.0
 CultureInfo:
 CodeBase: arquivo: /// C: / projects / powershell / BuildAnalyzer / ...
 EscapedCodeBase: file: /// C: / projetos / powershell / BuildAnalyzer / ...
 ProcessadorArquitetura: MSIL
 Sinalizadores: PublicKey
 HashAlgorithm: SHA1
 VersãoCompatibilidade: SameMachine
 KeyPair:
 FullName: Microsoft.GLEE, versão = 1.0.0.0, Culture = neut ... 

Aqui, o ProcessorArchitecture identifica a plataforma de destino.

Estou usando o PowerShell neste exemplo para chamar o método.

Você pode usar a ferramenta CLI CorFlags (por exemplo, C: \ Arquivos de Programas \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) para determinar o status de um assembly, com base em sua saída e abrindo um assembly como um binário você deve ser capaz de determinar onde você precisa procurar para determinar se o sinalizador 32BIT está definido como 1 ( x86 ) ou 0 ( qualquer CPU ou x64 , dependendo do PE ):

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

O post do blog x64 Development with .NET tem algumas informações sobre o corflags .

Melhor ainda, você pode usar Module.GetPEKind para determinar se um assembly é um valor de PE32Plus (64 bits), Required32Bit (32 bits e WOW) ou ILOnly (qualquer CPU) juntamente com outros atributos de ILOnly .

Apenas para esclarecimento, o CorFlags.exe faz parte do .NET Framework SDK . Eu tenho as ferramentas de desenvolvimento na minha máquina, e a maneira mais simples para mim determinar se uma DLL é de 32 bits é:

  1. Abra o prompt de comando do Visual Studio (No Windows: menu Iniciar / Programas / Microsoft Visual Studio / Ferramentas do Visual Studio / Prompt de comando do Visual Studio 2008)

  2. CD para o diretório que contém a DLL em questão

  3. Corflags Run como este: corflags MyAssembly.dll

Você obterá algo assim:

  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 

Conforme os comentários, as sinalizações acima devem ser lidas da seguinte forma:

  • Qualquer CPU: PE = PE32 e 32BIT = 0
  • x86: PE = PE32 e 32BIT = 1
  • 64 bits: PE = PE32 + e 32BIT = 0

Que tal você apenas escrever seu próprio? O núcleo da arquitetura de PE não foi seriamente alterado desde sua implementação no Windows 95. Aqui está um exemplo 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; } } 

Agora as constantes atuais são:

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

Mas com este método permite as possibilidades de novas constantes, apenas valide o retorno como achar melhor.

Tente usar CorFlagsReader deste projeto no CodePlex . Não tem referências a outros conjuntos e pode ser usado como está.

 [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); } } 

Abaixo está um arquivo em lote que executará corflags.exe em todas as dlls e exes no diretório de trabalho atual e em todos os subdiretórios, analisará os resultados e exibirá a arquitetura de destino de cada um.

Dependendo da versão do corflags.exe usada, os itens de linha na saída includeão 32BIT ou 32BITREQ (e 32BITPREF ). Qualquer um desses dois está incluído na saída é o item de linha crítico que deve ser verificado para diferenciar entre Any CPU e x86 . Se você estiver usando uma versão mais antiga do corflags.exe (pré Windows SDK v8.0A), somente o item de linha 32BIT estará presente na saída, como outros indicaram nas respostas anteriores. Caso contrário, 32BITREQ e 32BITPREF substituem.

Isso pressupõe que o corflags.exe esteja no %PATH% . A maneira mais simples de garantir isso é usar um Developer Command Prompt . Como alternativa, você pode copiá-lo do local padrão .

Se o arquivo em lotes abaixo for executado em um dll ou exe não gerenciado, ele será exibido incorretamente como x86 , já que a saída real do Corflags.exe será uma mensagem de erro semelhante a:

corflags: erro CF008: O arquivo especificado não possui um header gerenciado 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 da JetBrians fornece uma maneira rápida e fácil de ver msil (anycpu), x86, x64 dotPeek

Outra maneira de verificar a plataforma de destino de um assembly .NET é inspecionar o assembly com o .NET Reflector …

@ # ~ # € ~! Acabei de perceber que a nova versão não é gratuita! Então, correção, se você tem uma versão gratuita do refletor .NET, você pode usá-lo para verificar a plataforma de destino.

cfeduke observa a possibilidade de chamar GetPEKind. É potencialmente interessante fazer isso a partir do PowerShell.

Aqui, por exemplo, é o código de um cmdlet que pode ser usado: https://stackoverflow.com/a/16181743/64257

Como alternativa, em https://stackoverflow.com/a/4719567/64257 , é observado que “há também o cmdlet Get-PEHeader nas Extensões da Comunidade do PowerShell que podem ser usadas para testar imagens executáveis”.

Uma aplicação mais avançada para isso você pode encontrar aqui: CodePlex – ApiChange

Exemplos:

 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 

Mais uma maneira seria usar o dumpbin das ferramentas do Visual Studio na DLL e procurar a saída apropriada

 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: Acima de o / p é para 32bit dll

Mais uma opção útil com o dumpbin.exe é / EXPORTS, ele mostrará a function exposta pela dll

 dumpbin.exe /EXPORTS  

Maneira mais genérica – use a estrutura de arquivos para determinar o bitness e o tipo de imagem:

 public static CompilationMode GetCompilationMode(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 CompilationMode.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 CompilationMode.Invalid; //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24); var result = CompilationMode.Invalid; uint clrHeaderSize; if (magic == 0x10b) { clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4); result |= CompilationMode.Bit32; } else if (magic == 0x20b) { clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4); result |= CompilationMode.Bit64; } else return CompilationMode.Invalid; result |= clrHeaderSize != 0 ? CompilationMode.CLR : CompilationMode.Native; return result; } finally { if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr); } } 

Enumeração do modo de compilation

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

Código-fonte com explicação no GitHub

Eu clonei uma ferramenta super acessível que adiciona uma input de menu de contexto para assemblies no Windows Explorer para mostrar todas as informações disponíveis:

Baixe aqui: https://github.com/tebjan/AssemblyInformation/releases

insira a descrição da imagem aqui