【发布时间】:2011-04-20 02:37:08
【问题描述】:
当我编译一个 .net 程序时,我可以告诉它为 /platform:anycpu 或 /platform:x86 等进行编译。有什么方法可以确定一个 .net exe/dll 是用什么平台值编译的?
有关确定平台标志的程序,请参阅下面的答案。或者使用 corflags.exe。
【问题讨论】:
标签: .net
当我编译一个 .net 程序时,我可以告诉它为 /platform:anycpu 或 /platform:x86 等进行编译。有什么方法可以确定一个 .net exe/dll 是用什么平台值编译的?
有关确定平台标志的程序,请参阅下面的答案。或者使用 corflags.exe。
【问题讨论】:
标签: .net
使用来自 Luke 和 Marty 的答案中的信息,我能够做到这一点。这是我编写的控制台程序,用于检查程序集是否使用指定的平台编译。它很乱,因为我还没有清理它,但它可以工作。
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace MyApp
{
static class App
{
[STAThread]
static void Main(string[] args)
{
if (args.GetUpperBound(0) != 1)
{
Console.WriteLine("Usage:");
Console.WriteLine(" checkPlatform [anycpu|x86|x64] filename");
return;
}
CheckPlatform(args[0], args[1]);
}
public static bool CheckPlatform(string targetPlatform, string filename)
{
//see http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
//offset to PE header is always at 0x3C
//PE header starts with "PE\0\0" = 0x50 0x45 0x00 0x00
//followed by 2-byte machine type field (see document above for enum)
FileStream fs = new FileStream(filename, FileMode.Open, System.IO.FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
fs.Seek(0x3c, SeekOrigin.Begin);
Int32 peOffset = br.ReadInt32();
fs.Seek(peOffset, SeekOrigin.Begin);
UInt32 peHead = br.ReadUInt32();
if(peHead!=0x00004550) // "PE\0\0", little-endian
throw new Exception("Can't find PE header");
int machineType = (int) br.ReadUInt16(); // The number that identifies the type of target machine.
int numberOfSections = (int)br.ReadUInt16(); // The number of sections. This indicates the size of the section table, which immediately follows the headers.
int timeDateStamp = (int)br.ReadUInt32(); // The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value), that indicates when the file was created.
int pointerToSymbolTable = (int)br.ReadUInt32(); // The file offset of the COFF symbol table, or zero if no COFF symbol table is present. This value should be zero for an image because COFF debugging information is deprecated.
int numberOfSymbols = (int)br.ReadUInt32(); // The number of entries in the symbol table. This data can be used to locate the string table, which immediately follows the symbol table. This value should be zero for an image because COFF debugging information is deprecated.
int sizeOfOptionalHeader = (int)br.ReadUInt16(); // The size of the optional header, which is required for executable files but not for object files. This value should be zero for an object file. For a description of the header format, see section 3.4, “Optional Header (Image Only).”
int characteristics = (int)br.ReadUInt16(); // The flags that indicate the attributes of the file. For specific flag values, see section 3.3.2, “Characteristics.”
int sectionoffset = (int)fs.Position + sizeOfOptionalHeader;
int magic = (int)br.ReadUInt16();
/*
Now we are at the end of the PE Header and from here, the
PE Optional Headers starts...
To go directly to the datadictionary, we'll increase the
stream’s current position to with 96 (0x60). 96 because,
28 for Standard fields
68 for NT-specific fields
From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,
doing simple maths 128/16 = 8.
So each directory is of 8 bytes.
In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.
btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
*/
ushort dataDictionaryStart;
uint[] dataDictionaryRVA = new uint[16];
uint[] dataDictionarySize = new uint[16];
dataDictionaryStart = Convert.ToUInt16 (Convert.ToUInt16(fs.Position) + 0x60);
fs.Position = dataDictionaryStart - 2;
for (int i = 0; i < 15; i++)
{
dataDictionaryRVA[i] = br.ReadUInt32();
dataDictionarySize[i] = br.ReadUInt32();
}
if (dataDictionaryRVA[14] == 0)
{
MessageBox.Show("This is NOT a valid CLR File!!");
return false;
}
fs.Position = sectionoffset;
int[] SVirtualAddress = new int[numberOfSections];
int[] SSizeOfRawData = new int[numberOfSections];
int[] SPointerToRawData = new int[numberOfSections];
for ( int i = 0 ; i <numberOfSections; i++)
{
br.ReadBytes(12);
SVirtualAddress[i] = br.ReadInt32();
SSizeOfRawData[i] = br.ReadInt32();
SPointerToRawData[i] = br.ReadInt32();
br.ReadBytes(16);
}
fs.Position = ConvertRVA(numberOfSections, SVirtualAddress, SSizeOfRawData, SPointerToRawData, dataDictionaryRVA[14]);
int size = br.ReadInt32();
int majorruntimeversion = br.ReadInt16();
int minorruntimeversion = br.ReadInt16();
int metadatarva = br.ReadInt32();
int metadatasize = br.ReadInt32();
int corflags = br.ReadInt32();
br.Close();
fs.Close();
bool is32bit = false;
if ((characteristics & 0x0100) == (0x0100)) is32bit = true;
string s = "";
if (magic == 0x10b) s += "Magic=PE\r\n"; else
if (magic == 0x20b) s += "Magic=PE+\r\n"; else
s += "Magic=" + magic.ToString("X") + "\r\n";
s += "machineType=" + machineType.ToString() + "\r\n";
s += "is32bit=" + is32bit.ToString() + "\r\n";
s += "numberOfSections=" + numberOfSections.ToString() + "\r\n";
s += "sizeOfOptionalHeader=" + sizeOfOptionalHeader.ToString() + "\r\n";
s += "Characteristics=" + characteristics.ToString() + "\r\n";
s += "corflags=" + corflags.ToString("X") + "\r\n";
//· anycpu: PE = PE32 and 32BIT = 0
//· x86: PE = PE32 and 32BIT = 1
//· 64-bit: PE = PE32+ and 32BIT = 0
if ((corflags & 2) == 2) is32bit = true; else is32bit = false;
string platform = "Unknown";
if (magic == 0x10b)
{
// PE32
if (is32bit) platform = "x86"; else platform = "anycpu";
} else
if (magic == 0x20b)
{
// PE32+
if (is32bit == false) platform = "x64";
}
if (platform.ToUpper() != targetPlatform.ToUpper())
{
MessageBox.Show(filename + " is " + platform + ", not " + targetPlatform + ".\r\n" + s);
return false;
}
return true;
}
public static long ConvertRVA(int numberOfSections, int[] SVirtualAddress, int[] SSizeOfRawData, int[] SPointerToRawData, long rva)
{
int i;
for ( i = 0 ; i <numberOfSections; i++)
{
if ( rva >= SVirtualAddress [i] && ( rva < SVirtualAddress[i] + SSizeOfRawData [i] ))
break ;
}
return SPointerToRawData [i] + ( rva - SVirtualAddress[i] );
}
}
}
【讨论】:
这可能对可执行文件有所帮助:
如果您需要以编程方式检查 .net dll,那么有这些帖子:
【讨论】:
看看CorFlags.exe。它允许您查看 .NET 程序集的 PE 和 32BIT 标志。
编辑:this page 提供了有关如何解释 CorFlags 输出的更多信息。
【讨论】: