Как определить, для какой платформы исполняется исполняемый файл? - PullRequest
48 голосов
/ 13 октября 2008

Мне нужно работать с исполняемыми файлами Windows, которые созданы для x86, x64 и IA64. Я хотел бы программно выяснить платформу, изучив сами файлы.

Мой целевой язык - PowerShell, но подойдет пример на C #. Если вы не знаете, какая логика требуется, это было бы здорово.

Ответы [ 10 ]

37 голосов
/ 18 января 2011

Если у вас установлена ​​Visual Studio, вы можете использовать dumpbin.exe. В Расширения сообщества PowerShell также имеется командлет Get-PEHeader, который можно использовать для проверки исполняемых образов.

Dumpbin будет сообщать о DLL как machine (x86) или machine (x64)

Get-PEHeader сообщит о DLL как PE32 или PE32+

24 голосов
/ 20 мая 2009

(из другого Q, так как удалено)

Тип машины: это небольшой кусочек кода, который я основал на некоторых, который получает временную метку компоновщика. Это находится в том же заголовке, и, похоже, работает - он возвращает I386 при компиляции -any cpu- и x64 при компиляции с этим в качестве целевой платформы.

Запись в блоге Exploring PE Headers (К. Стэнтон, MSDN), которая показала мне смещение, как отмечалось в другом ответе.

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;
}
11 голосов
/ 13 октября 2008

Вам нужна функция GetBinaryType win32. Это вернет соответствующие части исполняемого файла формата PE.

Как правило, в поле BinaryType вы получаете либо SCS_32BIT_BINARY, либо SCS_64BIT_BINARY,

Альтернативно вы можете проверить сам формат PE, чтобы увидеть, для какой архитектуры скомпилирован исполняемый файл.

В поле IMAGE_FILE_HEADER.Machine будет установлено «IMAGE_FILE_MACHINE_IA64» для двоичных файлов IA64, IMAGE_FILE_MACHINE_I386 для 32-разрядных и IMAGE_FILE_MACHINE_AMD64 для 64-разрядных (т. Е. X86_64).

В журнале MSDN есть статья , которая поможет вам начать работу.

Приложение: Это может помочь вам немного больше. Вы читаете двоичный файл как файл: проверьте первые 2 байта, скажем «MZ», затем пропустите следующие 58 байтов и прочитайте магическое 32-битное значение при 60 байтах в образ (что равно 0x00004550 для исполняемых файлов PE). Следующие байты это заголовок , первые 2 байта которого указывают, для какой машины предназначен двоичный файл (0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).

(резюме: прочитайте байты 65 и 66 файла, чтобы получить тип изображения)

8 голосов
/ 13 октября 2008
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);

Целевая машина должна быть в машине.

Это будет работать только со сборками .NET.

2 голосов
/ 05 марта 2018

Согласно этому сообщению , вы можете проверить, является ли DLL или EXE-файл 32 или 64, открыв его с помощью NotePad и найдя «PE» в начале, если следующий буква «L», платформа 32-битная, буква «D», платформа 64-битная.

Я попробовал это на своих dll, и, похоже, это точно.

1 голос
/ 13 октября 2008

Я могу предложить ссылку на некоторый код C # для доступа к IMAGE_FILE_HEADER, который, я думаю, можно (легко) скомпилировать в командлет PowerShell. Я вполне уверен, что вы не можете использовать этот метод непосредственно в скрипте PowerShell, поскольку в нем отсутствуют указатели и возможность PInvoke.

Тем не менее, вы должны быть в состоянии использовать свои обширные знания о формате PE-заголовка ;-), чтобы просто перейти "прямо" к нужным байтам и выяснить это. Этот будет работать в сценарии PowerShell, и вы сможете просто преобразовать этот код C # из блога Tasos в сценарий. Я не буду повторять код здесь, так как он не мой.

0 голосов
/ 11 июля 2018

dumpbin.exe доступно в каталоге bin Visual Studio работает как для .lib, так и для .dll

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine
0 голосов
/ 22 мая 2018

Вот реализация на 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 голосов
/ 06 августа 2016

Вот моя собственная реализация, которая имеет еще несколько проверок и всегда возвращает результат.

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

Как использовать:

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

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

Для значений перечисления, используемых здесь, они были получены из pe.go . Причина, по которой это работает, заключается в том, что для каждого двоичного распределения «go» должен иметь правильный флаг в сборке, чтобы он мог пройти операционные системы «можете ли вы запустить здесь?» проверять. Поскольку 'go' является кроссплатформенным (все платформы), это хорошая база для получения этой информации. Вероятно, есть и другие источники этой информации, но они, кажется, вложены по колено в Google Ca-Ca, и для их обнаружения требуется черный пояс 10-го дана в Google-fu.

0 голосов
/ 13 октября 2008

ОС Unix имеет утилиту под названием «файл», которая идентифицирует файлы. Правила идентификации хранятся в файле описания под названием «магия». Вы можете попробовать файл, чтобы увидеть, сможет ли он правильно идентифицировать ваши файлы и извлечь соответствующие правила из волшебного файла.

...