代码之家  ›  专栏  ›  技术社区  ›  halr9000

如何确定编译可执行文件的平台?

  •  47
  • halr9000  · 技术社区  · 17 年前

    我的目标语言是PowerShell,但C#示例就可以了。如果你知道所需的逻辑,这两种方法都失败了,那就太好了。

    10 回复  |  直到 17 年前
        1
  •  40
  •   anon    10 年前

    如果已安装Visual Studio,则可以使用 dumpbin.exe . 还有 Get-PEHeader 中的cmdlet PowerShell Community Extensions

    Dumpbin会将DLL报告为 machine (x86) machine (x64)

    Get PEHeader会将DLL报告为 PE32 PE32+

        2
  •  29
  •   Andrew    17 年前

    (来自另一个Q,自删除后)

    机器类型:这是一段快速的代码,我基于一些获取链接器时间戳的代码。这是在同一个报头中,它似乎可以工作-编译时返回I386-任何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;
    }
    
        3
  •  11
  •   gbjbaanb    17 年前

    您需要GetBinaryType win32函数。这将返回PE格式可执行文件的相关部分。

    通常,您会在BinaryType字段中获得SCS\u 32位\u二进制或SCS\u 64位\u二进制,

    另外,您可以检查PE格式本身,以查看编译可执行文件的体系结构。

    IMAGE_FILE_HEADER.Machine字段将为IA64二进制文件设置“IMAGE_FILE_Machine_IA64”,为32位文件设置IMAGE_FILE_Machine_I386,为64位文件设置IMAGE_FILE_Machine_AMD64(即x86_64)。

    有一个 MSDN magazine article

    增编: This 我可以再帮你一点忙。将二进制文件作为文件读取:检查前2个字节,如“MZ”,然后跳过接下来的58个字节,并将60个字节处的魔法32位值读取到图像中(对于PE可执行文件,这等于0x00004550)。以下字节为 this header ,其前2个字节告诉您二进制文件是为哪台机器设计的(0x8664=x86_64,0x0200=IA64,0x014c=i386)。

    (执行摘要:读取文件的字节65和66以获取图像类型)

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

    然后,目标机器应该在机器中。

        5
  •  3
  •   default    8 年前

    据此, post ,您可以通过使用打开DLL或EXE来检查它是32还是64 在开头查找“PE”,如果下一个字母是“L”,则平台为32位,如果字母是“D”,则平台为64位。

    我在我的DLL上试用过,它似乎是准确的。

        6
  •  2
  •   Saad Saadi    8 年前

    dumpbin.exe 可根据 bin VisualStudio的目录对这两个方面都适用 .lib .dll

     dumpbin.exe /headers *.dll |findstr machine
     dumpbin.exe /headers *.lib |findstr machine
    
        7
  •  1
  •   Jaykul    17 年前

    我可以提供一个 link to some C# code 用于访问IMAGE_FILE_头,我认为可以(轻松地)编译成PowerShell cmdlet。我相当肯定您不能直接在PowerShell脚本中使用该方法,因为它缺少指针和PInvoke功能。

    但是,您现在应该能够使用您对PE头格式的丰富知识;-)直接转到正确的字节,然后找出它。这 在PowerShell脚本中工作,您应该能够转换 this C# code from Tasos' blog 编写脚本。我不会在这里重复代码,因为它不是我的。

        8
  •  1
  •   John Matthews    5 年前

    #include "stdafx.h"
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
      int nRetCode = 0;
      int nrd;
    
      IMAGE_DOS_HEADER idh;
      IMAGE_NT_HEADERS inth;
      IMAGE_FILE_HEADER ifh;
    
      // initialize MFC and print and error on failure
      if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
      {
        _tprintf(_T("Fatal Error: MFC initialization failed\n"));
        nRetCode = 1;
        return 1;
      }
      if (argc != 2) {
        _ftprintf(stderr, _T("Usage: %s filename\n"), argv[0]);
        return 1;
      }
      // Try to open the file
      CFile ckf;
      CFileException ex;
      DWORD flags = CFile::modeRead | CFile::shareDenyNone;
    
      if (!ckf.Open(argv[1], flags, &ex)) {
        TCHAR szError[1024];
        ex.GetErrorMessage(szError, 1024);
        _tprintf_s(_T("Couldn't open file: %1024s"), szError);
        return 2;
      }
    
      // The following is adapted from:
      // https://stackoverflow.com/questions/495244/how-can-i-test-a-windows-dll-file-to-determine-if-it-is-32-bit-or-64-bit
      // https://stackoverflow.com/questions/46024914/how-to-parse-exe-file-and-get-data-from-image-dos-header-structure-using-c-and
      // Seek to beginning of file
      ckf.Seek(0, CFile::begin);
    
      // Read DOS header
      int nbytes = sizeof(IMAGE_DOS_HEADER);
      nrd = ckf.Read(&idh, nbytes);
    
      // The idh.e_lfanew member is the offset to the NT_HEADERS structure
      ckf.Seek(idh.e_lfanew, CFile::begin);
    
      // Read NT headers
      nbytes = sizeof(IMAGE_NT_HEADERS);
      nrd = ckf.Read(&inth, nbytes);
    
      ifh = inth.FileHeader;
    
      _ftprintf(stdout, _T("File machine type: "));
      switch (ifh.Machine) {
         case IMAGE_FILE_MACHINE_I386:
           _ftprintf(stdout, _T("I386\n"));
           break;
         case IMAGE_FILE_MACHINE_IA64:
           _ftprintf(stdout, _T("IA64\n"));
           break;
         case IMAGE_FILE_MACHINE_AMD64:
           _ftprintf(stdout, _T("AMD64\n"));
           break;
         default:
           _ftprintf(stdout, _T("Unknown (%d = %X)\n"), ifh.Machine, ifh.Machine);
           break;
      }
    
      // Write characteristics (see WinNT.h)
      _ftprintf(stdout, _T("Characteristics:\n"));
      _ftprintf(stdout, _T("RELOCS_STRIPPED Relocation info stripped from file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("EXECUTABLE_IMAGE File is executable  (i.e. no unresolved externel references): %c\n"),
        (ifh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("LINE_NUMS_STRIPPED Line nunbers stripped from file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("LOCAL_SYMS_STRIPPED Local symbols stripped from file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("AGGRESIVE_WS_TRIM Agressively trim working set: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("LARGE_ADDRESS_AWARE App can handle >2gb addresses: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("BYTES_REVERSED_LO Bytes of machine word are reversed: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_BYTES_REVERSED_LO ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("32BIT_MACHINE 32 bit word machine: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_32BIT_MACHINE ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("DEBUG_STRIPPED Debugging info stripped from file in .DBG file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_DEBUG_STRIPPED ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("REMOVABLE_RUN_FROM_SWAP If Image is on removable media, copy and run from the swap file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("NET_RUN_FROM_SWAP If Image is on Net, copy and run from the swap file: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("SYSTEM System File: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_SYSTEM ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("DLL File is a DLL: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_DLL ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("UP_SYSTEM_ONLY File should only be run on a UP machine: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY ? _T('Y') : _T('N')));
      _ftprintf(stdout, _T("BYTES_REVERSED_HI Bytes of machine word are reversed: %c\n"),
        (ifh.Characteristics & IMAGE_FILE_BYTES_REVERSED_HI ? _T('Y') : _T('N')));
    
    
      ckf.Close();
    
      return nRetCode;
    }
    
        9
  •  0
  •   Sec    17 年前

    Unix操作系统有一个名为“file”的实用程序,用于标识文件。识别规则保存在一个名为“magic”的描述文件中。您可以尝试使用该文件,看看它是否能够正确识别您的文件,并从魔法文件中获取适当的规则。

        10
  •  0
  •   Kraang Prime    10 年前

    这是我自己的实现,它有多个检查,并且总是返回一个结果。

    // 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”的每个二进制ditdistribution,程序集中必须有正确的标志,才能让它通过操作系统“can you run here?”检查。由于“go”是跨平台的(所有平台),因此它是获取此信息的良好基础。这些信息可能还有其他来源,但它们似乎嵌套在齐膝深的谷歌ca中,需要谷歌fu中的第10条黑带才能找到。

        11
  •  0
  •   Jiminion    8 年前

    这里是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;
    }
    
        12
  •  0
  •   risingballs    5 年前

    // Fri May 28, 2021 -two
    
    #include <stdio.h>
    #include <io.h>
    #include <stdint.h>
    #include <iostream.h>
    using namespace std;
    
    bool queryExeMachineType( const char *filename )
    {
        FILE *fp = fopen( filename, "rb" );
    
        if (fp == NULL)
            return false;
    
        // DOS header is 64 bytes
        const uint32_t fsize = filelength( fileno( fp ) );
        char magic[ 2 ] = { 0 };
        uint32_t offset = 0;
        uint16_t machine = 0;
    
        if (fread( magic, 1, 2, fp ) != 2 || magic[ 0 ] != 'M' || magic[ 1 ] != 'Z')
        {
            cerr << "not an executable file" << endl;
            fclose( fp );
            return false;
        }
        fseek( fp, 60, SEEK_SET );
        fread( &offset, 1, 4, fp );
    
        if (offset >= fsize)
        {
            cerr << "invalid pe offset" << endl;
            fclose( fp );
            return false;
        }
        fseek( fp, offset, SEEK_SET );
    
        if (fread( magic, 1, 2, fp ) != 2 || magic[ 0 ] != 'P' || magic[ 1 ] != 'E')
        {
            cerr << "not a pe executable" << endl;
            fclose( fp );
            return false;
        }
        fread( magic, 1, 2, fp );
        fread( &machine, 1, 2, fp );
    
        switch (machine)
        {
            case 0x014c:
                cout << "i386" << endl;  // x86
                break;
    
            case 0x8664:
                cout << "amd64" << endl; // x86_64
                break;
    
           case 0x0200:
                cout << "ia64" << endl;  // itanium
                break;
    
            default:
                cerr << "unknown machine 0x" << hex << machine << endl;
                break;
        }
        fclose( fp );
        return true;
    }
    
    int main( int argc, char *argv[] )
    {
        const char *fn = (argc > 1) ? argv[ 1 ] : "test.dll";
    
        if (queryExeMachineType( fn ))
            cerr << "succeeded" << endl;
        else
            cerr << "failed" << endl;
    
        return 0;
    }