¿Cómo determinar si un ensamblado.NET fue construido para x86 o x64?
assemblies 64bit (14)
Tengo una lista arbitraria de ensamblados .NET.
Necesito verificar mediante programación si cada DLL se creó para x86 (a diferencia de x64 o Cualquier CPU). es posible?
¿Qué tal si solo escribes tu propia propiedad? El núcleo de la arquitectura de PE no ha cambiado seriamente desde su implementación en Windows 95. Aquí hay un ejemplo de 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;
}
}
Ahora las constantes actuales son:
0x10B - PE32 format.
0x20B - PE32+ format.
Pero con este método permite las posibilidades de nuevas constantes, solo valide la devolución como mejor le parezca.
A continuación se muestra un archivo por lotes que ejecutará corflags.exe
en todos los dlls
corflags.exe
y exes
en el directorio de trabajo actual y en todos los subdirectorios, analiza los resultados y muestra la arquitectura de destino de cada uno.
Dependiendo de la versión de corflags.exe
que se use, los artículos de línea en la salida incluirán 32BIT
o 32BITREQ
(y 32BITPREF
). Cualquiera de estos dos incluidos en la salida es la línea de pedido crítica que debe verificarse para diferenciar entre Any CPU
y x86
. Si está utilizando una versión anterior de corflags.exe
(anterior a Windows SDK v8.0A), solo estará presente la línea de pedido de 32BIT
en la salida, como han indicado otros en respuestas anteriores. De 32BITREQ
contrario, 32BITREQ
y 32BITPREF
reemplazan.
Esto supone que corflags.exe
está en el %PATH%
. La forma más sencilla de garantizar esto es utilizar un Developer Command Prompt
. Alternativamente, podría copiarlo desde su ubicación predeterminada .
Si el archivo por lotes a continuación se ejecuta en una dll
o exe
no administrada, se mostrará incorrectamente como x86
, ya que la salida real de Corflags.exe
será un mensaje de error similar a:
corflags: error CF008: el archivo especificado no tiene un encabezado administrado válido
@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.
Forma más genérica: use la estructura de archivos para determinar el bitness y el tipo de imagen:
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);
}
}
Enumeración de modo compilación
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
Código fuente con explicación en GitHub
He clonado una herramienta súper útil que agrega una entrada de menú contextual para ensamblajes en el explorador de Windows para mostrar toda la información disponible:
Descargue aquí: https://github.com/tebjan/AssemblyInformation/releases
Intente usar CorFlagsReader de este proyecto en CodePlex . No tiene referencias a otros ensamblajes y se puede utilizar como está.
Otra forma de verificar la plataforma de destino de un ensamblado .NET es inspeccionar el ensamblaje con .NET Reflector ...
@ # ~ # € ~! ¡Acabo de darme cuenta de que la nueva versión no es gratis! Por lo tanto, corrección, si tiene una versión gratuita de .NET reflector, puede usarla para verificar la plataforma de destino.
Puede usar la herramienta CLI CorFlags (por ejemplo, C: / Archivos de programa / Microsoft SDKs / Windows / v7.0 / Bin / CorFlags.exe) para determinar el estado de un ensamblaje, en función de su salida y de abrir un ensamblaje como un activo binario debe poder determinar dónde debe buscar determinar si el indicador de 32 BIT está establecido en 1 ( x86 ) o 0 ( cualquier CPU o x64 , según el PE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
La publicación del blog x64 Development con .NET tiene alguna información sobre corflags
.
Aún mejor, puede usar Module.GetPEKind
para determinar si un ensamblaje es PortableExecutableKinds
valor PE32Plus
(64 bits), Required32Bit
(32 bits y WOW), o ILOnly
(cualquier CPU) junto con otros atributos.
Solo para aclarar, CorFlags.exe es parte del SDK de .NET Framework . Tengo las herramientas de desarrollo en mi máquina, y la forma más sencilla para mí de determinar si una DLL solo es de 32 bits es:
Abra el Símbolo del sistema de Visual Studio (En Windows: menú Inicio / Programas / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Símbolo del sistema)
CD al directorio que contiene la DLL en cuestión
Ejecute corflags como este:
corflags MyAssembly.dll
Obtendrá salida algo como esto:
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
Según los comentarios, las banderas de arriba deben leerse como sigue:
- Cualquier CPU: PE = PE32 y 32BIT = 0
- x86: PE = PE32 y 32BIT = 1
- 64 bits: PE = PE32 + y 32BIT = 0
Una aplicación más avanzada que puedes encontrar aquí: CodePlex - ApiChange
Ejemplos:
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
Una forma más sería usar dumpbin de las herramientas de Visual Studio en DLL y buscar el resultado apropiado
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
Nota: encima de / p es para 32bit dll
Una opción más útil con dumpbin.exe es / EXPORTS, le mostrará la función expuesta por el dll
dumpbin.exe /EXPORTS <PATH OF THE DLL>
cfeduke señala la posibilidad de llamar a GetPEKind. Es potencialmente interesante hacer esto desde PowerShell.
Aquí, por ejemplo, hay un código para un cmdlet que se podría usar: https://.com/a/16181743/64257
Alternativamente, en https://.com/a/4719567/64257 se observa que "también está el cmdlet Get-PEHeader en las extensiones de la comunidad de PowerShell que se puede usar para probar imágenes ejecutables".
Mire System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
Puede examinar los metadatos del conjunto desde la instancia de AssemblyName devuelta:
Utilizando 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...
Aquí, ProcessorArchitecture identifica la plataforma de destino.
- Amd64 : un procesador de 64 bits basado en la arquitectura x64.
- Brazo : Un procesador ARM.
- IA64 : Un procesador Intel Itanium de 64 bits solamente.
- MSIL : Neutral con respecto al procesador y bits por palabra.
- X86 : un procesador Intel de 32 bits, ya sea nativo o en el entorno Windows en Windows en una plataforma de 64 bits (WOW64).
- Ninguno : una combinación desconocida o no especificada de procesador y bits por palabra.
Estoy usando PowerShell en este ejemplo para llamar al método.
[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);
}
}