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

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


当前回答

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

其他回答

你自己写就行了。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。

JetBrains的DotPeek提供了一个快速简单的方法来查看msil(任何CPU), x86和x64:

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

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

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

博客文章x64 Development with . net有一些关于corflags的信息。

更好的是,您可以使用Module。GetPEKind来确定程序集是否为portableexecutabletypes值PE32Plus(64位)、Required32Bit(32位和WoW)或ILOnly(任何CPU)以及其他属性。