Как определить, была ли сборка.NET построена для x86 или x64?

У меня есть произвольный список сборок.NET.

Мне нужно программно проверить, была ли каждая DLL построена для x86 (в отличие от x64 или любого процессора). Это возможно?

16 ответов

Решение

Смотреть на System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Вы можете проверить метаданные сборки из возвращенного экземпляра AssemblyName:

Использование PowerShell:

[36] C: \> [mirror.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | Флорида

Имя: Microsoft.GLEE
Версия: 1.0.0.0
CultureInfo:
CodeBase: файл:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase: file:///C:/projects/powershell/BuildAnalyzer/...Архитектура процессора: MSIL Флаги: PublicKey
HashAlgorithm: SHA1
Совместимость с версиями: SameMachine
KeyPair:
FullName: Microsoft.GLEE, Версия =1.0.0.0, Культура = Нейт... 

Здесь ProcessorArchitecture определяет целевую платформу.

  • Amd64: 64-разрядный процессор на основе архитектуры x64.
  • Рука: процессор ARM.
  • IA64: только 64-разрядный процессор Intel Itanium.
  • MSIL: Нейтрально по отношению к процессору и битам на слово.
  • X86: 32-разрядный процессор Intel, встроенный или в среде Windows на Windows, на 64-разрядной платформе (WOW64).
  • Нет: неизвестная или неопределенная комбинация процессора и битов на слово.

В этом примере я использую PowerShell для вызова метода.

Вы можете использовать инструмент CLI CorFlags (например, C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe), чтобы определить состояние сборки на основе ее вывода и открытия сборки как двоичный актив, вы должны быть в состоянии определить, где вам нужно искать, чтобы определить, установлен ли флаг 32BIT 1 (x86) или 0 (любой процессор или x64, в зависимости от PE):

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

В блоге x64 Development с.NET есть некоторая информация о corflags,

Даже лучше, вы можете использовать Module.GetPEKind определить, является ли сборка PortableExecutableKinds значение PE32Plus (64-битный), Required32Bit (32-битный и WOW), или ILOnly (любой процессор) вместе с другими атрибутами.

Просто для пояснения, CorFlags.exe является частью .NET Framework SDK. У меня есть инструменты разработки на моей машине, и самый простой способ определить, является ли библиотека DLL 32-разрядной, состоит в следующем:

  1. Откройте командную строку Visual Studio (в Windows: меню Пуск / Программы /Microsoft Visual Studio/ Инструменты Visual Studio / Командная строка Visual Studio 2008)

  2. Компакт-диск в каталог, содержащий DLL

  3. Запустите corflags, как это:corflags MyAssembly.dll

Вы получите вывод примерно так:

    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

В соответствии с комментариями флаги выше должны читаться следующим образом:

  • Любой процессор: PE = PE32 и 32BIT = 0
  • x86: PE = PE32 и 32BIT = 1
  • 64-разрядный: PE = PE32+ и 32BIT = 0

Как насчет того, чтобы написать себе? Ядро архитектуры PE не претерпело серьезных изменений с момента ее реализации в Windows 95. Вот пример 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;
    }
}

Теперь текущие константы:

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

Но с помощью этого метода он учитывает возможности новых констант, просто проверяйте возвращаемость по своему усмотрению.

DotPeek от JetBrians обеспечивает быстрый и простой способ просмотра msil(anycpu), x86, x64 dotPeek

Попробуйте использовать CorFlagsReader из этого проекта на CodePlex. Он не имеет ссылок на другие сборки и может использоваться как есть.

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

Ниже приведен командный файл, который будет работать corflags.exe против всех dlls а также exes в текущем рабочем каталоге и во всех подкаталогах проанализируйте результаты и отобразите целевую архитектуру каждого из них.

В зависимости от версии corflags.exe что используется, позиции в выводе будут включать 32BITили 32BITREQ (а также 32BITPREF). Независимо от того, что из этих двух включено в выходные данные, это критическая позиция, которая должна быть проверена, чтобы различать Any CPU а также x86, Если вы используете более старую версию corflags.exe (до Windows SDK v8.0A), затем только 32BIT позиция будет присутствовать в выводе, как другие указали в предыдущих ответах. Иначе 32BITREQ а также 32BITPREF замени это.

Это предполагает corflags.exe находится в %PATH%, Самый простой способ убедиться в этом - использовать Developer Command Prompt, В качестве альтернативы вы можете скопировать его из расположения по умолчанию.

Если приведенный ниже пакетный файл запускается с неуправляемым dll или же exeбудет неправильно отображаться как x86, поскольку фактический выход из Corflags.exe будет сообщение об ошибке, похожее на:

corflags: ошибка CF008: указанный файл не имеет допустимого управляемого заголовка

@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.

Я клонировал очень удобный инструмент, который добавляет пункт контекстного меню для сборок в проводнике Windows, чтобы показать всю доступную информацию:

Загрузить здесь: https://github.com/tebjan/AssemblyInformation/releases

Более продвинутое приложение для этого вы можете найти здесь: CodePlex - ApiChange

Примеры:

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

Более общий способ - используйте файловую структуру для определения битности и типа изображения:

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

Перечисление в режиме компиляции

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

Исходный код с пояснениями на GitHub

Еще одним способом было бы использовать dumpbin из инструментов Visual Studio для DLL и искать соответствующий вывод

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

Примечание: выше o/p для 32-битных DLL

Еще одна полезная опция с dumpbin.exe - это /EXPORTS, она покажет вам функцию, предоставляемую DLL

dumpbin.exe /EXPORTS <PATH OF THE DLL>

Еще один способ проверить целевую платформу сборки.NET - это проверка сборки с помощью .NET Reflector...

@ # ~ # ~ €! Я только что понял, что новая версия не бесплатна! Итак, исправление: если у вас есть бесплатная версия.NET рефлектора, вы можете использовать ее для проверки целевой платформы.

cfeduke отмечает возможность вызова GetPEKind. Это потенциально интересно сделать из PowerShell.

Вот, например, код для командлета, который можно использовать: /questions/6735703/kak-opredelit-byila-li-sborkanet-skompilirovana-kak-x86-x64-ili-lyuboj-protsessor/6735728#6735728

В качестве альтернативы на /questions/30647482/kak-opredelit-dlya-kakoj-platformyi-ispolnyaetsya-ispolnyaemyij-fajl/30647499#30647499 отмечается, что "в расширениях сообщества PowerShell есть также командлет Get-PEHeader, который можно использовать для проверки наличия исполняемых образов".

Альтернативой уже упомянутым инструментам является Telerik JustDecompile (бесплатный инструмент), который отображает информацию рядом с названием сборки:

Мне нравится ILSpy инструмент ребята. Он показывает не только архитектуру, но и целевой фреймворк:

      // linq2db, Version=3.0.0.0, Culture=neutral, PublicKeyToken=e41013125f9e410a
// Global type: <Module>
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// This assembly is signed with a strong name key.
// This assembly was compiled using the /deterministic option.
// Hash algorithm: SHA1

Таким образом, можно определить, является ли это .Net Core 2.1, .Net Framework 4.6 или любой другой:

Другие вопросы по тегам