2008-10-13 15 views
46

Tengo una necesidad de trabajar con ejecutables de Windows que están hechos para x86, x64 e IA64. Me gustaría descubrir la plataforma mediante programación examinando los archivos ellos mismos.¿Cómo puedo determinar para qué plataforma se compila un ejecutable?

Mi idioma de destino es PowerShell, pero un ejemplo de C# servirá. Si falla alguno de ellos, si conoce la lógica requerida, sería genial.

Respuesta

21

(de otro Q, ya eliminado)

Tipo de máquina: Esto es un poco más rápido de código I basada en algunas que se pone la marca de tiempo de enlace. Esto está en el mismo encabezado, y parece funcionar: devuelve I386 cuando se compila -cualquier CPU- y x64 cuando se compila con eso como plataforma de destino.

La entrada del blog Exploring PE Headers (K. Stanton, MSDN) que me mostró el desplazamiento, como se indicó en otra respuesta.

public enum MachineType { 
    Native = 0, I386 = 0x014c, Itanium = 0x0200, x64 = 0x8664 
} 

public static MachineType GetMachineType(string fileName) 
{ 
    const int PE_POINTER_OFFSET = 60;    
    const int MACHINE_OFFSET = 4; 
    byte[] data = new byte[4096]; 
    using (Stream s = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { 
     s.Read(data, 0, 4096); 
    } 
    // dos header is 64 bytes, last element, long (4 bytes) is the address of the PE header 
    int PE_HEADER_ADDR = BitConverter.ToInt32(data, PE_POINTER_OFFSET); 
    int machineUint = BitConverter.ToUInt16(data, PE_HEADER_ADDR + MACHINE_OFFSET); 
    return (MachineType)machineUint; 
} 
0

Unix OS tiene una utilidad llamada "archivo" que identifica los archivos. Las reglas para identificar se guardan en un archivo de descripción llamado "magia". Podría intentar con el archivo para ver si es capaz de identificar sus archivos correctamente y tomar las reglas apropiadas del archivo mágico.

8
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe")); 
Module manifestModule = assembly.ManifestModule; 
PortableExecutableKinds peKind; 
ImageFileMachine machine; 
manifestModule.GetPEKind(out peKind, out machine); 

La máquina de destino debería estar en la máquina.

Sin embargo, eso solo funcionará con los ensamblados .NET.

+0

Esto funciona bien, si se puede cargar el binario de destino. En mi caso, había una DLL .NET que necesitaba VCRedist y traté de averiguar cuál (x86 o x64), que corresponde a .NET dll. Pero, lógicamente e irónicamente, no puedo cargar este .NET dll sin VCRedist instalado y, por lo tanto, no puedo detectar cuál necesita (con este método). – Nicolas

11

Necesita la función GetBinaryType win32. Esto devolverá las partes relevantes del ejecutable de formato PE.

Por lo general, obtendrá ya sea SCS_32BIT_BINARY o SCS_64BIT_BINARY en el campo binaryType,

Alternativaly puede comprobar el formato PE mismo para ver lo que la arquitectura del ejecutable está compilado para.

El campo IMAGE_FILE_HEADER.Machine tendrá "IMAGE_FILE_MACHINE_IA64" set para binarios IA64, IMAGE_FILE_MACHINE_I386 para 32 bits y IMAGE_FILE_MACHINE_AMD64 para 64 bits (es decir x86_64).

Hay un MSDN magazine article para ayudarle a ponerse en marcha.

Adición: This puede ayudarlo un poco más. Lees el binario como un archivo: comprueba los primeros 2 bytes, di "MZ", luego omite los siguientes 58 bytes y lee el valor mágico de 32 bits a 60 bytes en la imagen (que equivale a 0x00004550 para ejecutables PE). Los siguientes bytes son this header, cuyos primeros 2 bytes le indican para qué máquina está diseñado el binario (0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).

(resumen ejecutivo: leer bytes 65 y 66 del archivo para obtener el tipo de imagen)

+0

Eso es más informativo que útil en mi caso. Mi culpa, no tuya :) Necesito algo que me acerque más. – halr9000

+0

lo siento viejo amigo, no estoy de acuerdo con PowerShell, pero espero que te ponga en el camino correcto. ver mi edición – gbjbaanb

+0

Voy a intentarlo la próxima semana y es posible que termine marcando el suyo como "la respuesta". – halr9000

1

puedo ofrecer un link to some C# code para acceder a la IMAGE_FILE_HEADER, que creo que podría ser (fácilmente) compila en un cmdlet de PowerShell. Estoy razonablemente seguro de que no puede usar ese método directamente en el script de PowerShell, ya que carece de punteros y capacidad de PInvoke.

Sin embargo, debería poder utilizar su extenso conocimiento del formato de encabezado PE ;-) para simplemente ir "directo" a los bytes correctos y resolverlo. Este funcionará con en secuencia de comandos de PowerShell, y usted solo podrá convertir this C# code from Tasos' blog en secuencia de comandos. No me molestaré en repetir el código aquí porque no es mío.

+0

El enlace al blog de Tasos no funciona. Esta es una de las razones por las que debe incluir partes relevantes de un enlace en su respuesta. –

+0

Página de Tasos en el Archivo web: http://web.archive.org/web/20080113025340/http://www.anastasiosyal.com/archive/2007/04/17/3.aspx –

35

Si tiene instalado Visual Studio puede usar dumpbin.exe. También está el cmdlet Get-PEHeader en PowerShell Community Extensions que se puede usar para probar imágenes ejecutables.

de Dumpbin reportará DLL como machine (x86) o machine (x64)

Get-PEHeader reportará DLL como sea PE32 o PE32+

+0

Impresionante. Get-PEHeader hace por usted las dos respuestas que (actualmente) son las más valoradas, simplemente le brindan información para que usted mismo escriba. PSCX FTW. – Jaykul

+0

http://stackoverflow.com/a/16181743/64257 también tiene código para un cmdlet similar (probablemente con funcionalidad reducida) aquí en Stack Overflow. – Chris

+18

Para aquellos (como yo) que son demasiado perezosos para leer el manual: 'dumpbin/headers | findstr machine' –

0

Aquí está mi propia implementación de este que tiene varias más cheques en su lugar y siempre devuelve un resultado .

// the enum of known pe file types 
public enum FilePEType : ushort 
{ 
    IMAGE_FILE_MACHINE_UNKNOWN = 0x0, 
    IMAGE_FILE_MACHINE_AM33 = 0x1d3, 
    IMAGE_FILE_MACHINE_AMD64 = 0x8664, 
    IMAGE_FILE_MACHINE_ARM = 0x1c0, 
    IMAGE_FILE_MACHINE_EBC = 0xebc, 
    IMAGE_FILE_MACHINE_I386 = 0x14c, 
    IMAGE_FILE_MACHINE_IA64 = 0x200, 
    IMAGE_FILE_MACHINE_M32R = 0x9041, 
    IMAGE_FILE_MACHINE_MIPS16 = 0x266, 
    IMAGE_FILE_MACHINE_MIPSFPU = 0x366, 
    IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466, 
    IMAGE_FILE_MACHINE_POWERPC = 0x1f0, 
    IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1, 
    IMAGE_FILE_MACHINE_R4000 = 0x166, 
    IMAGE_FILE_MACHINE_SH3 = 0x1a2, 
    IMAGE_FILE_MACHINE_SH3DSP = 0x1a3, 
    IMAGE_FILE_MACHINE_SH4 = 0x1a6, 
    IMAGE_FILE_MACHINE_SH5 = 0x1a8, 
    IMAGE_FILE_MACHINE_THUMB = 0x1c2, 
    IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169, 
} 

// pass the path to the file and check the return 
public static FilePEType GetFilePE(string path) 
{ 
    FilePEType pe = new FilePEType(); 
    pe = FilePEType.IMAGE_FILE_MACHINE_UNKNOWN; 
    if(File.Exists(path)) 
    { 
     using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
     { 
      byte[] data = new byte[4096]; 
      fs.Read(data, 0, 4096); 
      ushort result = BitConverter.ToUInt16(data, BitConverter.ToInt32(data, 60) + 4); 
      try 
      { 
       pe = (FilePEType)result; 
      } catch (Exception) 
      { 
       pe = FilePEType.IMAGE_FILE_MACHINE_UNKNOWN; 
      } 
     } 
    } 
    return pe; 
} 

Modo de empleo:

string myfile = @"c:\windows\explorer.exe"; // the file 
FilePEType pe = GetFilePE(myfile); 

System.Diagnostics.WriteLine(pe.ToString()); 

Para los valores de enumeración utilizados aquí, que se obtuvieron de pe.go. La razón por la que esto funciona es que para cada distribución binaria de 'go' debe tener el indicador correcto en el ensamblado para permitirle pasar los sistemas operativos '¿puede ejecutar aquí?' comprobar. Como 'ir' es multiplataforma (todas las plataformas), es una buena base para obtener esta información. Probablemente haya otras fuentes para esta información, pero parecen estar anidadas hasta la rodilla en google ca-ca que requieren un cinturón negro de décimo dan en Google-fu para localizar.

0

De acuerdo con esta post, se puede comprobar si un archivo DLL o EXE es 32 o 64 abriéndolo con Bloc de notas y en busca de "PE" al principio, si la próxima carta es "L" de la plataforma es de 32 -bit, es la letra "D" la plataforma es de 64 bits.

Lo probé en mi dlls y parece ser exacto.

Cuestiones relacionadas