检查DLL文件是否是C#中的CLR程序集的最佳方法

检查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开始,0x3c的DWORD包含指向PE签名的指针(通常为0x80),为4字节,接下来的20个字节为COFF标头,然后是PE标头(在0x9处.PE标头为224)字节并包含数据目录(96字节到PE头= 0xf。第15个条目(在0x16是CLR头描述符(有时称为COM描述符,但这与COM没有任何关系)。如果这是空(即从0x168到0x16f的8个字节中的0)然后该文件不是.NET程序集。如果要检查它是否是COM DLL,那么您应该查看它是否导出GetClassObject。

参考。

更新 :有一种更“.NET”的方式来完成这个:

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

NotAPortableExecutableImage该文件不是可移植可执行(PE)文件格式。

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

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

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

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

如果程序集被加载,例如Assembly.LoadFile(dotNetDllorExe)并且不抛出任何exception,那么它是一个有效的.NET程序集。 如果不是那么它将抛出“BadImageFormatException”。

通过加载和检查是否抛出exception来检查文件的天气是否assembly的想法; 似乎不太干净。 在exception使用所有exception之后。


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

它validation文件头以检查它是否是托管程序集。 在ECMA规范分区II – 随.NET SDK一起提供的元数据中,您会看到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参考 , 博客参考

面对过去的同样问题,我采用了您的reflection方法,因为另一种方法是手动读取这样的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/library/ms173100.aspx

您可以从文件中读取前两个字节,如果字节为“MZ”,则尝试读取程序集名称以确定( microsoft slow way )程序集的有效性。

  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; } }