简体   繁体   English

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

[英]How can I determine if a .NET assembly was built for x86 or x64?

I've got an arbitrary list of .NET assemblies.我有一个任意的.NET 程序集列表。

I need to programmatically check if each DLL was built for x86 (as opposed to x64 or Any CPU).我需要以编程方式检查每个 DLL 是否是为 x86(而不是 x64 或任何 CPU)构建的。 Is this possible?这可能吗?

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

You can examine assembly metadata from the returned AssemblyName instance:您可以从返回的 AssemblyName 实例中检查程序集元数据:

Using PowerShell :使用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...

Here, ProcessorArchitecture identifies the target platform.在这里, ProcessorArchitecture标识了目标平台。

  • Amd64 : A 64-bit processor based on the x64 architecture. Amd64 :基于 x64 架构的 64 位处理器。
  • Arm : An ARM processor. Arm :一个ARM处理器。
  • IA64 : A 64-bit Intel Itanium processor only. IA64 :仅限 64 位 Intel Itanium处理器。
  • MSIL : Neutral with respect to processor and bits-per-word. MSIL :与处理器和每字位数无关。
  • X86 : A 32-bit Intel processor, either native or in the Windows on Windows environment on a 64-bit platform ( WoW64 ). X86 :32 位 Intel 处理器,本机或在 64 位平台 ( WoW64 ) 上的 Windows on Windows 环境中。
  • None : An unknown or unspecified combination of processor and bits-per-word.:处理器和每字位数的未知或未指定组合。

I'm using PowerShell in this example to call the method.在此示例中,我使用 PowerShell 来调用该方法。

You can use the CorFlags CLI tool (for instance, C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe) to determine the status of an assembly, based on its output and opening an assembly as a binary asset you should be able to determine where you need to seek to determine if the 32BIT flag is set to 1 ( x86 ) or 0 ( Any CPU or x64 , depending on PE ):您可以使用CorFlags CLI工具(例如,C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe)根据其输出确定程序集的状态并将程序集作为二进制资产,您应该能够确定需要寻找的位置,以确定 32BIT 标志是设置为 1 ( x86 ) 还是 0 ( Any CPU or x64 ,具体取决于PE ):

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

The blog post x64 Development with .NET has some information about corflags .博客文章x64 Development with .NET有一些关于corflags的信息。

Even better, you can use Module.GetPEKind to determine whether an assembly is PortableExecutableKinds value PE32Plus (64-bit), Required32Bit (32-bit and WoW ), or ILOnly (any CPU) along with other attributes.更好的是,您可以使用Module.GetPEKind来确定程序集是PortableExecutableKindsPE32Plus (64 位)、 Required32Bit (32 位和WoW )还是ILOnly (任何 CPU)以及其他属性。

Just for clarification, CorFlags.exe is part of the .NET Framework SDK .只是为了澄清,CorFlags.exe 是.NET Framework SDK的一部分。 I have the development tools on my machine, and the simplest way for me determine whether a DLL is 32-bit only is to:我的机器上有开发工具,确定 DLL 是否仅为 32 位的最简单方法是:

  1. Open the Visual Studio Command Prompt (In Windows: menu Start/Programs/Microsoft Visual Studio/Visual Studio Tools/Visual Studio 2008 Command Prompt)打开 Visual Studio 命令提示符(在 Windows 中:菜单开始/程序/Microsoft Visual Studio/Visual Studio 工具/Visual Studio 2008 命令提示符)

  2. CD to the directory containing the DLL in question CD 到包含相关 DLL 的目录

  3. Run corflags like this: corflags MyAssembly.dll像这样运行 corflags: corflags MyAssembly.dll

You will get output something like this:你会得到这样的输出:

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

As per comments the flags above are to be read as following:根据评论,上述标志应如下阅读:

  • Any CPU: PE = PE32 and 32BIT = 0任何 CPU:PE = PE32 和 32BIT = 0
  • x86: PE = PE32 and 32BIT = 1 x86:PE = PE32 和 32BIT = 1
  • 64-bit: PE = PE32+ and 32BIT = 0 64 位:PE = PE32+ 和 32BIT = 0

Just write your own.只写你自己的。 The core of the PE architecture hasn't been seriously changed since its implementation in Windows 95 . PE 体系结构的核心自从在Windows 95中实现以来并没有发生重大变化。

Here's a C# example:这是一个 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))
                {
                    // Check the MZ signature
                    if (bReader.ReadUInt16() == 23117)
                    {
                        // Seek to e_lfanew.
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current);

                        // Seek to the start of the NT header.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin);

                        if (bReader.ReadUInt32() == 17744) // Check the PE\0\0 signature.
                        {
                            // Seek past the file header,
                            fStream.Seek(20, System.IO.SeekOrigin.Current);

                            // Read the magic number of the optional header.
                            architecture = bReader.ReadUInt16();
                        }
                    }
                }
            }
        }
        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;
    }
}

Now the current constants are:现在的常数是:

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

But with this method it allows for the possibilities of new constants.但是通过这种方法,它允许新常量的可能性。 Just validate the return as you see fit.只需按照您认为合适的方式验证退货。

DotPeek from JetBrains provides a quick and easy way to see msil (Any CPU), x86, and x64: JetBrains的 DotPeek 提供了一种快速简便的方法来查看msil (任何 CPU)、x86 和 x64:

点窥

Try to use CorFlagsReader from this project at CodePlex .尝试在 CodePlex 的这个项目中使用 CorFlagsReader。 It has no references to other assemblies and it can be used as is.它没有对其他程序集的引用,可以按原样使用。

[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);
    }
}

Below is a batch file that will run corflags.exe against all DLL files and EXE files in the current working directory and all sub-directories, parse the results and display the target architecture of each.下面是一个批处理文件,它将针对当前工作目录和所有子目录中的所有 DLL 文件和 EXE 文件运行corflags.exe ,解析结果并显示每个目标体系结构。

Depending on the version of corflags.exe that is used, the line items in the output will either include 32BIT , or 32BITREQ (and 32BITPREF ).根据使用的corflags.exe版本,输出中的行项目将包括32BIT32BITREQ (和32BITPREF )。 Whichever of these two is included in the output is the critical line item that must be checked to differentiate between Any CPU and x86 .输出中包含这两者中的任何一个都是必须检查以区分Any CPUx86的关键行项目。 If you are using an older version of corflags.exe (pre Windows SDK v8.0A), then only the 32BIT line item will be present in the output, as others have indicated in past answers.如果您使用的是旧版本的corflags.exeWindows SDK v8.0A 之前的版本),那么输出中只会出现32BIT行项目,正如其他人在过去的答案中所指出的那样。 Otherwise 32BITREQ and 32BITPREF replace it.否则32BITREQ32BITPREF替换它。

This assumes corflags.exe is in the %PATH% .这假设corflags.exe%PATH%中。 The simplest way to ensure this is to use a Developer Command Prompt .确保这一点的最简单方法是使用Developer Command Prompt Alternatively you could copy it from its default location .或者,您可以从其默认位置复制它。

If the batch file below is run against an unmanaged DLL or EXE file, it will incorrectly display it as x86 , since the actual output from Corflags.exe will be an error message similar to:如果下面的批处理文件针对非托管 DLL 或 EXE 文件运行,它将错误地将其显示为x86 ,因为Corflags.exe的实际输出将是类似于以下内容的错误消息:

corflags : error CF008 : The specified file does not have a valid managed header corflags:错误 CF008:指定的文件没有有效的托管标头

@echo off

echo.
echo Target architecture for all exes and dlls:
echo.

REM For each exe and dll in this directory and all subdirectories...
for %%a in (.exe, .dll) do forfiles /s /m *%%a /c "cmd /c echo @relpath" > testfiles.txt

for /f %%b in (testfiles.txt) do (
    REM Dump corflags results to a text file
    corflags /nologo %%b > corflagsdeets.txt

   REM Parse the corflags results to look for key markers
   findstr /C:"PE32+">nul .\corflagsdeets.txt && (
      REM `PE32+` indicates x64
        echo %%~b = x64
    ) || (
      REM pre-v8 Windows SDK listed only "32BIT" line item,
      REM newer versions list "32BITREQ" and "32BITPREF" line items
        findstr /C:"32BITREQ  : 0">nul /C:"32BIT     : 0" .\corflagsdeets.txt && (
            REM `PE32` and NOT 32bit required indicates Any CPU
            echo %%~b = Any CPU
        ) || (
            REM `PE32` and 32bit required indicates x86
            echo %%~b = x86
        )
    )

    del corflagsdeets.txt
)

del testfiles.txt
echo.

I've cloned a super handy tool that adds a context menu entry for assemblies in Windows Explorer to show all available information:我克隆了一个超级方便的工具,它为Windows 资源管理器中的程序集添加上下文菜单条目以显示所有可用信息:

Download from Releases · tebjan/AssemblyInformation .Releases·tebjan/AssemblyInformation下载。

在此处输入图像描述

One more way would be to use dumpbin from the Visual Studio tools on the DLL and look for the appropriate output:另一种方法是在 DLL 上使用 Visual Studio 工具中的dumpbin并查找适当的输出:

dumpbin.exe /HEADERS <your DLL file 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

Note: The above output is for a 32-bit DLL file注意:以上输出是针对 32 位 DLL 文件的

One more useful option with dumpbin.exe is /EXPORTS. dumpbin.exe的另一个有用选项是 /EXPORTS。 It will show you the function exposed by the DLL file它将向您显示 DLL 文件公开的功能

dumpbin.exe /EXPORTS <PATH OF THE DLL FILE>

A more generic way - use the file structure to determine bitness and image type:一种更通用的方法 - 使用文件结构来确定位数和图像类型:

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

Compilation mode enumeration编译模式枚举

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

Source code with explanation is at GitHub .带有解释的源代码位于 GitHub

cfeduke notes the possibility of calling GetPEKind. cfeduke 注意到调用 GetPEKind 的可能性。 It's potentially interesting to do this from PowerShell.从 PowerShell 执行此操作可能很有趣。

Here, for example, is code for a cmdlet that could be used: https://stackoverflow.com/a/16181743/64257例如,这里是可以使用的 cmdlet 的代码: https ://stackoverflow.com/a/16181743/64257

Alternatively, at https://stackoverflow.com/a/4719567/64257 it is noted that "there's also the Get-PEHeader cmdlet in the PowerShell Community Extensions that can be used to test for executable images."或者,在https://stackoverflow.com/a/4719567/64257中指出“ PowerShell 社区扩展中还有 Get-PEHeader cmdlet,可用于测试可执行映像。”

A tool is sigcheck :一个工具是sigcheck

sigcheck c:\Windows\winhlp32.exe

Output:输出:

Sigcheck v2.71 - File version and signature viewer
Copyright (C) 2004-2018 Mark Russinovich
Sysinternals - www.sysinternals.com

c:\windows\winhlp32.exe:
        Verified:       Signed
        Signing date:   20:05 02.05.2022
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Windows Winhlp32 Stub
        Product:        Microsoft® Windows® Operating System
        Prod version:   10.0.19041.1
        File version:   10.0.19041.1 (WinBuild.160101.0800)
        MachineType:    32-bit

sigcheck -nobanner c:\Windows\HelpPane.exe

Output:输出:

c:\windows\HelpPane.exe:
        Verified:       Signed
        Signing date:   00:42 23.04.2022
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Microsoft Help and Support
        Product:        Microsoft® Windows® Operating System
        Prod version:   10.0.19041.1151
        File version:   10.0.19041.1151 (WinBuild.160101.0800)
        MachineType:    64-bit

Another way to check the target platform of a .NET assembly is inspecting the assembly with .NET Reflector ...检查 .NET 程序集的目标平台的另一种方法是使用.NET Reflector检查程序集...

@#~#€~! @#~#€~! I've just realized that the new version is not free!我刚刚意识到新版本不是免费的! So, correction, if you have a free version of .NET reflector, you can use it to check the target platform.所以,更正一下,如果你有一个免费版本的 .NET 反射器,你可以用它来检查目标平台。

An alternative to already mentioned tools is Telerik JustDecompile (free tool) which will display the information next to the assembly name:已经提到的工具的替代品是Telerik JustDecompile (免费工具),它将在程序集名称旁边显示信息:

Telerik 中的任何或 x86 或 x64 信息

I like the ILSpy tool.我喜欢ILSpy工具。 It shows not only architecture, but the target framework as well:它不仅展示了架构,还展示了目标框架:

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

So it is possible to determine if it is .NET Core 2.1, .NET Framework 4.6 or any other one:因此可以确定它是.NET Core 2.1、.NET Framework 4.6 还是其他任何一个:

目标框架

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM