c# - 如何判断一个DLL是托管程序集还是原生(防止加载原生dll)?

标签 c# plugins dll assemblies native

原标题:如何防止从 .NET 应用程序加载 native dll?

背景:

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

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

在同一应用程序目录中有一个 native (Windows、非 .net)dll,其中一个插件 dll 间接依赖于它。

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

“无法加载文件或程序集‘native.dll’或其依赖项之一。该模块应包含程序集 list 。”

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

问题:

是否有一些 .NET API 调用可用于确定二进制文件是否恰好是 .NET 程序集,以便我根本不会尝试加载 native 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)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/367761/

相关文章:

c# - 简单的视频编辑应用程序——我应该使用 WPF 还是 MFC?

c# - 如何通过互操作公开 COM 库中定义的枚举作为 C# 函数的返回类型

c# - LINQ 查询以识别系列中的片段

plugins - 成语Rust插件系统

javascript - 具有多种方法的 jQuery 插件

c++ - 如何修复 C++ DLL 中未解析的外部符号错误?

dll - F# 有自己的字符串操作库吗?

c# - 您可以在自己的初始化行中使用变量(字典中的 tryGetOrElse)吗?

api - 开发谷歌浏览器插件(没有扩展!)

java - 使用 JNA 从 Java 调用 DLL