如何确定一个DLL是一个托管程序集还是一个本机(阻止加载本地DLL)? [英] How to determine whether a DLL is a managed assembly or native (prevent loading a native dll)?
问题描述
背景:
我的C#应用程序包含一个插件框架和通用插件加载器。
My C# application includes a plugin framework and generic plugin loader.
插件加载程序枚举应用程序目录,以识别插件dll本质上它在此时搜索* .dll)。
The plugin loader enumerates the application directory in order to identify plugin dlls (essentially it searches for *.dll at this time).
在同一个应用程序目录中是一个本机(Windows,non-.net)dll,间接地,一个插件DLL依赖于。
Within the same application directory is a native (Windows, non-.net) dll, which, indirectly, one of the plugin dlls depends upon.
插件加载器盲目地假定native.dll是一个.NET程序集DLL,只是因为它只检查文件扩展名。当它尝试加载本机dll时,会抛出异常:
The plugin loader blindly assumes that the native.dll is a .NET Assembly dll, simply because it only checks the file extension. When it attempts to load the native dll, an exception is thrown:
无法加载文件或程序集native.dll或其依赖项之一。预计会包含一个程序集清单。
"Could not load file or assembly 'native.dll' or one of its dependencies. The module was expected to contain an assembly manifest."
如果插件加载失败,我基本上创建一个诊断报告,所以我试图避免让这个日志填满不了能够加载本机dll(我甚至不想尝试)。
I basically create a diagnostic report if plugin loading fails, so I'm trying to avoid having this log filled up with messages about not being able to load the native dll (which I don't even want to attempt).
问题:
是否有一些.NET API调用,可以用来确定二进制文件是否恰好是.NET程序集,以便我不会尝试加载本机的dll?
Is there some .NET API call that I can use to determine whether a binary happens to be a .NET assembly so that I don't attempt to load the native dll at all?
也许更长的一段时间我会将我的插件移动到一个子目录,但现在我只是想要一个不涉及硬编码native.dll名称的内容我的插件加载器
Perhaps longer term I will move my plugins to a subdirectory, but for now, I just want a work around that doesn't involve hard-coding the "native.dll" name inside my plugin loader.
我想我正在寻找某种静态Assembly.IsManaged()API调用,我忽略了....可能没有这样的API存在? p>
I guess I'm looking for some kind of static Assembly.IsManaged() API call that I've overlooked.... presumably no such API exists?
推荐答案
由lubos hasko引用的答案是好的,但它不适用于64位程序集。这是一个更正版本(灵感来自 http: //apichange.codeplex.com/SourceControl/changeset/view/76c98b8c7311#ApiChange.Api/src/Introspection/CorFlagsReader.cs )
Answer quoted by lubos hasko is good but it doesn't work for 64-bit assemblies. Here's a corrected version (inspired by 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:
The missing piece was to offset to the data dictionary start differently depending on whether we are PE32 or 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));
这篇关于如何确定一个DLL是一个托管程序集还是一个本机(阻止加载本地DLL)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!