Jak mogę ustalić, czy zestaw .NET został zbudowany dla x86 czy x64?

327

Mam dowolną listę zestawów .NET.

Muszę programowo sprawdzić, czy każda biblioteka DLL została zbudowana dla x86 (w przeciwieństwie do x64 lub dowolnego procesora). czy to możliwe?

Judah Gabriel Himango
źródło
2
Możesz także sprawdzić ten: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Matt
2
W późniejszej wersji CorFlags, odpowiadającej .NET 4.5, „32BIT” zastąpiono „32BITREQ” ​​i „32BITPREF”. .
Peter Mortensen

Odpowiedzi:

280

Patrzeć na System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Możesz sprawdzić metadane zestawu z zwróconej instancji AssemblyName:

Za pomocą programu PowerShell :

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

Nazwa: Microsoft.GLEE
Wersja: 1.0.0.0
CultureInfo:
CodeBase: plik: /// C: / projects / powershell / BuildAnalyzer / ...
EscapedCodeBase: file: /// C: / projects / powershell / BuildAnalyzer / ...
ProcesorArchitektura: MSIL
Flagi: PublicKey
Algorytm Hash: SHA1
VersionCompatibility: SameMachine
KeyPair:
Pełna nazwa: Microsoft.GLEE, wersja = 1.0.0.0, kultura = neut ... 

Tutaj ProcessorArchitecture identyfikuje platformę docelową.

  • Amd64 : 64-bitowy procesor oparty na architekturze x64.
  • Uzbrojenie : procesor ARM.
  • IA64 : Tylko 64-bitowy procesor Intel Itanium.
  • MSIL : Neutralny w odniesieniu do procesora i bitów na słowo.
  • X86 : 32-bitowy procesor Intel, natywny lub w środowisku Windows w systemie Windows na platformie 64-bitowej (WOW64).
  • Brak : nieznana lub nieokreślona kombinacja procesora i bitów na słowo.

Korzystam z programu PowerShell w tym przykładzie do wywołania metody.

x0n
źródło
60
Wybacz głupie pytanie - ale co w tym mówi ci, że to x86?
George Mauer,
53
Pole ProcessorArchitecture jest wyliczeniem; w powyższym przykładzie jest ustawiony na MSIL, co oznacza „Neutralny w odniesieniu do procesora i bitów na słowo”. Inne wartości to X86, IA64, Amd64. Aby uzyskać więcej informacji, zobacz msdn.microsoft.com/en-us/library/ ...
Brian Gillespie,
4
Spróbuj, [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")ponieważ czasami bieżący katalog procesu nie jest taki sam jak bieżący dostawca (w którym zakładam, że biblioteka DLL jest dla Ciebie)
x0n
2
Kolejnym zastrzeżeniem, na które należy zwrócić uwagę, jest zapomnienie o „odblokowaniu” biblioteki DLL, jeśli została ona pobrana z Internetu. Użyj pliku odblokowania lub kliknij prawym przyciskiem myszy / właściwości / odblokuj z Eksploratora. Będziesz musiał zrestartować powłokę, aby rozpoznała status odblokowania, jeśli już raz zawiodłeś w bieżącej sesji (obwiniaj za to Internet Explorera - tak, naprawdę.)
x0n
1
W kodzie ASP.NET MVC jest komentarz // 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.Niestety nie ma możliwości odczytania architektury procesora bez użycia GetName instance method; przy użyciu AssemblyName constructorpole jest zawsze ustawione na None.
metadings
221

Możesz użyć narzędzia CorFlags CLI (na przykład C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe), aby określić status zestawu na podstawie jego danych wyjściowych i otwarcia zestawu jako binarny zasób, powinieneś być w stanie określić, gdzie musisz szukać, czy flaga 32BIT jest ustawiona na 1 ( x86 ) lub 0 ( dowolny procesor lub x64 , w zależności od PE):

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

W poście na blogu x64 Development with .NET znajduje się kilka informacji na temat corflags.

Co więcej, możesz użyć,Module.GetPEKind aby określić, czy zestaw jest PortableExecutableKindswartością PE32Plus(64-bit), Required32Bit(32-bit i WOW) lub ILOnly(dowolny procesor) wraz z innymi atrybutami.

cfeduke
źródło
1
Po obejrzeniu aktualizacji wydaje się, że użycie GetPEKind jest właściwym sposobem. Jako odpowiedź zaznaczyłem twój.
Judah Gabriel Himango,
9
GetPEKind kończy się niepowodzeniem w procesie 64-bitowym podczas sprawdzania zespołów 32-bitowych
jjxtra,
2
Musisz zadzwonić do GetPEKind z procesu 32-bitowego
Ludwo
2
Instaluję VS 2008, VS 2010, VS 2012 i VS 2013. Mam 8 plików CorFlags.exe w podfolderach w C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Którego powinienem użyć?
Kiquenet,
5
Jak wskazano w tej odpowiedzi , w .NET 4.5 zamiast flagi 32BIT występuje 32BITREQ i 32BITPREF. PE32 / 0/0 i PE32 / 0/1 są odpowiednio AnyCPU i AnyCPU 32-bitowe.
angularsen
141

Dla wyjaśnienia, CorFlags.exe jest częścią zestawu .NET Framework SDK . Mam narzędzia programistyczne na moim komputerze, a najprostszym sposobem na określenie, czy biblioteka DLL jest 32-bitowa, jest:

  1. Otwórz wiersz polecenia programu Visual Studio (w systemie Windows: menu Start / Programy / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Wiersz polecenia)

  2. CD do katalogu zawierającego daną bibliotekę DLL

  3. Uruchom corflags w następujący sposób: corflags MyAssembly.dll

Otrzymasz coś takiego:

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

Zgodnie z komentarzami powyższe flagi należy rozumieć następująco:

  • Dowolny procesor: PE = PE32 i 32BIT = 0
  • x86: PE = PE32 i 32BIT = 1
  • 64-bit: PE = PE32 + i 32BIT = 0
JoshL
źródło
12
Tymczasem wydaje się, że to się zmieniło; corflags wyświetla teraz 32BITREQi 32BITPREFzamiast pojedynczej 32BITwartości.
LUB Mapper
1
Microsoft .NET 4.5 wprowadził nową opcję, Any CPU 32-bit Preferred. Oto szczegóły.
RBT
„Wiersz polecenia programu Visual Studio” jest obecnie nazywany „ wierszem polecenia programu Visual Studio 2019 dla programistów ”.
Uwe Keim
22

Co powiesz na napisanie własnego? Rdzeń architektury PE nie został poważnie zmieniony od czasu jego implementacji w Windows 95. Oto przykład 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;
    }
}

Teraz obecne stałe to:

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

Ale dzięki tej metodzie pozwala ona na możliwości nowych stałych, wystarczy zweryfikować zwrot według własnego uznania.

Jason
źródło
1
Ciekawe, dziękuję za kod z wyjaśnieniem. Module.GetPEKind jest prawdopodobnie najłatwiejszą ścieżką. Ale to jest pomocne ze względu na naukę. Dzięki.
Judah Gabriel Himango,
3
Bardzo interesujące, ale gdy mam aplikację skompilowaną z dowolnym procesorem, wynikiem jest 0x10B. To źle, ponieważ moja aplikacja jest uruchomiona w systemie x64. Czy jest jakaś inna flaga do sprawdzenia?
Samuel
GetPEArchitecture działa dla zestawów skompilowanych przy użyciu .net 3.5, 4.0, 4.5 i 4.5.1? W każdym razie, jak sądzę, Module.GetPEKind kończy się niepowodzeniem w procesie 64-bitowym podczas sprawdzania zestawów 32-bitowych.
Kiquenet
9

Spróbuj użyć CorFlagsReader z tego projektu w CodePlex . Nie ma odniesień do innych zestawów i może być używany w takiej postaci, w jakiej jest.

Ludwo
źródło
1
To jest najdokładniejsza i najbardziej użyteczna odpowiedź.
Kirill Osenkov
Link nadal działa w chwili pisania tego tekstu, ale ponieważ CodePlex ma zostać zamknięty, dobrze byłoby wykonać odpowiednie działania, zanim będzie za późno.
Peter Mortensen
7

DotPeek od JetBrians zapewnia szybki i łatwy sposób zobaczenia msil (anycpu), x86, x64 dotPeek

Prabhakaran Rajagopal
źródło
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);
    }
}
Morgan Mellor
źródło
Dzięki za to, jedna z naszych aplikacji musi być zbudowana jako x86, dodanie testu jednostkowego gwarantuje, że biblioteki kompilacji serwera kompilacji będą 32-bitowe i pozwoli uniknąć tych błędów :)
Mido
5

Poniżej znajduje się plik wsadowy, który będzie działał corflags.exedla wszystkich dllsoraz exesw bieżącym katalogu roboczym i wszystkich podkatalogach, analizował wyniki i wyświetlał architekturę docelową każdego z nich.

W zależności od wersji corflags.exe, która jest używana, gdy pozycje w wyjścia albo będzie zawierać 32BIT, lub 32BITREQ (i 32BITPREF). Którykolwiek z tych dwóch elementów jest uwzględniony w danych wyjściowych, jest to krytyczny element zamówienia, który należy sprawdzić, aby odróżnić od Any CPUi x86. Jeśli używasz starszej wersji corflags.exe(wcześniejszej wersji Windows SDK 8.0A), tylko wynik 32BITbędzie obecny na wyjściu, jak wskazali inni w poprzednich odpowiedziach. W przeciwnym razie 32BITREQi 32BITPREFwymień go.

Zakłada się, że corflags.exejest w %PATH%. Najprostszym sposobem zapewnienia tego jest użycie Developer Command Prompt. Możesz też skopiować go z domyślnej lokalizacji .

Jeśli plik wsadowy poniżej jest uruchamiany z niezarządzanym dlllub exe, niepoprawnie wyświetli go jako x86, ponieważ rzeczywiste wyjście z Corflags.exebędzie komunikatem o błędzie podobnym do:

corflags: error CF008: Podany plik nie ma prawidłowego zarządzanego nagłówka

@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.
Eric Lease
źródło
2

Jeszcze jednym sposobem byłoby użycie śmietnika z narzędzi Visual Studio na DLL i poszukiwanie odpowiedniego wyjścia

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

Uwaga: powyżej o / p jest dll dla 32-bitów

Jeszcze jedną przydatną opcją z dumpbin.exe jest / EXPORTS, pokaże ci funkcję ujawnioną przez dll

dumpbin.exe /EXPORTS <PATH OF THE DLL>
Ayush Joshi
źródło
2

Bardziej ogólny sposób - użyj struktury pliku, aby określić bitowość i typ obrazu:

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

Wyliczanie trybu kompilacji

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

Kod źródłowy z wyjaśnieniem na GitHub

BlackGad
źródło
1

Innym sposobem sprawdzenia platformy docelowej zestawu .NET jest sprawdzenie zestawu za pomocą .NET Reflector ...

@ # ~ # € ~! Właśnie zdałem sobie sprawę, że nowa wersja nie jest darmowa! Tak więc, jeśli masz darmową wersję odbłyśnika .NET, możesz go użyć do sprawdzenia platformy docelowej.

sakito
źródło
9
Użyj ILSpy , jest to podstawowa aplikacja typu open source, która robi te same rzeczy, co Reflector
Binary Worrier
1

Bardziej zaawansowaną aplikację do tego można znaleźć tutaj: CodePlex - ApiChange

Przykłady:

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
Wernfried Domscheit
źródło
0

Alternatywą dla już wspomnianych narzędzi jest Telerik JustDecompile (darmowe narzędzie), które wyświetla informacje obok nazwy zestawu:

Dowolna lub x86 lub x64 informacja w Telerik

Aleksiej
źródło