Tengo una lista arbitraria de ensamblados .NET.
Necesito verificar mediante programación si cada DLL se creó para x86 (a diferencia de x64 o Any CPU). es posible?
Tengo una lista arbitraria de ensamblados .NET.
Necesito verificar mediante programación si cada DLL se creó para x86 (a diferencia de x64 o Any CPU). es posible?
Respuestas:
Mirar System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
Puede examinar los metadatos de ensamblaje desde la instancia de AssemblyName devuelta:
Usando PowerShell :
[36] C: \> [reflection.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | Florida Nombre: Microsoft.GLEE Versión: 1.0.0.0 CultureInfo: CodeBase: archivo: /// C: / projects / powershell / BuildAnalyzer / ... EscapedCodeBase: archivo: /// C: / projects / powershell / BuildAnalyzer / ... Procesador Arquitectura: MSIL Banderas: PublicKey HashAlgorithm: SHA1 Versión Compatibilidad: SameMachine Par de claves : FullName: Microsoft.GLEE, Version = 1.0.0.0, Culture = neut ...
Aquí, ProcessorArchitecture identifica la plataforma objetivo.
Estoy usando PowerShell en este ejemplo para llamar al método.
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
ya que a veces el directorio actual del proceso no es el mismo que el del proveedor actual (que es donde supongo que la DLL es para usted)
// 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.
Lamentablemente, no hay forma de leer la Arquitectura del procesador sin usar el GetName instance method
; utilizando AssemblyName constructor
, el campo siempre se establece en None
.
Puede usar la herramienta CorFlags CLI (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 abrir un ensamblaje como un El activo binario debe poder determinar dónde necesita buscar para determinar si el indicador de 32 bits está establecido en 1 ( x86 ) o 0 ( cualquier CPU o x64 , según PE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
La publicación de blog x64 Desarrollo con .NET tiene información sobre corflags
.
Aún mejor, puede usarModule.GetPEKind
para determinar si un ensamblado tiene un 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 determinar si una DLL es solo 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 Command Prompt)
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 anteriores deben leerse de la siguiente manera:
32BITREQ
y 32BITPREF
no un solo 32BIT
valor.
¿Qué tal si solo escribes el tuyo? El núcleo de la arquitectura 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 el retorno como mejor le parezca.
Intente utilizar CorFlagsReader de este proyecto en CodePlex . No tiene referencias a otros ensamblajes y se puede usar como está.
[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);
}
}
A continuación se muestra un archivo por lotes que se ejecutará corflags.exe
en todos dlls
y exes
en el directorio de trabajo actual y todos los subdirectorios, analiza los resultados y muestra la arquitectura de destino de cada uno.
Dependiendo de la versión corflags.exe
utilizada, las líneas de pedido en la salida incluirán 32BIT
, o 32BITREQ
(y 32BITPREF
). Cualquiera de estos dos está incluido 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 la 32BIT
línea de pedido estará presente en la salida, como lo han indicado otros en respuestas anteriores. De lo contrario 32BITREQ
, y 32BITPREF
reemplazarlo.
Esto supone que corflags.exe
está en el %PATH%
. La forma más sencilla de garantizar esto es utilizar a Developer Command Prompt
. Alternativamente, puede copiarlo desde su ubicación predeterminada .
Si el archivo por lotes siguiente se ejecuta contra un archivo no administrado dll
o exe
, lo mostrará incorrectamente como x86
, ya que el resultado 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.
Una forma más sería usar dumpbin de las herramientas de Visual Studio en DLL y buscar la salida adecuada
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: Por encima de o / p es para 32 bits 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>
De forma más genérica: use la estructura de archivos para determinar el tipo de imagen y el bitness:
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 del modo de 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 práctica 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
Otra forma de verificar la plataforma de destino de un ensamblado .NET es inspeccionar el ensamblaje con .NET Reflector ...
@ # ~ # € ~! ¡Me acabo de dar cuenta de que la nueva versión no es gratuita! Entonces, corrección, si tiene una versión gratuita del reflector .NET, puede usarla para verificar la plataforma de destino.
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 podría usarse: https://stackoverflow.com/a/16181743/64257
Alternativamente, en https://stackoverflow.com/a/4719567/64257 se observa que "también está el cmdlet Get-PEHeader en las Extensiones de comunidad de PowerShell que se puede usar para probar imágenes ejecutables".
Puede encontrar una aplicación más avanzada para eso 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 alternativa a las herramientas ya mencionadas es Telerik JustDecompile (herramienta gratuita) que mostrará la información junto al nombre del ensamblado: