Question

J'ai besoin de travailler avec des exécutables Windows conçus pour x86, x64 et IA64. J'aimerais comprendre par programme la plate-forme en examinant les fichiers eux-mêmes.

Ma langue cible est PowerShell, mais un exemple en C # suffira. Si vous connaissez la logique requise, ce serait formidable.

Était-ce utile?

La solution

(d'un autre Q, depuis supprimé)

Type de machine: C’est un petit morceau de code rapide basé sur certains qui obtient l’horodatage de l’éditeur de liens. C’est dans le même en-tête, et cela semble fonctionner: il retourne I386 lorsqu’il a été compilé, et x64 lorsqu’il est compilé avec cela comme plate-forme cible.

L’entrée de blog Exploring PE Headers (K. Stanton, MSDN) qui m’a montré le décalage, comme indiqué dans une autre réponse.

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

Autres conseils

Si Visual Studio est installé sur votre ordinateur, vous pouvez utiliser dumpbin.exe . Il existe également la cmdlet Get-PEHeader dans la extensions de la communauté PowerShell pouvant être utilisée pour tester pour les images exécutables.

Dumpbin signalera les DLL comme machine (x86) ou machine (x64)

Get-PEHeader signalera les DLL sous la forme PE32 ou PE32 +

.

Vous avez besoin de la fonction GetBinaryType win32. Ceci renverra les parties pertinentes de l’exécutable au format PE.

Généralement, vous obtenez soit SCS_32BIT_BINARY, soit SCS_64BIT_BINARY dans le champ BinaryType,

.

Alternativement, vous pouvez vérifier le format PE lui-même pour voir quelle architecture pour laquelle l'exécutable est compilé.

Le champ IMAGE_FILE_HEADER.Machine aura "IMAGE_FILE_MACHINE_IA64". défini pour les binaires IA64, IMAGE_FILE_MACHINE_I386 pour 32 bits et IMAGE_FILE_MACHINE_AMD64 pour 64 bits (c.-à-d. x86_64).

Il existe un article de magazine MSDN pour vous aider à démarrer.

Addendum: Ceci peut vous aider un peu plus. Vous lisez le fichier binaire sous forme de fichier: vérifiez les 2 premiers octets en indiquant "MZ", puis ignorez les 58 octets suivants et lisez la valeur magique 32 bits à 60 octets dans l'image (ce qui correspond à 0x00004550 pour les exécutables PE). Les octets suivants sont cet en-tête , les 2 premiers les octets vous indiquent sur quelle machine le binaire est conçu (0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).

(résumé: lisez les octets 65 et 66 du fichier pour obtenir le type d'image)

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

La machine cible doit alors être dans la machine.

Cela fonctionnera uniquement avec les assemblys .NET.

Selon cette post , vous pouvez vérifier si une DLL ou un fichier EXE est 32 ou 64 en l'ouvrant avec Bloc-notes et en recherchant "PE". au début, si la lettre suivante est " L " la plate-forme est en 32 bits, la lettre est "D" la plate-forme est 64 bits.

Je l'ai essayé sur mes dll et cela semble être précis.

Je peux proposer un lien vers du code C # pour accéder à IMAGE_FILE_HEADER, qui, je pense, pourrait être (facilement) compilé dans une applet de commande PowerShell. Je suis pratiquement sûr que vous ne pouvez pas utiliser directement cette méthode dans le script PowerShell, car elle manque de pointeurs et de capacité PInvoke.

Cependant, vous devriez pouvoir utiliser votre connaissance étendue du format d’en-tête PE ;-) pour passer simplement "tout droit". aux bons octets et le comprendre. Cela fonctionnera dans le script PowerShell et vous devriez pouvoir convertir ce code C # du blog de Tasos au script. Je ne me dérangerai pas de répéter le code ici car ce n'est pas le mien.

Les systèmes d'exploitation Unix ont un utilitaire appelé "fichier". qui identifie les fichiers. Les règles d'identification sont conservées dans un fichier de description appelé "magique". Vous pouvez essayer fichier pour voir s’il est capable d’identifier correctement vos fichiers et d’extraire les règles appropriées du fichier magique.

Voici ma propre implémentation, qui a plusieurs vérifications en place et renvoie toujours un résultat.

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

Comment utiliser:

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

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

Pour les valeurs enum utilisées ici, elles ont été obtenues auprès de pe.go . . La raison pour laquelle cela fonctionne est que, pour chaque distribution binaire de 'go', le drapeau correct doit être placé dans l'assembly afin de le laisser passer sous le système d'exploitation 'pouvez-vous exécuter ici?' vérifier. Puisque «aller» est multiplateforme (toutes les plateformes), c'est une bonne base pour obtenir cette information. Il existe probablement d'autres sources pour ces informations, mais elles semblent être imbriquées jusqu'aux goûts de google ca-ca, ce qui nécessite une ceinture noire dans Google-fu 10e dan.

Voici une implémentation dans 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;
}

dumpbin.exe disponible dans le répertoire bin de Visual Studio fonctionne à la fois pour .lib et .dll

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top