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

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


当前回答

一个工具是sigcheck:

sigcheck c:\Windows\winhlp32.exe

输出:

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

输出:

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

其他回答

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

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

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

还有一种方法是在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

注意:上面的输出是一个32位DLL文件

dumpbin.exe的一个更有用的选项是/EXPORTS。它将显示DLL文件公开的函数

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

你自己写就行了。PE架构的核心自从在Windows 95中实现以来就没有发生过重大变化。

下面是一个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;
    }
}

现在的常数是:

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

但是用这种方法,它允许新常数的可能性。只要验证你认为合适的返回。

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

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。