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

如何确定.NET程序集是为x86还是x64生成的?,.net,assemblies,x86,64-bit,x86-64,.net,Assemblies,X86,64 Bit,X86 64,我有一个任意的.NET程序集列表 我需要以编程方式检查每个DLL是否是为x86(而不是x64或任何CPU)构建的。这是否可行?您可以使用该工具(例如,C:\Program Files\Microsoft SDK\Windows\v7.0\Bin\CorFlags.exe)根据程序集的输出和以二进制资源打开程序集来确定程序集的状态。您应该能够确定需要在何处查找以确定32位标志设置为1(x86)还是0(任何CPU或x64,取决于PE): 这篇博文中有一些关于corflags的信息 更好的是,您可以确

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

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

您可以使用该工具(例如,C:\Program Files\Microsoft SDK\Windows\v7.0\Bin\CorFlags.exe)根据程序集的输出和以二进制资源打开程序集来确定程序集的状态。您应该能够确定需要在何处查找以确定32位标志设置为1(x86)还是0(任何CPU或x64,取决于
PE
):

这篇博文中有一些关于corflags的信息


更好的是,您可以确定一个程序集是
portableexecutabletypes
value
PE32Plus
(64位)、
Required32Bit
(32位和WOW),还是
ILOnly
(任何CPU)以及其他属性。

查看
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... [36]C:\>[reflection.assemblyname]::GetAssemblyName(“${pwd}\Microsoft.GLEE.dll”)| fl 名称:Microsoft.GLEE 版本:1.0.0.0 文化资讯: 代码库:file:///C:/projects/powershell/BuildAnalyzer/... 转义代码库:file:///C:/projects/powershell/BuildAnalyzer/... 处理器架构:MSIL 标志:公钥 哈希算法:SHA1 版本兼容性:同一台机器 密钥对: 全名:Microsoft.GLEE,版本=1.0.0.0,区域性=neut。。。 这里,标识目标平台

  • Amd64:基于x64体系结构的64位处理器
  • Arm:一种Arm处理器
  • IA64:仅限64位英特尔安腾处理器
  • MSIL:与处理器和每个字的位无关
  • X86:32位英特尔处理器,本机或在64位平台(WOW64)上的Windows on Windows环境中
  • :处理器和每个字的位的未知或未指定的组合

在本例中,我使用PowerShell调用该方法。

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

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

  • CD到包含有问题的DLL的目录

  • 运行以下命令:
    corflags MyAssembly.dll

  • 您将得到如下输出:

    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,32位=0
    • x86:PE=PE32,32位=1
    • 64位:PE=PE32+和32位=0

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


    @#~#€~!我刚刚意识到新版本不是免费的!因此,更正一下,如果你有一个免费版本的.NET reflector,你可以用它来检查目标平台。

    你自己写怎么样?PE体系结构的核心自在Windows 95中实现以来没有发生过重大变化。下面是一个C#示例:

    现在,当前常数为:

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

    但是,使用此方法,它允许使用新常量,只需验证您认为合适的返回值。

    尝试使用CorFlagsReader。它没有对其他程序集的引用,可以按原样使用。

    cfeduke注意到调用GetPEKind的可能性。从PowerShell执行此操作可能会很有趣

    例如,下面是可以使用的cmdlet的代码:


    或者,注意到“中还有Get-PEHeader cmdlet,可用于测试可执行映像。”

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

    根据所使用的
    corflags.exe
    版本,输出中的行项目将包括
    32BIT
    ,或
    32BITREQ
    (和
    32bitref
    )。输出中包含的这两项中的任何一项都是必须检查的关键行项目,以区分
    任何CPU
    x86
    。如果您使用的是较旧版本的
    corflags.exe
    (Windows SDK v8.0A之前版本),则只有
    32BIT
    行项目将出现在输出中,正如其他人在过去的回答中所指出的那样。否则
    32BITREQ
    32bitref
    将其替换

    这假设
    corflags.exe
    位于
    %PATH%
    中。确保这一点的最简单方法是使用
    开发人员命令提示符
    。或者,您可以从它的

    如果下面的批处理文件是针对非托管的
    dll
    exe
    运行的,它将错误地将其显示为
    x86
    ,因为
    Corflags.exe
    的实际输出将是一条类似于以下内容的错误消息:

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


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

    示例:

    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
    

    另一种方法是在DLL上使用VisualStudioTools中的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
    
    dumpbin.exe/HEADERS
    文件头值
    14C机器(x86)
    4节数
    5885AC36时间日期戳2017年1月23日星期一12:39:42
    0指向符号表的文件指针
    0符号数
    
    [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);
        }
    }
    
    @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.
    
    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
    
    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
    
    dumpbin.exe /EXPORTS <PATH OF THE DLL>
    
    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
    }
    
    // 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