如何确定可执行文件是针对哪个平台编译的?

发布于 2024-07-07 22:30:43 字数 136 浏览 8 评论 0原文

我需要使用为 x86、x64 和 IA64 制作的 Windows 可执行文件。 我想通过检查文件本身以编程方式找出平台。

我的目标语言是 PowerShell,但 C# 示例就可以了。 如果您知道其中的任何一个失败,那就太好了。

I have a need to work with Windows executables which are made for x86, x64, and IA64. I'd like to programmatically figure out the platform by examining the files themselves.

My target language is PowerShell but a C# example will do. Failing either of those, if you know the logic required that would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

野味少女 2024-07-14 22:30:43

如果您安装了 Visual Studio,则可以使用 dumpbin.exePowerShell 社区扩展 中还有可用于测试的 Get-PEHeader cmdlet对于可执行图像。

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

Get-PEHeader 将把 DLL 报告为 PE32PE32+< /代码>

If you have Visual Studio installed you can use dumpbin.exe. There's also the Get-PEHeader cmdlet in the PowerShell Community Extensions that can be used to test for executable images.

Dumpbin will report DLLs as machine (x86) or machine (x64)

Get-PEHeader will report DLLs as either PE32 or PE32+

忆梦 2024-07-14 22:30:43

(来自另一个问题,已删除)

机器类型:这是我基于一些获取链接器时间戳的快速代码。 这是在同一个标​​头中,并且似乎有效 - 当编译任何 cpu- 时它返回 I386,当用它作为目标平台编译时返回 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;
}

(from another Q, since removed)

Machine type: This is a quick little bit of code I based on some that gets the linker timestamp. This is in the same header, and it seems to work - it returns I386 when compiled -any cpu-, and x64 when compiled with that as the target platform.

The Exploring PE Headers (K. Stanton,MSDN) blog entry that showed me the offset, as another response noted.

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;
}
傻比既视感 2024-07-14 22:30:43

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

通常,您会在 BinaryType 字段中获得 SCS_32BIT_BINARY 或 SCS_64BIT_BINARY,

或者您可以检查 PE 格式本身以查看可执行文件是为哪种体系结构编译的。

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

有一篇 MSDN 杂志文章可以帮助您入门。

附录:可能会对您有更多帮助。 您将二进制文件作为文件读取:检查前 2 个字节为“MZ”,然后跳过接下来的 58 个字节并将 60 个字节处的神奇 32 位值读取到映像中(对于 PE 可执行文件来说等于 0x00004550)。 以下字节是此标头,前 2 个其中的字节告诉您二进制文件是为哪台机器设计的(0x8664 = x86_64、0x0200 = IA64、0x014c = i386)。

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

You need the GetBinaryType win32 function. This will return the relevant parts of the PE-format executable.

Typically, you'll get either SCS_32BIT_BINARY or SCS_64BIT_BINARY in the BinaryType field,

Alternativaly you can check the PE format itself to see what architecture the executable is compiled for.

The IMAGE_FILE_HEADER.Machine field will have "IMAGE_FILE_MACHINE_IA64" set for IA64 binaries, IMAGE_FILE_MACHINE_I386 for 32-bit and IMAGE_FILE_MACHINE_AMD64 for 64-bit (ie x86_64).

There's a MSDN magazine article to help you get going.

Addendum: This may help you a little more. You read the binary as a file: check the first 2 bytes say "MZ", then skip the next 58 bytes and read the magic 32-bit value at 60 bytes into the image (which equals 0x00004550 for PE executables). The following bytes are this header, the first 2 bytes of which tell you which machine the binary is designed for (0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).

(executive summary: read bytes 65 and 66 of the file to get the image type)

伪装你 2024-07-14 22:30:43

根据“确定应用程序是否为 32 位编译的 10 种方法”位还是 64 位”,您可以通过用记事本打开 DLL 或 EXE 并查找 PE 来检查它是 32 位还是 64 位开头 - 如果后面的第三个字母是:

  • L,则平台是 32 位:
    带 x32 二进制的记事本
  • a d 平台为64位:
    带有 x64 二进制的记事本

我在我的 DLL 上尝试了它,它似乎是准确的。

According to "10 Ways to Determine if Application is Compiled for 32-bit or 64-bit", you can check if a DLL or EXE is 32-bit or 64-bit by opening it with Notepad and looking for PE at the beginning - if the 3rd letter after that is:

  • an L the platform is 32-bit:
    Notepad with x32 binary
  • a d the platform is 64-bit:
    Notepad with x64 binary

I tried it on my DLLs and it seems to be accurate.

逆光下的微笑 2024-07-14 22:30:43
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);

目标机器应该在机器中。

不过,这只适用于 .NET 程序集。

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

The target machine should then be in machine.

That'll only work with .NET assemblies though.

≈。彩虹 2024-07-14 22:30:43

Visual Studio 的 bin 目录下提供的 dumpbin.exe 适用于 .lib.dll

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine

dumpbin.exe available under bin directory of Visual Studio works for both .lib and .dll

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine
吝吻 2024-07-14 22:30:43

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

Unix OS have a utility called "file" which identifies files. The rules for identifying are kept in a description file called "magic". You could try file to see if it is able to identify your files correctly and grab the appropriate rules out of the magic file.

梦晓ヶ微光ヅ倾城 2024-07-14 22:30:43

我可以提供一些 C# 代码的链接访问 IMAGE_FILE_HEADER,我认为它可以(轻松)编译到 PowerShell cmdlet 中。 我相当确定您不能直接在 PowerShell 脚本中使用该方法,因为它缺少指针和 PInvoke 功能。

然而,您应该能够利用您现在对 PE 标头格式的广泛了解;-)“直接”找到正确的字节并找出它。 这在PowerShell脚本中工作,并且您应该能够仅转换此 C# 代码来自 Tasos 博客 到脚本。 我不会在这里重复代码,因为它不是我的。

I can offer a link to some C# code for accessing the IMAGE_FILE_HEADER, which I think could be (easily) compiled into a PowerShell cmdlet. I'm reasonably sure you can't use that method in PowerShell script directly, since it lacks pointers and PInvoke capability.

However, you should be able to use your by now extensive knowledge of the PE header format ;-) to just go "straight" to the right bytes and figure it out. This will work in PowerShell script, and you should be able to just convert this C# code from Tasos' blog to script. I won't bother repeating the code here since it's not mine.

柳若烟 2024-07-14 22:30:43

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

Here is an implementation 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;
}
鸠魁 2024-07-14 22:30:43

下面是一个 C++ MFC 控制台应用程序,用于写出文件头信息。 您可以检查特征中的机器类型(IMAGE_FILE_HEADER Machine 成员)或 IMAGE_FILE_32BIT_MACHINE 标志,以查看该文件是为哪个平台构建的。 有关结构的更多信息,请参阅 WinNT.h。

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

Here's a C++ MFC console application that writes out the file header information. You can check the machine type (IMAGE_FILE_HEADER Machine member) or the IMAGE_FILE_32BIT_MACHINE flag in the Characteristics to see what platform the file is built for. See WinNT.h for more info on the structures.

#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;
}
暖阳 2024-07-14 22:30:43

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

// 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 中,需要 Google-fu 中的 10 段黑带才能定位。

Here is my own implementation of this which has several more checks in place and always returns a result.

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

How to use :

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

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

For the enum values used here, they were obtained from pe.go . The reason why this works is that for each binary ditribution of 'go' must have the correct flag in the assembly to let it pass the operating systems 'can you run here ?' check. Since 'go' is cross platform (all platforms), it is a good base to get this information. There are probably other sources for this information, but they seem to be nested knee-deep in google ca-ca requiring a 10th dan black-belt in Google-fu to locate.

恍梦境° 2024-07-14 22:30:43

这是使用 C/C++ 作为独立工具的另一个解决方案,可以根据您的需要进行调整:

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

Here's another solution using C/C++ as a standalone tool, ready to be adapted to whatever you need:

// 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文