2008-10-13 51 views
46

我需要使用适用于x86,x64和IA64的Windows可执行文件。我想通过检查文件本身来以编程方式确定平台。如何确定可执行文件编译的平台?

我的目标语言是PowerShell,但是一个C#示例可以。如果你知道所要求的逻辑很好,那么这两者中的任何一个都不行。

回答

21

(从另一个Q,因为删除)

机器类型:这是我根据一些获取链接时间戳的代码快速点点。这是在同一个头,它似乎工作 - 编译时,它会返回I386 -any cpu-,以及编译时将x64作为目标平台。

的探索PE头(K.斯坦顿,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; 
} 
0

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

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

目标机器应该在机器中。

虽然这只能用于.NET程序集。

+0

如果可以加载目标二进制文件,这可以很好地工作。在我的情况下,有一个.NET DLL需要VCRedist,我试图找出哪一个(x86或x64),对应于.NET DLL。但是,逻辑上和讽刺的是,如果没有安装VCRedist,我无法加载这个.NET DLL,因此无法检测到它需要哪个(使用此方法)。 – Nicolas 2015-12-07 13:33:03

11

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

通常情况下,你会在BinaryType场获得任意SCS_32BIT_BINARY或SCS_64BIT_BINARY,

Alternativaly可以检查PE格式本身看什么架构的可执行文件编译为。

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

有一个MSDN magazine article来帮助你开始。

附录:This可能会帮助你多一点。您将二进制读取为一个文件:检查前两个字节,如“MZ”,然后跳过下一个58个字节,并读取60个字节的魔术32位值(等于PE可执行文件的0x00004550)。以下字节为this header,其中的前2个字节告诉您该二进制文件设计为哪台计算机(0x8664 = x86_64,0x0200 = IA64,0x014c = i386)。

(内容提要:读取的字节65和文件66来获取图像类型)

+0

对我而言,这比我的帮助更有价值。我的错,不是你的。 :)我需要让我更接近的东西。 – halr9000 2008-10-13 16:06:03

+0

对不起老朋友,我不喜欢PowerShell,但我希望我能让你走上正确的道路。看我的编辑。 – gbjbaanb 2008-10-14 21:31:36

+0

我将在下周出发,并可能最终将您标为“答案”。 – halr9000 2008-10-19 00:10:59

1

我可以访问IMAGE_FILE_HEADER,我想这可能是提供一个link to some C# code(容易)编译成PowerShell命令。我相当肯定你不能直接在PowerShell脚本中使用该方法,因为它缺少指针和PInvoke功能。

但是,你应该能够通过PE头格式;-)现在广泛的知识用你只是去“直”,以正确的字节,看着办吧。这工作在PowerShell脚本,你应该能够将this C# code from Tasos' blog转换为脚本。我不会在这里重复代码,因为它不是我的。

35

如果您安装了Visual Studio,则可以使用dumpbin.exePowerShell Community Extensions中还有Get-PEHeader cmdlet,可用于测试可执行映像。

DUMPBIN将报告的DLL作为machine (x86)machine (x64)

GET-PEHeader将报告的DLL作为要么PE32PE32+

0

这是我自己实现的这里面有几个检查到位,并始终返回结果。

// 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'的每个二进制分布,在程序集中必须有正确的标记才能让它通过操作系统'你可以在这里运行吗?'检查。由于'去'是跨平台(所有平台),因此它是获取此信息的好基础。这些信息可能还有其他来源,但它们似乎在google ca-ca中嵌套在一起,需要Google-fu中的第10个黑带才能找到。

0

根据这一post,您可以检查是否DLL或EXE为32或64的开头与记事本打开它,并寻找“PE”,如果下一个字母为“L”的平台是32它的字母是“D”,平台是64位。

我在我的dll上试过了,它似乎是准确的。

相关问题