2009-09-02 2 views
15

Каков наилучший способ проверить, является ли DLL-файл DLL-файловой системой Win32 или если это сборка CLR. На данный момент я использую этот кодЛучший способ проверить, является ли DLL-файл сборкой CLR в C#

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 заголовка, а затем есть РЕ заголовка (в 0x9. заголовок РЕ 224 байт и содержит каталог данных (на 96 байт в заголовке PE = 0xf. пятнадцатого входа (на 0x16 это заголовок CLR (иногда называемый COM , но это не имеет ничего общего с COM). Если это пустым (то есть 0 в 8 байтах от 0x168 до 0x16f), то файл не является сборкой .NET . Если вы хотите проверить, является ли это COM-DLL, тогда вы должны посмотреть на , если он экспортирует GetClassObject.

Ref.

UPDATE: есть более '.NET' способ достижения этого:

Используйте Module.GetPEKind метод и проверить PortableExecutableKinds Перечень:

NotAPortableExecutableImage Файл не находится в переносном исполняемом файле (PE).

ILOnly Исполняемый содержит только Microsoft промежуточный язык (MSIL), и, следовательно, нейтральна по отношению к 32-битных или 64-битных платформах.

Required32Bit Исполняемый может работать на 32-битной платформе, или в 32-битных ОС Windows на Windows (WOW) среды на 64-битной платформе.

PE32Plus Для исполняемого файла требуется 64-разрядная платформа.

Unmanaged32Bit Исполняемый файл содержит чистый неуправляемый код.

+8

Я пытаюсь сделать что-то похожее на ОП. Это решение звучит здорово, но как вы можете получить экземпляр модуля, не вызывая Assembly.LoadFile (который генерирует исключение BadImageFormatException для DLL не CLR, прежде чем вы сможете вызвать GetPEKind)? –

+1

@Simon: конечно, если это вас интересует, как насчет того, чтобы написать и добавить код в качестве ответа? –

+2

@Mitch: Хорошо, возможно, нижняя часть была немного поспешна. Я попытался отменить его, но истечет время ожидания. Сожалею. не стесняйтесь обсуждать некоторые из моих ответов :). Я попытался заставить это работать. Хотя мне казалось, что вопрос Паулса действителен. Module.GetPEKind - это экземпляр. Итак, чтобы получить модуль, вам нужно вызвать сборку Assembly.Load. который выдает исключение. Поскольку в вопросе явно указано «никаких исключений», казалось бы, этот ответ либо неполный, либо неверный. – Simon

2

Столкнувшись с той же проблемой в прошлом, я прибегал к использованию вашего подхода к отражению, потому что альтернативой является ручной просмотр заголовка PE like this. Мне показалось, что это слишком тяжело для моего сценария, но это может быть полезно для вас.

0

Вы не указали, нужно ли это делать в коде, или если вам просто нужно знать, есть ли файл, который вы ищете в вашей системе, является сборкой .NET (что, возможно, вы думаете, ваш собственный код для этого). Если последний, вы можете использовать Dependency Walker, чтобы узнать, имеет ли он зависимость от MSCOREE.dll, который является механизмом выполнения .Net.

+0

Спасибо, но мне нужно это, чтобы избежать исключения исключения. – schoetbi

-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?

Он проверяет заголовок файла, чтобы проверить, является ли это управляемой сборкой или нет. В спецификации ECMA Partition II - Метаданные, поставляемые вместе с .NET SDK, вы видите, что в PE-формате есть отдельный заголовок CLI. Это 15-й каталог данных в PE дополнительных заголовках. Итак, в простых выражениях, если у нас есть значение в этом каталоге данных, значит, это допустимая сборка .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 Ref, Blog 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