Как определить, на какой платформе компилируется исполняемый файл?

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

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

Ответ 1

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

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

Ввод записи блога заголовков PE (K. Stanton, 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;
}

Ответ 2

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

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

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

Ответ 3

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

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

Alternativaly вы можете проверить сам формат 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 файла для получения типа изображения)

Ответ 4

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

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

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

// 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.