检查 DLL 文件是否为 Win32 DLL 或者是否为 CLR 程序集的最佳方法是什么。目前我使用这段代码

    try
    {
        this.currentWorkingDirectory = Path.GetDirectoryName(assemblyPath);

        //Try to load the assembly.
        assembly = Assembly.LoadFile(assemblyPath);

        return assembly != null;
    }
    catch (FileLoadException ex)
    {
        exception = ex;
    }
    catch (BadImageFormatException ex)
    {
        exception = ex;
    }
    catch (ArgumentException ex)
    {
        exception = ex;
    }
    catch (Exception ex)
    {
        exception = ex;
    }

    if (exception is BadImageFormatException)
    {
        return false;
    }

但我喜欢在加载之前进行检查,因为我不希望出现这些异常(时间)。

有没有更好的办法?

有帮助吗?

解决方案

检查PE头:

DOS标头始于0x0,DWORD在0x3C处包含一个指向PE签名(通常为0x80)的指针,即4个字节,接下来的20个字节是COFF标题,然后是PE标头(0x9。PE标头为224个字节,并包含数据目录(在96个字节中,PE标头= 0xF。第15个条目(在0x16是CLR标题描述符(有时称为COM描述符,但这与COM无关)。如果这是空的(即8个字节中的0 x168到0x16f),则文件不是.NET组件。如果要检查是否是com dll,则应该查看它是否导出getClassObject。

参考号

更新:有一种更“.NET”的方式来实现这一点:

使用 Module.GetPEKind 方法并检查 PortableExecutableKinds 枚举:

不是可移植可执行映像 该文件不在便携式可执行文件(PE)文件格式中。

仅IL 可执行文件仅包含Microsoft中间语言(MSIL),因此相对于32位或64位平台是中性的。

需要32位 可执行文件可以在32位平台上运行,也可以在64位平台上的Windows(WOW)环境上的32位窗口中运行。

PE32Plus 可执行文件需要 64 位平台。

非托管32位 可执行文件包含纯非托管代码。

其他提示

如果加载了程序集,例如 Assembly.LoadFile(dotNetDllorExe) 并且不会抛出任何异常,它是一个有效的 .NET 程序集。如果不是,则会抛出“BadImageFormatException”。

通过加载文件并检查是否抛出异常来检查文件是否为汇编的想法;看起来不太干净。毕竟异常应该被异常地使用。


.NET 程序集是常规的 Win32 PE 文件,操作系统不区分 .NET 程序集和 Win32 可执行二进制文件,它们是相同的普通 PE 文件。那么,如果 DLL 或 EXE 是托管程序集,系统如何计算以加载 CLR?

它验证文件头以检查它是否是托管程序集。在与 .NET SDK 一起提供的 ECMA 规范分区 II – 元数据中,您会看到 PE 格式中有一个单独的 CLI 标头。它是 PE可选头中的第15个数据目录. 。因此,简单来说,如果我们在这个数据目录中有价值,那么就意味着这是一个有效的 .NET 程序集,否则就不是。

internal static class PortableExecutableHelper
{
    internal static bool IsDotNetAssembly(string peFile)
    {
        uint peHeader;
        uint peHeaderSignature;
        ushort machine;
        ushort sections;
        uint timestamp;
        uint pSymbolTable;
        uint noOfSymbol;
        ushort optionalHeaderSize;
        ushort characteristics;
        ushort dataDictionaryStart;
        uint[] dataDictionaryRVA = new uint[16];
        uint[] dataDictionarySize = new uint[16];


        Stream fs = new FileStream(peFile, FileMode.Open, FileAccess.Read);
        BinaryReader reader = new BinaryReader(fs);

        //PE Header starts @ 0x3C (60). Its a 4 byte header.
        fs.Position = 0x3C;

        peHeader = reader.ReadUInt32();

        //Moving to PE Header start location...
        fs.Position = peHeader;
        peHeaderSignature = reader.ReadUInt32();

        //We can also show all these value, but we will be       
        //limiting to the CLI header test.

        machine = reader.ReadUInt16();
        sections = reader.ReadUInt16();
        timestamp = reader.ReadUInt32();
        pSymbolTable = reader.ReadUInt32();
        noOfSymbol = reader.ReadUInt32();
        optionalHeaderSize = reader.ReadUInt16();
        characteristics = reader.ReadUInt16();

        /*
            Now we are at the end of the PE Header and from here, the
                        PE Optional Headers starts...
                To go directly to the datadictionary, we'll increase the      
                stream’s current position to with 96 (0x60). 96 because,
                        28 for Standard fields
                        68 for NT-specific fields
            From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,
            doing simple maths 128/16 = 8.
            So each directory is of 8 bytes.
                        In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.

            btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
     */
        dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
        fs.Position = dataDictionaryStart;
        for (int i = 0; i < 15; i++)
        {
            dataDictionaryRVA[i] = reader.ReadUInt32();
            dataDictionarySize[i] = reader.ReadUInt32();
        }
        if (dataDictionaryRVA[14] == 0)
        {
            Console.WriteLine("This is NOT a valid CLR File!!");
            return false;
        }
        else
        {
            Console.WriteLine("This is a valid CLR File..");
            return true;
        }
        fs.Close();
    }
}

ECMA 参考, 博客参考

过去面对同样的问题,我求助于使用你的反射方法,因为替代方法是手动读取PE头 像这样. 。对于我的场景来说似乎有点矫枉过正,但它可能对你有用。

您没有指定你是否有这样做的代码,或者如果你只是个人需要你觉得这可能需要你写知道,如果你正在寻找在你的系统上的文件是一个.NET组件(您自己的代码来做到这一点)。如果是后者,则可以使用的Dependency Walker,看它是否具有对MSCOREE.DLL的依赖性,这是.NET运行时引擎。

您可以使用类似:

        AssemblyName assemblyName = null;

        try
        {
            assemblyName = AssemblyName.GetAssemblyName(filename);
        }
        catch (System.IO.FileNotFoundException ex)
        {
            throw new Exception("File not found!", ex);
        }
        catch (System.BadImageFormatException ex)
        {
            throw new Exception("File is not an .Net Assembly.", ex);
        }

请还检查了: https://msdn.microsoft.com/en -us /库/ ms173100.aspx

您可以从文件中读取前两个字节,如果字节是“MZ”,则尝试读取程序集名称以确定(微软慢速方式) 装配的有效性。

    public static bool isValidAssembly (string sFileName)
    {
        try
        {
            using (FileStream fs = File.OpenRead(sFileName))
            {
                if ((fs.ReadByte() != 'M') || (fs.ReadByte() != 'Z'))
                {
                    fs.Close();
                    return false;
                }
                fs.Close();
            }

            // http://msdn.microsoft.com/en-us/library/ms173100.aspx
            object foo = SR.AssemblyName.GetAssemblyName(sFileName);
            return true;
        }
        catch 
        {
            return false;
        }
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top