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


327

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

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



2
您可能还需要检查以下一项:check-if-unmanaged-dll-is-32-bit-或-64-bit
马特2015年

2
在与.NET 4.5对应的更高版本的CorFlags中,“ 32BIT”被“ 32BITREQ”​​和“ 32BITPREF”代替。
Peter Mortensen

Answers:


280

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

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

使用PowerShell

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

名称:Microsoft.GLEE
版本:1.0.0.0
CultureInfo:
代码库:file:/// C:/ projects / powershell / BuildAnalyzer / ...
EscapedCodeBase:file:/// C:/ projects / powershell / BuildAnalyzer / ...
处理器架构:MSIL
标志:公钥
哈希算法:SHA1
版本兼容性:SameMachine
密钥对:
FullName:Microsoft.GLEE,Version = 1.0.0.0,Culture = neut ... 

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

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

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


60
原谅这个愚蠢的问题-但是,这能告诉您x86是什么?
George Mauer 2012年

53
ProcessorArchitecture字段是一个枚举;在上面的示例中,将其设置为MSIL,表示“对于处理器和每字位数为中性”。其他值包括X86,IA64,Amd64。有关更多详细信息,请参见msdn.microsoft.com/en-us/library/…
Brian Gillespie 2012年

4
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")有时尝试使用该进程的当前目录与当前提供程序的目录不同(这是我认为DLL适合您的位置)
x0n

2
需要注意的另一个警告是,如果您是从互联网上下载的,则忘记“解除阻止”该DLL。使用取消阻止文件,或右键单击/属性/从资源管理器取消阻止。如果您在当前会话中已经失败了一次,则需要重新启动外壳以识别其畅通状态(对此归咎于Internet Explorer)-是的,是的
。–

1
在ASP.NET MVC代码中,有一个注释,// DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.可悲的是,如果不使用GetName instance method; ,就无法读取ProcessorArchitecture 。使用时AssemblyName constructor,该字段始终设置为None
metadings 2014年

221

您可以使用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通过.NET开发具有有关.NET的一些信息corflags

更好的是,可以使用Module.GetPEKind以确定一个集是否PortableExecutableKindsPE32Plus(64位),Required32Bit(32位和WOW),或者ILOnly(在任何CPU)与其他的属性。


1
看到您的更新后,使用GetPEKind似乎是执行此操作的正确方法。我已将您的答案标记为答案。
Judah Gabriel Himango,

9
检查32位程序集时,GetPEKind在64位进程中失败
jjxtra 2010年

2
您必须从32bit进程调用GetPEKind
Ludwo

2
我安装了VS 2008,VS 2010,VS 2012和VS2013。在C:\ Program Files(x86)\ Microsoft SDKs \ Windows \的子文件夹中有8个文件CorFlags.exe。我应该使用哪个?
Kiquenet 2014年

5
如此答案所指出的,.NET 4.5中有32BITREQ和32BITPREF而不是32BIT标志。PE32 / 0/0和PE32 / 0/1分别是32位AnyCPU和AnyCPU首选。
angularsen,2015年

141

只是为了澄清起见,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

您将获得如下输出:

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

12
同时,这似乎已经改变了。现在显示corflags 32BITREQ32BITPREF而不是单个32BIT值。
OR Mapper

1
Microsoft .NET 4.5引入了一个新选项,即“首选32位CPU”。是详细信息。
RBT

如今,“ Visual Studio命令提示符”被称为“ Visual Studio 2019开发人员命令提示符 ”。
乌威·基姆

22

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

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


1
有趣,感谢您提供解释的代码。Module.GetPEKind可能是最简单的路径。但这对学习很有帮助。谢谢。
Judah Gabriel Himango 2012年

3
非常有趣,但是当我使用任何CPU编译应用程序时,结果为0x10B。这是错误的,因为我的应用程序在x64系统上运行。还有其他标志要检查吗?
塞缪尔

GetPEArchitecture适用于使用.net 3.5、4.0、4.5和4.5.1编译的程序集?无论如何,我认为,当检查​​32位程序集时,Module.GetPEKind在64位进程中失败。
Kiquenet 2014年



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

为此,我们的应用程序之一必须构建为x86,添加一个单元测试可确保构建服务器的构建库为32位,并避免发生这些错误:)
2015年

5

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

取决于版本corflags.exe所使用,在输出线的项目将包括32BIT 32BITREQ(及32BITPREF)。输出中包括这两者中的哪一个是关键行项目,必须对其进行检查以区分Any CPUx86。如果您使用的是旧版corflags.exe(Windows SDK v8.0A之前的版本),则32BIT输出中将仅显示该订单项,如其他人在过去的答案中指出的那样。否则32BITREQ,请32BITPREF更换它。

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

如果下面的批处理文件是针对非托管dll或运行的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.

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>

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源代码



1

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

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


9
使用ILSpy,这是一个基本的开源应用程序,其功能与Reflector相同
二进制杞人忧天


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.