c# – 如何确定DLL是一个托管程序集还是本机(阻止加载本机DLL)?

原始标题:如何防止从.NET应用程序加载本地DLL?

背景:

我的C#应用​​程序包括一个插件框架和通用插件加载程序。

插件加载程序枚举应用程序目录,以识别插件dll(本质上它在此时搜索* .dll)。

在同一应用程序目录中是一个本机(Windows,non.net)dll,间接地,一个插件DLL依赖于它。

插件加载器盲目地假定native.dll是一个.NET程序集DLL,只是因为它只检查文件扩展名。当它尝试加载本机dll时,会抛出异常:

“无法加载文件或程序集”native.dll“或其依赖项之一,该模块预计将包含程序集清单。

我基本上创建一个诊断报告,如果插件加载失败,所以我试图避免这个日志填满了无法加载本机dll(我甚至不想尝试)的消息。

问题:

有没有一些.NET API调用,我可以使用它来确定一个二进制是否是一个.NET程序集,所以我不尝试加载本机的DLL?

也许更长的一段时间我会将我的插件移动到一个子目录,但现在我只想要一个工作,不涉及硬编码我的插件加载程序中的“native.dll”名称。

我想我正在寻找某种静态Assembly.IsManaged()API调用,我忽略了….可能没有这样的API存在?

最佳答案
lubos hasko引用的答案是好的,但它对64位程序集不起作用。这是一个更正版本(灵感来自http://apichange.codeplex.com/SourceControl/changeset/view/76c98b8c7311#ApiChange.Api/src/Introspection/CorFlagsReader.cs)

public static bool IsManagedAssembly(string fileName)
{
    using (Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    using (BinaryReader binaryReader = new BinaryReader(fileStream))
    {
        if (fileStream.Length < 64)
        {
            return false;
        }

        //PE Header starts @ 0x3C (60). Its a 4 byte header.
        fileStream.Position = 0x3C;
        uint peHeaderPointer = binaryReader.ReadUInt32();
        if (peHeaderPointer == 0)
        {
            peHeaderPointer = 0x80;
        }

        // Ensure there is at least enough room for the following structures:
        //     24 byte PE Signature & Header
        //     28 byte Standard Fields         (24 bytes for PE32+)
        //     68 byte NT Fields               (88 bytes for PE32+)
        // >= 128 byte Data Dictionary Table
        if (peHeaderPointer > fileStream.Length - 256)
        {
            return false;
        }

        // Check the PE signature.  Should equal 'PE\0\0'.
        fileStream.Position = peHeaderPointer;
        uint peHeaderSignature = binaryReader.ReadUInt32();
        if (peHeaderSignature != 0x00004550)
        {
            return false;
        }

        // skip over the PEHeader fields
        fileStream.Position += 20;

        const ushort PE32 = 0x10b;
        const ushort PE32Plus = 0x20b;

        // Read PE magic number from Standard Fields to determine format.
        var peFormat = binaryReader.ReadUInt16();
        if (peFormat != PE32 && peFormat != PE32Plus)
        {
            return false;
        }

        // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
        // When this is non-zero then the file contains CLI data otherwise not.
        ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248));
        fileStream.Position = dataDictionaryStart;

        uint cliHeaderRva = binaryReader.ReadUInt32();
        if (cliHeaderRva == 0)
        {
            return false;
        }

        return true;
    }
}

缺少的部分是根据我们是PE32还是PE32Plus,偏移到数据字典开始的方式不同:

    // Read PE magic number from Standard Fields to determine format.
    var peFormat = binaryReader.ReadUInt16();
    if (peFormat != PE32 && peFormat != PE32Plus)
    {
        return false;
    }

    // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
    // When this is non-zero then the file contains CLI data otherwise not.
    ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248));

转载注明原文:c# – 如何确定DLL是一个托管程序集还是本机(阻止加载本机DLL)? - 代码日志