如何确定.NET程序集是为x86还是x64构建的?

时间:2008-11-06 22:14:03

标签: .net assemblies x86 64-bit x86-64

我有一个任意的.NET程序集列表。

我需要以编程方式检查每个DLL是否是为x86构建的(而不是x64或任何CPU)。这可能吗?

16 个答案:

答案 0 :(得分:252)

查看System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

您可以从返回的AssemblyName实例检查程序集元数据:

使用 PowerShell

[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | fl

Name                  : Microsoft.GLEE
Version               : 1.0.0.0
CultureInfo           :
CodeBase              : file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase       : file:///C:/projects/powershell/BuildAnalyzer/...
ProcessorArchitecture : MSIL
Flags                 : PublicKey
HashAlgorithm         : SHA1
VersionCompatibility  : SameMachine
KeyPair               :
FullName              : Microsoft.GLEE, Version=1.0.0.0, Culture=neut... 

此处,ProcessorArchitecture标识了目标平台。

  • Amd64 :基于x64架构的64位处理器。
  • Arm :ARM处理器。
  • IA64 :仅限64位Intel Itanium处理器。
  • MSIL :关于处理器和每字位数的中性。
  • X86 :32位英特尔处理器,无论是本机还是Windows环境下的Windows 64位平台(WOW64)。
  • :处理器和每个字位数的未知或未指定组合。

我在此示例中使用PowerShell来调用该方法。

答案 1 :(得分:215)

您可以使用CorFlags CLI工具(例如,C:\ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe)来确定程序集的状态,根据其输出并打开一个程序集作为二进制资产,您应该能够确定在何处需要设置以确定32BIT标志是否设置为1( x86 )或0(任何CPU x64 ,取决于PE):

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

博文 x64 Development with .NET 包含有关corflags的一些信息。

更好的是,您可以use Module.GetPEKind确定程序集是PortableExecutableKindsPE32Plus(64位),Required32Bit(32位和WOW),还是ILOnly(任何CPU)以及其他属性。

答案 2 :(得分:134)

为了澄清,CorFlags.exe是.NET Framework SDK的一部分。我的机器上有开发工具,我最简单的方法是确定DLL是否只是32位:

  1. 打开Visual Studio命令提示符(在Windows中:菜单“开始/程序/ Microsoft Visual Studio / Visual Studio工具/ Visual Studio 2008命令提示符”)

  2. CD到包含相关DLL的目录

  3. 运行这样的corflags: corflags MyAssembly.dll

  4. 您将获得如下输出:

        Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  3.5.21022.8
    Copyright (c) Microsoft Corporation.  All rights reserved.
    
    Version   : v2.0.50727
    CLR Header: 2.5
    PE        : PE32
    CorFlags  : 3
    ILONLY    : 1
    32BIT     : 1
    Signed    : 0
    

    根据评论,上面的标志应如下所示:

    • 任何CPU:PE = PE32和32BIT = 0
    • x86:PE = PE32且32BIT = 1
    • 64位:PE = PE32 +和32BIT = 0

答案 3 :(得分:18)

你怎么写自己的?自从在Windows 95中实现以来,PE体系结构的核心并没有被严重改变。这是一个C#示例:

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    if (bReader.ReadUInt16() == 23117) //check the MZ signature
                    {
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                        if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                        {
                            fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                            architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                        }
                    }
                }
            }
        }
        catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */}
        //if architecture returns 0, there has been an error.
        return architecture;
    }
}

现在的常量是:

0x10B - PE32  format.
0x20B - PE32+ format.

但是使用这种方法,它允许新常量的可能性,只需根据需要验证返回。

答案 4 :(得分:9)

尝试使用CorFlagsReader from this project at CodePlex。它没有引用其他程序集,可以按原样使用。

答案 5 :(得分:6)

[TestMethod]
public void EnsureKWLLibrariesAreAll64Bit()
{
    var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(x => x.FullName.StartsWith("YourCommonProjectName")).ToArray();
    foreach (var assembly in assemblies)
    {
        var myAssemblyName = AssemblyName.GetAssemblyName(assembly.FullName.Split(',')[0] + ".dll");
        Assert.AreEqual(ProcessorArchitecture.MSIL, myAssemblyName.ProcessorArchitecture);
    }
}

答案 6 :(得分:5)

来自JetBrians的DotPeek提供了快速简便的方法来查看msil(anycpu),x86,x64 dotPeek

答案 7 :(得分:4)

下面是一个批处理文件,它将针对当前工作目录和所有子目录中的所有corflags.exedlls运行exes,解析结果并显示每个目标体系结构

根据所使用的corflags.exe版本,输出中的订单项将包含32BIT 32BITREQ(以及{{1 }})。输出中包含这两者中的哪一项是必须检查以区分32BITPREFAny CPU的关键行项目。如果您使用的是较旧版本的x86(Windows SDK v8.0A之前版本),那么输出中只会显示corflags.exe订单项,正如其他人在过去的答案中所指出的那样。否则32BIT32BITREQ会替换它。

这假设32BITPREF位于corflags.exe。确保这一点的最简单方法是使用%PATH%。或者,您可以从default location复制它。

如果针对非托管Developer Command Promptdll运行以下批处理文件,则会将其错误地显示为exe,因为x86的实际输出将是错误消息类似于:

  

corflags:错误CF008:指定的文件没有有效的托管标题

Corflags.exe

答案 8 :(得分:2)

另一种方法是在DLL上使用Visual Studio工具中的dumpbin并查找适当的输出

dumpbin.exe /HEADERS <your dll path>
    FILE HEADER VALUE
                 14C machine (x86)
                   4 number of sections
            5885AC36 time date stamp Mon Jan 23 12:39:42 2017
                   0 file pointer to symbol table
                   0 number of symbols
                  E0 size of optional header
                2102 characteristics
                       Executable
                       32 bit word machine
                       DLL

注意:上面的o / p适用于32位dll

dumpbin.exe的另一个有用选项是/ EXPORTS,它会显示dll公开的函数

dumpbin.exe /EXPORTS <PATH OF THE DLL>

答案 9 :(得分:2)

我已经克隆了一个超级方便的工具,该工具在Windows资源管理器中为程序集添加了一个上下文菜单项,以显示所有可用信息:

在这里下载: https://github.com/tebjan/AssemblyInformation/releases

enter image description here

答案 10 :(得分:1)

检查.NET程序集的目标平台的另一种方法是使用.NET Reflector检查程序集...

@#〜#€〜!我刚刚意识到新版本不是免费的!因此,更正,如果您有免费版本的.NET反射器,您可以使用它来检查目标平台。

答案 11 :(得分:1)

cfeduke指出调用GetPEKind的可能性。从PowerShell执行此操作可能很有趣。

例如,这里是可以使用的cmdlet代码:https://stackoverflow.com/a/16181743/64257

或者,在https://stackoverflow.com/a/4719567/64257注意到“PowerShell Community Extensions中还有可用于测试可执行映像的Get-PEHeader cmdlet。”

答案 12 :(得分:1)

您可以在此处找到更高级的应用程序:CodePlex - ApiChange

示例:

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\winhlp32.exe
File Name; Type; Size; Processor; IL Only; Signed
winhlp32.exe; Unmanaged; 296960; X86

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\HelpPane.exe
File Name; Type; Size; Processor; IL Only; Signed
HelpPane.exe; Unmanaged; 733696; Amd64

答案 13 :(得分:0)

更通用的方法 - 使用文件结构来确定位数和图像类型:

public static CompilationMode GetCompilationMode(this FileInfo info)
{
    if (!info.Exists) throw new ArgumentException($"{info.FullName} does not exist");

    var intPtr = IntPtr.Zero;
    try
    {
        uint unmanagedBufferSize = 4096;
        intPtr = Marshal.AllocHGlobal((int)unmanagedBufferSize);

        using (var stream = File.Open(info.FullName, FileMode.Open, FileAccess.Read))
        {
            var bytes = new byte[unmanagedBufferSize];
            stream.Read(bytes, 0, bytes.Length);
            Marshal.Copy(bytes, 0, intPtr, bytes.Length);
        }

        //Check DOS header magic number
        if (Marshal.ReadInt16(intPtr) != 0x5a4d) return CompilationMode.Invalid;

        // This will get the address for the WinNT header  
        var ntHeaderAddressOffset = Marshal.ReadInt32(intPtr + 60);

        // Check WinNT header signature
        var signature = Marshal.ReadInt32(intPtr + ntHeaderAddressOffset);
        if (signature != 0x4550) return CompilationMode.Invalid;

        //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER
        var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24);

        var result = CompilationMode.Invalid;
        uint clrHeaderSize;
        if (magic == 0x10b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4);
            result |= CompilationMode.Bit32;
        }
        else if (magic == 0x20b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4);
            result |= CompilationMode.Bit64;
        }
        else return CompilationMode.Invalid;

        result |= clrHeaderSize != 0
            ? CompilationMode.CLR
            : CompilationMode.Native;

        return result;
    }
    finally
    {
        if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr);
    }
}

编译模式枚举

[Flags]
public enum CompilationMode
{
    Invalid = 0,
    Native = 0x1,
    CLR = Native << 1,
    Bit32 = CLR << 1,
    Bit64 = Bit32 << 1
}

包含GitHub

说明的源代码

答案 14 :(得分:0)

Telerik JustDecompile(免费工具)是已经提到的工具的替代方法,它将在程序集名称旁边显示信息:

Any or x86 or x64 information in Telerik

答案 15 :(得分:0)

我喜欢ILSpy 工具。它不仅展示了架构,还展示了目标框架:

// linq2db, Version=3.0.0.0, Culture=neutral, PublicKeyToken=e41013125f9e410a
// Global type: <Module>
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// This assembly is signed with a strong name key.
// This assembly was compiled using the /deterministic option.
// Hash algorithm: SHA1

因此可以确定它是 .Net Core 2.1、.Net Framework 4.6 还是其他任何一个:

target framework