Wie kann ich feststellen, ob eine .NET-Assembly für x86 oder x64 erstellt wurde?

327

Ich habe eine beliebige Liste von .NET-Assemblys.

Ich muss programmgesteuert prüfen, ob jede DLL für x86 erstellt wurde (im Gegensatz zu x64 oder einer beliebigen CPU). Ist das möglich?

Judah Gabriel Himango
quelle
2
Vielleicht möchten Sie auch Folgendes überprüfen: Überprüfen Sie, ob die nicht verwaltete DLL-32-Bit-oder-64-Bit ist .
Matt
2
In einer späteren Version von CorFlags, die .NET 4.5 entspricht, wurde "32BIT" durch "32BITREQ" und "32BITPREF" ersetzt. .
Peter Mortensen

Antworten:

280

Ansehen System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Sie können Assembly-Metadaten aus der zurückgegebenen AssemblyName-Instanz untersuchen:

Verwenden von 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 / ...
Prozessorarchitektur: MSIL
Flaggen: PublicKey
HashAlgorithm: SHA1
Versionskompatibilität: SameMachine
Schlüsselpaar:
Vollständiger Name: Microsoft.GLEE, Version = 1.0.0.0, Kultur = neut ... 

Hier identifiziert ProcessorArchitecture die Zielplattform.

  • Amd64 : Ein 64-Bit-Prozessor, der auf der x64-Architektur basiert.
  • Arm : Ein ARM-Prozessor.
  • IA64 : Nur ein 64-Bit-Intel Itanium-Prozessor.
  • MSIL : Neutral in Bezug auf Prozessor und Bit-pro-Wort.
  • X86 : Ein 32-Bit-Intel-Prozessor, entweder nativ oder in der Windows-unter-Windows-Umgebung auf einer 64-Bit-Plattform (WOW64).
  • Keine : Eine unbekannte oder nicht spezifizierte Kombination aus Prozessor und Bit pro Wort.

In diesem Beispiel verwende ich PowerShell, um die Methode aufzurufen.

x0n
quelle
60
Verzeihen Sie die dumme Frage - aber was sagt Ihnen das, dass es x86 ist?
George Mauer
53
Das Feld ProcessorArchitecture ist eine Aufzählung. im obigen Beispiel ist es auf MSIL gesetzt, was "Neutral in Bezug auf Prozessor und Bits pro Wort" bedeutet. Andere Werte umfassen X86, IA64, Amd64. Weitere Informationen finden Sie unter msdn.microsoft.com/en-us/library/… .
Brian Gillespie
4
Versuchen Sie es mit, [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")da manchmal das aktuelle Verzeichnis des Prozesses nicht das gleiche ist wie das des aktuellen Anbieters (wo ich
annehme,
2
Eine weitere Einschränkung, auf die Sie achten sollten, ist das Vergessen, die DLL zu "entsperren", wenn Sie sie aus dem Internet heruntergeladen haben. Verwenden Sie die Blockierungsdatei oder klicken Sie mit der rechten Maustaste auf / properties / unblock from explorer. Sie müssen die Shell neu starten, damit sie den Status "
Nicht blockiert"
1
In ASP.NET MVC-Code gibt es einen Kommentar. // 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.Leider gibt es keine Möglichkeit, ProcessorArchitecture zu lesen, ohne das zu verwenden GetName instance method. Mit AssemblyName constructorwird das Feld immer auf gesetzt None.
Metadings
221

Mit dem CorFlags- CLI- Tool (z. B. C: \ Programme \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) können Sie den Status einer Assembly anhand ihrer Ausgabe ermitteln und eine Assembly als öffnen Binäres Asset Sie sollten in der Lage sein zu bestimmen, wo Sie suchen müssen, um festzustellen, ob das 32BIT-Flag auf 1 ( x86 ) oder 0 ( Beliebige CPU oder x64) gesetzt ist je nachPE ) gesetzt ist:

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

Der Blogbeitrag x64 Development with .NET enthält einige Informationen zu corflags.

Noch besser ist es ,Module.GetPEKind zu bestimmen, ob eine Assembly zusammen mit anderen Attributen ein PortableExecutableKindsWert PE32Plus(64-Bit), Required32Bit(32-Bit und WOW) oder ILOnly(eine beliebige CPU) ist.

cfeduke
quelle
1
Nachdem Sie Ihr Update gesehen haben, scheint die Verwendung von GetPEKind der richtige Weg zu sein, dies zu tun. Ich habe deine als Antwort markiert.
Judah Gabriel Himango
9
GetPEKind schlägt in einem 64-Bit-Prozess fehl, wenn 32-Bit-Assemblys überprüft werden
jjxtra
2
Sie müssen GetPEKind aus dem 32-Bit-Prozess
aufrufen
2
Ich installiere VS 2008, VS 2010, VS 2012 und VS 2013. Ich habe 8 Dateien CorFlags.exe in Unterordnern unter C: \ Programme (x86) \ Microsoft SDKs \ Windows \. Welches sollte ich verwenden?
Kiquenet
5
Wie in dieser Antwort ausgeführt , gibt es in .NET 4.5 32BITREQ und 32BITPREF anstelle des 32BIT-Flags. PE32 / 0/0 und PE32 / 0/1 sind AnyCPU bzw. AnyCPU 32-Bit bevorzugt.
Angularsen
141

Zur Verdeutlichung ist CorFlags.exe Teil des .NET Framework SDK . Ich habe die Entwicklungstools auf meinem Computer, und der einfachste Weg für mich festzustellen, ob eine DLL nur 32-Bit ist, besteht darin:

  1. Öffnen Sie die Visual Studio-Eingabeaufforderung (In Windows: Menü Start / Programme / Microsoft Visual Studio / Visual Studio-Tools / Visual Studio 2008-Eingabeaufforderung)

  2. CD in das Verzeichnis mit der betreffenden DLL

  3. Führen Sie Corflags wie folgt aus: corflags MyAssembly.dll

Sie erhalten ungefähr folgende Ausgabe:

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

Gemäß den Kommentaren sind die obigen Flags wie folgt zu lesen:

  • Beliebige CPU: PE = PE32 und 32BIT = 0
  • x86: PE = PE32 und 32BIT = 1
  • 64-Bit: PE = PE32 + und 32BIT = 0
JoshL
quelle
12
Dies scheint sich inzwischen geändert zu haben; corflags werden jetzt angezeigt 32BITREQund 32BITPREFnicht mehr nur ein einzelner 32BITWert.
ODER Mapper
1
Microsoft .NET 4.5 hat eine neue Option eingeführt: Beliebige CPU 32-Bit bevorzugt. Hier sind die Details.
RBT
Die "Visual Studio-Eingabeaufforderung" wird heutzutage als " Visual Studio 2019 Developer Command Prompt " bezeichnet.
Uwe Keim
22

Wie wäre es, wenn du nur deine eigenen schreibst? Der Kern der PE-Architektur wurde seit ihrer Implementierung in Windows 95 nicht ernsthaft geändert. Hier ein C # -Beispiel:

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

Jetzt sind die aktuellen Konstanten:

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

Mit dieser Methode werden jedoch die Möglichkeiten neuer Konstanten berücksichtigt. Überprüfen Sie einfach die Rückgabe nach Belieben.

Jason
quelle
1
Interessant, danke für den Code mit Erklärung. Module.GetPEKind ist wahrscheinlich der einfachste Weg. Dies ist jedoch hilfreich, um zu lernen. Vielen Dank.
Judah Gabriel Himango
3
Sehr interessant, aber wenn ich eine Anwendung mit einer beliebigen CPU kompiliert habe, ist das Ergebnis 0x10B. Dies ist falsch, da meine Anwendung auf einem x64-System ausgeführt wird. Gibt es noch eine andere Flagge zu überprüfen?
Samuel
GetPEArchitecture funktioniert für Assemblys, die mit .net 3.5, 4.0, 4.5 und 4.5.1 kompiliert wurden. Wie auch immer, ich denke, Module.GetPEKind schlägt in einem 64-Bit-Prozess fehl, wenn 32-Bit-Assemblys überprüft werden.
Kiquenet
9

Versuchen Sie, CorFlagsReader aus diesem Projekt bei CodePlex zu verwenden . Es enthält keine Verweise auf andere Baugruppen und kann unverändert verwendet werden.

Ludwo
quelle
1
Dies ist die genaueste und nützlichste Antwort.
Kirill Osenkov
Der Link funktioniert zum jetzigen Zeitpunkt noch, aber da CodePlex kurz vor dem Herunterfahren steht, ist es gut, die entsprechenden Maßnahmen zu ergreifen, bevor es zu spät ist.
Peter Mortensen
7

DotPeek von JetBrians bietet eine schnelle und einfache Möglichkeit, msil (anycpu), x86, x64 anzuzeigen dotPeek

Prabhakaran Rajagopal
quelle
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
quelle
Vielen Dank dafür. Eine unserer Anwendungen muss als x86 erstellt werden. Durch Hinzufügen eines Komponententests wird sichergestellt, dass die Build-Bibliotheken des Build-Servers 32-Bit sind, und es werden diese Fehler vermieden :)
Mido
5

Unten finden Sie eine Batch-Datei, die corflags.exefür alle dllsund exesim aktuellen Arbeitsverzeichnis sowie für alle Unterverzeichnisse ausgeführt wird. Analysieren Sie die Ergebnisse und zeigen Sie die Zielarchitektur der einzelnen Verzeichnisse an.

Je nach Version von , corflags.exedie verwendet wird, werden entweder die Einzelposten in der Ausgabe enthalten 32BIT, oder 32BITREQ (und 32BITPREF). Welche dieser beiden in der Ausgabe enthalten ist, ist die kritische Werbebuchung, die überprüft werden muss, um zwischen Any CPUund zu unterscheiden x86. Wenn Sie eine ältere Version von corflags.exe(vor Windows SDK v8.0A) verwenden, ist nur die Werbebuchung 32BITin der Ausgabe vorhanden, wie andere in früheren Antworten angegeben haben. Andernfalls 32BITREQund 32BITPREFersetzen Sie es.

Dies setzt voraus, dass corflags.exein der %PATH%. Der einfachste Weg, dies sicherzustellen, ist die Verwendung von a Developer Command Prompt. Alternativ können Sie es vom Standardspeicherort kopieren .

Wenn die folgende Batchdatei für eine nicht verwaltete Datei dlloder ausgeführt wird exe, wird sie fälschlicherweise als angezeigt x86, da die tatsächliche Ausgabe von Corflags.exeeine Fehlermeldung ähnlich der folgenden ist:

corflags: Fehler CF008: Die angegebene Datei hat keinen gültigen verwalteten Header

@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
quelle
2

Eine weitere Möglichkeit wäre, den Dumpbin aus den Visual Studio-Tools in der DLL zu verwenden und nach der entsprechenden Ausgabe zu suchen

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

Hinweis: Oben o / p gilt für 32-Bit-DLL

Eine weitere nützliche Option mit dumpbin.exe ist / EXPORTS. Sie zeigt Ihnen die Funktion, die von der DLL verfügbar gemacht wird

dumpbin.exe /EXPORTS <PATH OF THE DLL>
Ayush Joshi
quelle
2

Allgemeinere Methode - Verwenden Sie die Dateistruktur, um die Bitheit und den Bildtyp zu bestimmen:

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

Aufzählung des Kompilierungsmodus

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

Quellcode mit Erklärung bei GitHub

BlackGad
quelle
1

Eine andere Möglichkeit, die Zielplattform einer .NET-Assembly zu überprüfen, besteht darin, die Assembly mit .NET Reflector zu überprüfen ...

@ # ~ # € ~! Ich habe gerade festgestellt, dass die neue Version nicht kostenlos ist! Wenn Sie also eine kostenlose Version von .NET Reflector haben, können Sie damit die Zielplattform überprüfen.

Sakito
quelle
9
Verwenden Sie ILSpy , es ist eine einfache Open-Source-App, die
fast
1

Eine erweiterte Anwendung dafür finden Sie hier: CodePlex - ApiChange

Beispiele:

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
quelle
0

Eine Alternative zu bereits erwähnten Tools ist Telerik JustDecompile (kostenloses Tool), das die Informationen neben dem Namen der Assembly anzeigt:

Beliebige oder x86- oder x64-Informationen in Telerik

Alexei
quelle