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?
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?
Antworten:
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.
In diesem Beispiel verwende ich PowerShell, um die Methode aufzurufen.
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
da manchmal das aktuelle Verzeichnis des Prozesses nicht das gleiche ist wie das des aktuellen Anbieters (wo ich
// 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 constructor
wird das Feld immer auf gesetzt None
.
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 PortableExecutableKinds
Wert PE32Plus
(64-Bit), Required32Bit
(32-Bit und WOW) oder ILOnly
(eine beliebige CPU) ist.
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:
Öffnen Sie die Visual Studio-Eingabeaufforderung (In Windows: Menü Start / Programme / Microsoft Visual Studio / Visual Studio-Tools / Visual Studio 2008-Eingabeaufforderung)
CD in das Verzeichnis mit der betreffenden DLL
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:
32BITREQ
und 32BITPREF
nicht mehr nur ein einzelner 32BIT
Wert.
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.
Versuchen Sie, CorFlagsReader aus diesem Projekt bei CodePlex zu verwenden . Es enthält keine Verweise auf andere Baugruppen und kann unverändert verwendet werden.
[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);
}
}
Unten finden Sie eine Batch-Datei, die corflags.exe
für alle dlls
und exes
im 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.exe
die 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 CPU
und zu unterscheiden x86
. Wenn Sie eine ältere Version von corflags.exe
(vor Windows SDK v8.0A) verwenden, ist nur die Werbebuchung 32BIT
in der Ausgabe vorhanden, wie andere in früheren Antworten angegeben haben. Andernfalls 32BITREQ
und 32BITPREF
ersetzen Sie es.
Dies setzt voraus, dass corflags.exe
in 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 dll
oder ausgeführt wird exe
, wird sie fälschlicherweise als angezeigt x86
, 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.
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>
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
Ich habe ein super praktisches Tool geklont, das einen Kontextmenüeintrag für Assemblys im Windows Explorer hinzufügt, um alle verfügbaren Informationen anzuzeigen:
Hier herunterladen: https://github.com/tebjan/AssemblyInformation/releases
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.
cfeduke weist auf die Möglichkeit hin, GetPEKind aufzurufen. Es ist möglicherweise interessant, dies über PowerShell zu tun.
Hier ist beispielsweise Code für ein Cmdlet, das verwendet werden könnte: https://stackoverflow.com/a/16181743/64257
Alternativ wird unter https://stackoverflow.com/a/4719567/64257 angemerkt, dass "in den PowerShell-Community-Erweiterungen auch das Cmdlet Get-PEHeader enthalten ist, mit dem auf ausführbare Bilder getestet werden kann".
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
Eine Alternative zu bereits erwähnten Tools ist Telerik JustDecompile (kostenloses Tool), das die Informationen neben dem Namen der Assembly anzeigt: