it-swarm.com.de

Wie können Sie feststellen, ob eine .NET-Assembly für x86 oder x64 erstellt wurde?

Ich habe eine beliebige Liste von .NET-Assemblys.

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

295

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

Sie können Assembly-Metadaten von der zurückgegebenen AssemblyName-Instanz aus überprüfen:

Verwenden von PowerShell:

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

 Name: Microsoft.GLEE 
 Version: 1.0.0.0 
 CultureInfo: 
 CodeBase: Datei: /// C: /projects/powershell/BuildAnalyzer/...
 EscapedCodeBase: file: /// C: /projects/powershell/BuildAnalyzer/...
ProzessorArchitektur: MSIL
 Flags: PublicKey 
 HashAlgorithm: SHA1 
 VersionCompatibility: SameMachine 
 KeyPair: 
 FullName: Microsoft.GLEE, Version = 1.0.0.0, Culture = 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 Bits pro Wort.
  • X86: Ein 32-Bit-Intel-Prozessor, entweder nativ oder in der Windows-auf-Windows-Umgebung auf einer 64-Bit-Plattform (WOW64).
  • None: Eine unbekannte oder nicht angegebene Kombination aus Prozessor und Bits pro Wort.

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

246
x0n

Sie können das Tool CorFlagsCLI verwenden (z. B. C:\Programme\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe), um den Status einer Assembly zu ermitteln. Basierend auf ihrer Ausgabe und dem Öffnen einer Assembly als binäres Asset sollten Sie in der Lage sein zu bestimmen, wo Sie suchen müssen, um zu bestimmen, ob das 32BIT-Flag auf 1 (x86) oder 0 (Any CPU oder) gesetzt ist x64, abhängig von PE):

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

Der Blogbeitrag x64 Entwicklung mit .NET enthält einige Informationen zu corflags.

Noch besser können Sie verwenden Sie Module.GetPEKind , um festzustellen, ob eine Assembly PortableExecutableKinds-Wert PE32Plus (64-Bit), Required32Bit (32-Bit und WOW) oder ILOnly (beliebige CPU) zusammen mit anderen Attributen ist.

214
cfeduke

Nur 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, ist:

  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, das die betreffende DLL enthält

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

Sie erhalten etwa 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

Wie in den Kommentaren sind die Flaggen wie folgt zu lesen:

  • Beliebige CPU: PE = PE32 und 32BIT = 0
  • x86: PE = PE32 und 32BIT = 1
  • 64-Bit: PE = PE32 + und 32BIT = 0
133
JoshL

Wie wär's, wenn du nur dein eigenes schreibst? Der Kern der PE-Architektur wurde seit der Implementierung in Windows 95 nicht wesentlich 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;
    }
}

Nun sind die aktuellen Konstanten:

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

Bei dieser Methode können jedoch neue Konstanten verwendet werden. Validieren Sie einfach die Rückgabe so, wie Sie es für richtig halten.

18
Jason

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

9
Ludwo
[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);
    }
}
6
Morgan Mellor

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

Nachfolgend finden Sie eine Batchdatei, die corflags.exe für alle dlls und exes im aktuellen Arbeitsverzeichnis und für alle Unterverzeichnisse ausführt, die Ergebnisse parst und die Zielarchitektur von jedem anzeigt.

Abhängig von der verwendeten Version von corflags.exe umfassen die Einzelposten in der Ausgabe entweder 32BIT, oder32BITREQ (und 32BITPREF). Welche dieser beiden Optionen in der Ausgabe enthalten ist, ist die kritische Werbebuchung, die geprüft werden muss, um zwischen Any CPU und x86 zu unterscheiden. Wenn Sie eine ältere Version von corflags.exe (vor Windows SDK v8.0A) verwenden, wird nur die Werbebuchung 32BIT in der Ausgabe angezeigt, wie andere in früheren Antworten angegeben haben. Andernfalls ersetzen es 32BITREQ und 32BITPREF.

Dies setzt voraus, dass sich corflags.exe im %PATH% befindet. Die einfachste Möglichkeit, dies sicherzustellen, ist die Verwendung eines Developer Command Prompt. Alternativ können Sie es von Standardspeicherort kopieren.

Wenn die untenstehende Batchdatei mit einer nicht verwalteten dll oder exe ausgeführt wird, wird sie falsch als x86 angezeigt, da die tatsächliche Ausgabe von Corflags.exe eine 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.
4
Eric Lease

Eine weitere Möglichkeit wäre, dumpbin aus den Visual Studio-Tools unter 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: O/p ist für 32-Bit-DLL

Eine weitere nützliche Option mit dumpbin.exe ist/EXPORTS. Sie zeigt Ihnen die von der DLL zur Verfügung gestellte Funktion

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

Ich habe ein sehr praktisches Werkzeug geklont, das im Windows Explorer ein Kontextmenü für Baugruppen hinzufügt, um alle verfügbaren Informationen anzuzeigen:

Hier herunterladen: https://github.com/tebjan/AssemblyInformation/releases

 enter image description here

2
thalm

cfeduke weist auf die Möglichkeit hin, GetPEKind aufzurufen. Es ist möglicherweise interessant, dies von PowerShell aus zu tun.

Hier ist zum Beispiel Code für ein Cmdlet, das verwendet werden könnte: https://stackoverflow.com/a/16181743/64257

Alternativ kann unter https://stackoverflow.com/a/4719567/64257 Folgendes beachtet werden: "Es gibt auch das Cmdlet Get-PEHeader in den PowerShell Community Extensions , mit dem ausführbare Bilder getestet werden können . "

1
Chris

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

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

1
juanjo.arana

Eine fortgeschrittenere 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
1

Allgemeiner Weg - Verwenden Sie die Dateistruktur, um die Bitgröße 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 im Kompilierungsmodus

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

Quellcode mit Erklärung unter GitHub

0
BlackGad