我需要使用适用于x86,x64和IA64的Windows可执行文件。我想通过检查文件本身来以编程方式确定平台。如何确定可执行文件编译的平台?
我的目标语言是PowerShell,但是一个C#示例可以。如果你知道所要求的逻辑很好,那么这两者中的任何一个都不行。
我需要使用适用于x86,x64和IA64的Windows可执行文件。我想通过检查文件本身来以编程方式确定平台。如何确定可执行文件编译的平台?
我的目标语言是PowerShell,但是一个C#示例可以。如果你知道所要求的逻辑很好,那么这两者中的任何一个都不行。
(从另一个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;
}
Unix操作系统有一个名为“文件”的实用程序来识别文件。识别规则保存在一个名为“magic”的描述文件中。您可以尝试查看文件是否能够正确识别您的文件,并从魔术文件中获取适当的规则。
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);
目标机器应该在机器中。
虽然这只能用于.NET程序集。
您需要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来获取图像类型)
我可以访问IMAGE_FILE_HEADER,我想这可能是提供一个link to some C# code(容易)编译成PowerShell命令。我相当肯定你不能直接在PowerShell脚本中使用该方法,因为它缺少指针和PInvoke功能。
但是,你应该能够通过PE头格式;-)现在广泛的知识用你只是去“直”,以正确的字节,看着办吧。这将工作在PowerShell脚本,你应该能够将this C# code from Tasos' blog转换为脚本。我不会在这里重复代码,因为它不是我的。
如果您安装了Visual Studio,则可以使用dumpbin.exe
。 PowerShell Community Extensions中还有Get-PEHeader
cmdlet,可用于测试可执行映像。
DUMPBIN将报告的DLL作为machine (x86)
或machine (x64)
GET-PEHeader将报告的DLL作为要么PE32
或PE32+
这是我自己实现的这里面有几个检查到位,并始终返回结果。
// 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个黑带才能找到。
根据这一post,您可以检查是否DLL或EXE为32或64的开头与记事本打开它,并寻找“PE”,如果下一个字母为“L”的平台是32它的字母是“D”,平台是64位。
我在我的dll上试过了,它似乎是准确的。
如果可以加载目标二进制文件,这可以很好地工作。在我的情况下,有一个.NET DLL需要VCRedist,我试图找出哪一个(x86或x64),对应于.NET DLL。但是,逻辑上和讽刺的是,如果没有安装VCRedist,我无法加载这个.NET DLL,因此无法检测到它需要哪个(使用此方法)。 – Nicolas 2015-12-07 13:33:03