首页 文章

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

提问于
浏览
292

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

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

14 回答

  • 4

    看看 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位Intel处理器,可以是64位平台(WOW64)上的本机或Windows环境中的Windows .

    • None :处理器和每字位数的未知或未指定组合 .

    我在这个例子中使用PowerShell来调用该方法 .

  • 1

    您可以使用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)以及其他属性 .

  • 17

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

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

    • CD到包含相关DLL的目录

    • 像这样运行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

  • 0

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

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

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

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

  • 2

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

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

    假设 corflags.exe%PATH% 中 . 确保这一点的最简单方法是使用 Developer Command Prompt . 或者你可以从它的default location复制它 .

    如果下面的批处理文件针对非托管 dllexe 运行,它将错误地将其显示为 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.
    
  • 5

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

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

    enter image description here

  • 133

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

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

  • 212

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

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

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

  • 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
    
  • 242

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

    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

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

    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解释

相关问题