it-swarm.com.de

Wie kann ich feststellen, für welche Plattform eine ausführbare Datei kompiliert wurde?

Ich muss mit ausführbaren Windows-Dateien arbeiten, die für x86, x64 und IA64 erstellt wurden. Ich möchte die Plattform programmgesteuert herausfinden, indem ich die Dateien selbst untersuche.

Meine Zielsprache ist PowerShell, aber ein C # -Beispiel reicht aus. Wenn Sie die erforderliche Logik kennen, wäre das großartig.

47
halr9000

(von einem anderen Q, da entfernt)

Maschinentyp: Dies ist ein kurzer Code, der auf einigen basiert, die den Linker-Zeitstempel erhalten. Dieser befindet sich im selben Header und scheint zu funktionieren - er gibt I386 zurück, wenn er -any cpu- kompiliert wird, und x64, wenn er als Zielplattform kompiliert wird.

Der Blogeintrag "Exploring PE Headers" (K. Stanton, MSDN) zeigte mir den Versatz, wie eine andere Antwort feststellte.

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;
}
23
Andrew Backer

Wenn Sie Visual Studio installiert haben, können Sie dumpbin.exe verwenden. In den PowerShell Community Extensions gibt es auch das Get-PEHeader-Cmdlet, mit dem ausführbare Bilder getestet werden können.

Dumpbin meldet DLLs als machine (x86) oder machine (x64)

Get-PEHeader meldet DLLs entweder als PE32 oder PE32+

36
Keith Hill

Sie benötigen die GetBinaryType-Funktion win32. Dadurch werden die relevanten Teile der ausführbaren Datei im PE-Format zurückgegeben.

In der Regel erhalten Sie entweder SCS_32BIT_BINARY oder SCS_64BIT_BINARY im Feld BinaryType. 

Alternativ können Sie das PE-Format selbst prüfen, für welche Architektur die ausführbare Datei kompiliert wird.

Für das Feld IMAGE_FILE_HEADER.Machine ist "IMAGE_FILE_MACHINE_IA64" für IA64-Binärdateien festgelegt, IMAGE_FILE_MACHINE_I386 für 32-Bit und IMAGE_FILE_MACHINE_AMD64 für 64-Bit (dh x86_64).

Es gibt einen MSDN-Zeitschriftenartikel , der Ihnen dabei hilft, sich auf den Weg zu machen.

Nachtrag: Dies kann Ihnen etwas mehr helfen. Sie lesen die Binärdatei als Datei: Überprüfen Sie die ersten 2 Bytes, sagen Sie "MZ", überspringen Sie die nächsten 58 Bytes und lesen Sie den magischen 32-Bit-Wert mit 60 Bytes in das Image (was 0x00004550 für ausführbare PE-Dateien entspricht). Die folgenden Bytes sind dieser Header , von denen die ersten 2 Bytes angeben, für welche Maschine die Binärdatei vorgesehen ist (0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).

(Zusammenfassung: Lesen Sie die Bytes 65 und 66 der Datei, um den Bildtyp zu erhalten.)

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

Die Zielmaschine sollte sich dann in der Maschine befinden.

Das funktioniert aber nur mit .NET-Assemblys.

8
ICR

Entsprechend diesem post können Sie prüfen, ob ein DLL oder eine EXE oder 32 ist, indem Sie es mit NotePad öffnen und am Anfang nach "PE" suchen, wenn das Der nächste Buchstabe ist "L", die Plattform ist 32-Bit, es ist der Buchstabe "D", die Plattform ist 64Bit.

Ich habe es in meinen DLLs ausprobiert und es scheint genau zu sein.

2
mrelva

Ich kann ein Link zu einem C # -Code für den Zugriff auf den IMAGE_FILE_HEADER anbieten, der meiner Meinung nach (leicht) in ein PowerShell-Cmdlet kompiliert werden kann. Ich bin ziemlich sicher, dass Sie diese Methode nicht direkt in PowerShell-Skripts verwenden können, da sie keine Zeiger und keine PInvoke-Funktion hat.

Sie sollten jedoch in der Lage sein, Ihr mittlerweile umfangreiches Wissen über das PE-Header-Format zu nutzen ;-), um einfach "direkt" zu den richtigen Bytes zu gelangen und es herauszufinden. Dieses wird in PowerShell-Skript funktionieren, und Sie sollten in der Lage sein, diesen C # -Code aus dem Tasos-Blog in ein Skript zu konvertieren. Ich werde mich nicht darum kümmern, den Code hier zu wiederholen, da er nicht mein ist.

1
Jaykul

dumpbin.exe verfügbar im bin-Verzeichnis von Visual Studio funktioniert sowohl für .lib als auch für .dll 

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine
0
Saad Saadi

Unix-Betriebssysteme verfügen über ein Dienstprogramm namens "Datei", das Dateien identifiziert. Die Regeln für die Identifizierung werden in einer Beschreibungsdatei mit der Bezeichnung "Magie" aufbewahrt. Sie können versuchen, die Datei zu prüfen, ob sie Ihre Dateien richtig identifizieren und die entsprechenden Regeln aus der magischen Datei herausholen kann.

0
Sec

Hier ist eine Implementierung in C.

// Determines if DLL is 32-bit or 64-bit.
#include <stdio.h>

int sGetDllType(const char *dll_name);

int main()
{
  int ret;
  const char *fname = "sample_32.dll";
  //const char *fname = "sample_64.dll";
  ret = sGetDllType(fname);
}

static int sGetDllType(const char *dll_name) {
  const int PE_POINTER_OFFSET = 60;
  const int MACHINE_TYPE_OFFSET = 4;
  FILE *fp;
  unsigned int ret = 0;
  int peoffset;
  unsigned short machine;

  fp = fopen(dll_name, "rb");
  unsigned char data[4096];
  ret = fread(data, sizeof(char), 4096, fp);
  fclose(fp);
  if (ret == 0)
    return -1;

  if ( (data[0] == 'M') && (data[1] == 'Z') ) {
    // Initial magic header is good
    peoffset = data[PE_POINTER_OFFSET + 3];
    peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET + 2];
    peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET + 1];
    peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET];

    // Check second header
    if ((data[peoffset] == 'P') && (data[peoffset + 1] == 'E')) {
      machine = data[peoffset + MACHINE_TYPE_OFFSET];
      machine = (machine)+(data[peoffset + MACHINE_TYPE_OFFSET + 1] << 8);

      if (machine == 0x014c)
        return 32;
      if (machine == 0x8664)
        return 64;

      return -1;
    }
    return -1;
  }
  else
    return -1;
}
0
Jiminion

Hier ist meine eigene Implementierung, die einige weitere Prüfungen enthält und immer ein Ergebnis liefert.

// 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;
}

Wie benutzt man :

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

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

Für die hier verwendeten Enumerationswerte wurden sie aus pe.go ermittelt. Der Grund, warum dies funktioniert, ist, dass für jede Binärdistribution von 'go' das richtige Flag in der Assembly vorhanden sein muss, damit sie die Betriebssysteme passieren kann. 'Können Sie hier laufen?' prüfen. Da 'go' plattformübergreifend ist (alle Plattformen), ist es eine gute Basis, um diese Informationen zu erhalten. Es gibt wahrscheinlich andere Quellen für diese Informationen, aber sie scheinen in Google ca-ca knietief verschachtelt zu sein, was einen 10. Dan Black-Belt in Google-Fu zum Auffinden erfordert. 

0
Kraang Prime