352

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

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

4

16 回答 16

330

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

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

使用PowerShell

[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | 佛罗里达州

名称:Microsoft.GLEE
版本:1.0.0.0
文化信息:
代码库:file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase : file:///C:/projects/powershell/BuildAnalyzer/...
处理器架构:MSIL
标志:公钥
哈希算法:SHA1
版本兼容性:SameMachine
密钥对:
全名:Microsoft.GLEE,版本=1.0.0.0,文化=中性...

在这里,ProcessorArchitecture标识目标平台。

  • Amd64:基于 x64 架构的 64 位处理器。
  • Arm:一个ARM处理器。
  • IA64:仅限 64 位 Intel Itanium 处理器。
  • MSIL:与处理器和每字位数无关。
  • X86:32 位 Intel 处理器,本机或在 64 位平台 (WOW64) 上的 Windows on Windows 环境中。
  • :处理器和每字位数的未知或未指定组合。

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

于 2008-11-06T22:20:18.830 回答
234

您可以使用CorFlags CLI工具(例如,C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\CorFlags.exe)根据其输出确定程序集的状态并将程序集作为二进制资产,您应该能够确定需要寻找的位置,以确定 32BIT 标志是设置为 1(x86)还是 0(任何 CPUx64,具体取决于PE):

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

博客文章x64 Development with .NET提供了一些关于 .NET 的信息corflags

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

于 2008-11-06T22:19:37.647 回答
152

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

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

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

  3. 像这样运行标志: 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 和 32BIT = 0
  • x86:PE = PE32 和 32BIT = 1
  • 64 位:PE = PE32+ 和 32BIT = 0
于 2009-06-16T17:11:02.630 回答
23

你自己写怎么样?自从在 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.

但是使用这种方法,它允许新常量的可能性,只需在您认为合适的情况下验证返回即可。

于 2012-03-19T09:31:37.677 回答
14

JetBrains 的 DotPeek 提供了查看 msil(anycpu)、x86、x64 的快捷方式 点窥

于 2017-08-22T07:20:43.880 回答
9

尝试在 CodePlex 的这个项目中使用 CorFlagsReader 。它没有对其他程序集的引用,可以按原样使用。

于 2013-02-18T12:45:49.010 回答
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);
    }
}
于 2013-09-26T18:11:44.783 回答
5

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

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

这假设corflags.exe%PATH%. 确保这一点的最简单方法是使用Developer Command Prompt. 或者,您可以从它的默认位置复制它。

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

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.
于 2016-03-30T17:53:42.840 回答
4

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

在此处下载: https ://github.com/tebjan/AssemblyInformation/releases

在此处输入图像描述

于 2018-08-18T18:06:49.690 回答
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 为 32bit dll

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

dumpbin.exe /EXPORTS <PATH OF THE DLL>
于 2017-07-28T04:49:15.783 回答
2

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

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 上带有解释的源代码

于 2018-03-27T15:08:19.850 回答
1

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

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

于 2011-08-04T07:56:59.720 回答
1

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

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

或者,在https://stackoverflow.com/a/4719567/64257中指出“ PowerShell 社区扩展中还有 Get-PEHeader cmdlet,可用于测试可执行映像。”

于 2013-04-24T01:19:59.057 回答
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
于 2016-10-04T12:12:36.240 回答
0

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

Telerik 中的任何或 x86 或 x64 信息

于 2020-05-19T11:30:02.577 回答
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 还是其他任何一个:

目标框架

于 2021-04-14T22:48:39.150 回答