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



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



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

623   14  

14 ответов:

посмотреть System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

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

используя 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... 

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

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

можно использовать CorFlagsCLI инструмент (например, C:\Program файлы\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe) чтобы определить состояние сборки, основываясь на ее выводе и открытии сборки в качестве двоичного актива, вы должны быть в состоянии определить, где вам нужно искать, чтобы определить, установлен ли 32-битный флаг на 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 (любой процессор) вместе с другими атрибутами.

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

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

  2. CD в каталог, содержащий 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 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.

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

попробуйте использовать 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,или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.

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

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

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

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

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

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

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

еще один способ-использовать dumpbin из Visual Studio tools на 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 для 32bit dll

еще один полезный вариант с dumpbin.exe is / EXPORTS, он покажет вам функцию, представленную dll

dumpbin.exe /EXPORTS <PATH OF THE DLL>

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

скачать здесь: https://github.com/tebjan/AssemblyInformation/releases

enter image description here

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

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

Comments

    Ничего не найдено.