2009-09-02 44 views
15

檢查DLL文件是否爲Win32 DLL或者它是否爲CLR程序集的最佳方法是什麼?目前我使用此代碼檢查DLL文件是否是C#中的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; 
    } 

但我喜歡加載前檢查,因爲我不想要那些例外(時間)。

有沒有更好的方法?

回答

17

檢查PE頭:

DOS,標題開始處爲0x0,在 的DWORD爲0x3C包含一個指向所述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。

Ref.

UPDATE:有完成這更多的 '.NET' 的方式:

使用Module.GetPEKind方法和檢查PortableExecutableKinds枚舉:

NotAPortableExecutableImage該文件不在可移植的可執行文件中(PE)文件格式。

ILONLY可執行僅包含Microsoft中間語言 (MSIL),並且因此與 對於32位或64位平臺中性的。

Required32Bit可執行可以一個32位的平臺上運行,或者在Windows(WOW) 環境中的64位的平臺上的 32位Windows。

PE32Plus可執行文件需要64位平臺。

Unmanaged32Bit該可執行文件包含純非託管代碼。

+8

我試圖做類似的東西OP。這個解決方案聽起來不錯,但是如何在不調用Assembly.LoadFile(在調用GetPEKind之前拋出非CLR dll的BadImageFormatException)的情況下獲得Module實例? – 2010-01-18 19:55:19

+1

@Simon:當然如果你感興趣,你如何編寫並添加一些代碼作爲答案? – 2011-07-20 01:26:01

+2

@Mitch:好吧,或許downvote有點草率。我試圖撤消它,但超時已過。抱歉。隨時downvote我的一些答案:)。我確實試圖讓這個工作。儘管在我看來,保羅問題是有效的。 Module.GetPEKind是實例。所以要獲得一個模塊,你需要調用Assembly Assembly.Load。這將拋出一個異常。由於該問題明確指出「沒有例外」,因此似乎這個答案不完整或不正確。 – Simon 2011-07-20 10:03:27

2

面對過去同樣的問題,我訴諸於使用你的反射方法,因爲另一種方法是手動讀取PE頭like this。對我的情況來說似乎過度殺傷,但它可能對你有用。

0

您沒有指定是否必須在代碼中執行此操作,或者您個人需要知道您在系統上查看的文件是否爲.NET程序集(您可能認爲這需要您編寫你自己的代碼這樣做)。如果是後者,你可以使用Dependency Walker來查看它是否依賴於.Net運行時引擎MSCOREE.dll。

+0

謝謝,但我需要這個來避免反射異常。 – schoetbi 2013-01-11 12:03:14

-1

您可以從文件中讀取前兩個字節,如果字節爲「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; 
     } 
    } 
5

如果一個組件被加載如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 RefBlog Ref

0

您可以使用類似:

 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

相關問題