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


327

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

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



2
Вы также можете проверить это: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Мэтт

2
В более поздней версии CorFlags, соответствующей .NET 4.5, «32BIT» был заменен на «32BITREQ» и «32BITPREF». ,
Питер Мортенсен

Ответы:


281

смотреть на 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
Хэш-алгоритм: 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 для вызова метода.


60
Простите за глупый вопрос - но что в этом говорит вам, что это x86?
Джордж Мауэр

53
Поле ProcessorArchitecture является перечислением; в приведенном выше примере он установлен на MSIL, что означает «Нейтральный по отношению к процессору и битам на слово». Другие значения включают X86, IA64, Amd64. См. Msdn.microsoft.com/en-us/library/… для получения более подробной информации.
Брайан Гиллеспи

4
Попробуйте, так [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")как иногда текущий каталог процесса не совпадает с текущим провайдером (именно здесь я предполагаю, что DLL для вас)
x0n

2
Еще одна оговорка, на которую стоит обратить внимание, это забыть «разблокировать» DLL, если вы загрузили ее из интернета. Используйте unblock-файл или щелкните правой кнопкой мыши / properties / unblock from explorer. Вам нужно будет перезапустить оболочку, чтобы она распознала разблокированный статус, если вы уже однажды потерпели неудачу в текущем сеансе (в этом виноват Internet Explorer - да, действительно.)
x0n

1
В коде ASP.NET MVC есть комментарий // DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.К сожалению, нет способа прочитать ProcessorArchitecture без использования GetName instance method; используя AssemblyName constructor, поле всегда установлено в None.
метадинги

221

Вы можете использовать инструмент 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 Разработка с .NET есть некоторая информация о corflags.

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


1
После просмотра вашего обновления использование GetPEKind кажется правильным способом сделать это. Я отметил ваш ответ.
Иуда Габриэль Химанго

9
Сбой GetPEKind в 64-битном процессе при проверке 32-битных сборок
jjxtra

2
Вы должны позвонить в GetPEKind из 32-битного процесса
Ludwo

2
Я устанавливаю VS 2008, VS 2010, VS 2012 и VS 2013. У меня есть 8 файлов CorFlags.exe в подпапках в C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Какой я должен использовать?
Kiquenet

5
Как указано в этом ответе , в .NET 4.5 вместо флага 32BIT есть 32BITREQ и 32BITPREF. PE32 / 0/0 и PE32 / 0/1 предпочтительны для 32-разрядных AnyCPU и AnyCPU соответственно.
angularsen

141

Просто для пояснения, 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

12
Это, кажется, изменилось между тем; CorFlags теперь отображается 32BITREQи 32BITPREFвместо единого 32BITзначения.
ИЛИ Mapper

1
В Microsoft .NET 4.5 появилась новая опция «Любой процессор 32-битный предпочтительный» Вот подробности.
RBT

«Командная строка Visual Studio» в настоящее время называется « Командная строка разработчика Visual Studio 2019 ».
Уве Кейм

22

Как насчет того, чтобы написать себе? Ядро архитектуры 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.

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


1
Интересно, спасибо за код с пояснениями. Module.GetPEKind, вероятно, самый простой путь. Но это полезно для обучения. Спасибо.
Иуда Габриэль Химанго

3
Очень интересно, но когда у меня есть приложение, скомпилированное с Any CPU, результат равен 0x10B. Это неправильно, потому что мое приложение работает в системе x64. Есть ли другой флаг, чтобы проверить?
Самуил

GetPEArchitecture работает для сборок, скомпилированных с использованием .net 3.5, 4.0, 4.5 и 4.5.1? В любом случае, я думаю, что Module.GetPEKind завершается с ошибкой в ​​64-битном процессе при проверке 32-битных сборок.
Kiquenet

9

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


1
Это самый точный и полезный ответ.
Кирилл Осенков

Ссылка все еще работает на момент написания этой статьи, но так как CodePlex собирается быть закрытым, было бы хорошо сделать соответствующее действие, пока не стало слишком поздно.
Питер Мортенсен


6
[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, добавление модульного теста гарантирует, что библиотеки сборки сервера сборки будут 32-битными и не допускает этих ошибок :)
Mido

5

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

В зависимости от версии corflags.exe, которая используется, отдельные позиции в выходе будет либо включать в себя 32BIT, или 32BITREQ32BITPREF). Независимо от того, что из этих двух включено в выходные данные, это критическая позиция, которую необходимо проверить, чтобы различать 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.

2

Еще одним способом было бы использовать 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>

2

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

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


2

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

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

введите описание изображения здесь


1

Другой способ проверки целевой платформы сборки .NET - проверка сборки с помощью .NET Reflector. ...

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


9
Используйте ILSpy , это базовое приложение с открытым исходным кодом, которое выполняет те же функции, что и Reflector
Binary Worrier,

1

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

Вот, например, код для командлета, который можно использовать: https://stackoverflow.com/a/16181743/64257

В качестве альтернативы на https://stackoverflow.com/a/4719567/64257 отмечается, что «в расширениях сообщества PowerShell есть также командлет Get-PEHeader, который можно использовать для проверки наличия исполняемых образов».


1

Более продвинутое приложение для этого вы можете найти здесь: 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

0

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

Любая или x86 или x64 информация в Telerik

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.