Лучший способ проверить, является ли файл DLL сборкой CLR в C#

StackOverflow https://stackoverflow.com/questions/1366503

  •  21-09-2019
  •  | 
  •  

Вопрос

Как лучше всего проверить, является ли файл 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, DWORD при 0x3C содержит указатель на подпись PE (обычно 0x80), которая составляет 4 байта, следующие 20 байтов - заголовок COFF, а затем есть заголовок PE (при 0x9. Заголовок PE - 224 байты и содержит каталог данных (на 96 байтах в заголовок PE = 0xf. 15 -я запись (при 0x16 является дескриптор заголовка CLR (иногда называемый дескриптор COM, но это не имеет никакого отношения к COM). Если это Пусто (т.е. 0 в 8 байтах от 0x168 до 0x16f), тогда файл не является сборкой .NET. Если вы хотите проверить, является ли это COM DLL, вам следует посмотреть, экспортирует ли он getClassObject.

Рефери

ОБНОВИТЬ: Есть более '.net' способ сделать это:

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

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

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

Требуется 32 бит Исполняемый файл может быть запущен на 32-разрядной платформе или в 32-разрядной среде Windows в Windows (WOW) на 64-битной платформе.

PE32Plus Исполняемый файл требует 64-битной платформы.

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

Другие советы

Если сборка загружается, например Assembly.LoadFile(dotNetDllorExe) И не бросает никаких исключений, это действительная сборка .NET. Если это не так, то это бросит «badimageformatexception».

Идея проверить погоду файл является сборкой или нет путем его загрузки и проверки, брошено ли исключение или нет; Не кажется слишком чистым. После того, как все исключения должны использоваться исключительно.


.NET Assemblies - это регулярные файлы Win32 PE, операционная система не различает между сборками .NET и исполняемыми двоичными файлами WIN32, это одинаковые обычные файлы PE. Итак, как работает система, если DLL или EXE является управляемой сборкой для загрузки CLR?

Он проверяет заголовок файла, чтобы проверить, является ли это управляемой сборкой или нет. В разделе «Спецификации ECMA». Это 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, Блог Ref

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

Вы не указали, должны ли вы сделать это в коде, или вам лично вам нужно знать, является ли файл, на который вы смотрите в своей системе, является сборкой .NET (что, возможно, вы думаете Сделай так). Если последнее, вы можете использовать «Зависимость», чтобы увидеть, имеет ли он зависимость от 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 медленно) достоверность сборки.

    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;
        }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top