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




assemblies 64bit (10)

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?


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 incluirã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 cabeçalho 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.

Apenas para esclarecimentos, 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ê terá uma saída 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


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

dumpbin.exe /HEADERS <your dll path>
    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

Uma opção mais útil com o dumpbin.exe é / EXPORTS, ele mostrará a função exposta pela dll

dumpbin.exe /EXPORTS <PATH OF THE DLL>

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.


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 esse método, ele permite as possibilidades de novas constantes, apenas valide o retorno como achar melhor.


Uma aplicação mais avançada para isso que 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

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 é o valor de PE32Plus (64 bits), Required32Bit (32 bits e WOW) ou ILOnly (qualquer CPU) junto com outros atributos de ILOnly .


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

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

Usando o PowerShell :

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

Name                  : Microsoft.GLEE
Version               : 1.0.0.0
CultureInfo           :
CodeBase              : file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase       : file:///C:/projects/powershell/BuildAnalyzer/...
ProcessorArchitecture : MSIL
Flags                 : PublicKey
HashAlgorithm         : SHA1
VersionCompatibility  : SameMachine
KeyPair               :
FullName              : Microsoft.GLEE, Version=1.0.0.0, Culture=neut... 

Aqui, o ProcessorArchitecture identifica a plataforma de destino.

  • Amd64 : Um processador de 64 bits baseado na arquitetura x64.
  • Arm : Um processador ARM.
  • IA64 : apenas um processador Intel Itanium de 64 bits.
  • MSIL : Neutra em relação ao processador e bits por palavra.
  • X86 : Um processador Intel de 32 bits, nativo ou no ambiente Windows on Windows em uma plataforma de 64 bits (WOW64).
  • Nenhum : Uma combinação desconhecida ou não especificada de processador e bits por palavra.

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


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




x86-64