Pergunta

Qual é a melhor maneira de verificar se um arquivo DLL é uma DLL Win32 ou se é um assembly CLR.No momento em que eu use este código

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

Mas eu gostaria de verificar antes de carregar, porque eu não quero essas exceções (tempo).

Existe uma maneira melhor?

Foi útil?

Solução

Verifique o cabeçalho do PE:

O cabeçalho do DOS começa em 0x0, o DWORD em 0x3C contém um ponteiro para a assinatura do PE (geralmente 0x80), que é de 4 bytes, os próximos 20 bytes são o cabeçalho do caixão e depois há o cabeçalho PE (às 0x9. O cabeçalho do PE é 224 bytes e contém o diretório de dados (em 96 bytes no cabeçalho do PE = 0xf. A 15ª entrada (a 0x16 é o descritor de cabeçalho CLR (às vezes chamado de descritor, mas isso não tem nada a ver com com). Se isso for vazio (ou seja, 0 nos 8 bytes de 0x168 a 0x16f), o arquivo não é um conjunto .NET. Se você deseja verificar se é uma DLL, deve ver se ele exporta getClassObject.

Ref.

ATUALIZAR: Existe uma maneira mais '.NET' de realizar isso:

Usar Module.GetPEKind método e verifique o PortableExecutableKinds Enumeração:

NotportableExecutableImage O arquivo não está no formato de arquivo executável (PE) portátil.

Ilonly O executável contém apenas a linguagem intermediária da Microsoft (MSIL) e, portanto, é neutra em relação a plataformas de 32 ou 64 bits.

Requerido32bit O executável pode ser executado em uma plataforma de 32 bits ou no ambiente Windows no Windows (WOW) de 32 bits em uma plataforma de 64 bits.

PE32Plus O executável requer uma plataforma de 64 bits.

Não gerenciado32bit O executável contém código não gerenciado puro.

Outras dicas

Se um assembly é carregado por exemplo, Assembly.LoadFile(dotNetDllorExe) e não lançar qualquer exceção, é válido .LÍQUIDO de montagem.Se não é, então ele vai lançar um "BadImageFormatException".

A idéia de verificação de tempo de um arquivo é montagem ou não por carregá-lo e verificar se exceção é lançada ou não;não parece ser muito limpo.Depois de todas as exceções devem ser usados em casos excepcionais.


.NET assembléias regulares Win32 PE arquivos, o Sistema operacional não diferenciar .NET assembléias e executável Win32 binários, eles são os mesmos normal arquivos PE.Então, como funciona o Sistema de trabalho se uma DLL ou EXE é um assembly gerenciado a fim de carregar o CLR?

Ele valida o arquivo de cabeçalho para a verificação se um assembly gerenciado ou não.Nas Especificações ECMA Partição II – Metadados que é fornecido junto com .NET SDK você vê que há um separado CLI Cabeçalho no Formato PE.É o 15 de diretório de dados no PE Cabeçalhos Opcionais.Assim, em termos simples, se temos valor neste diretório de dados e, em seguida, isso significa que este é válido .LÍQUIDO de montagem, caso contrário não.

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

Diante do mesmo problema no passado, recorri ao uso da sua abordagem de reflexão porque a alternativa é ler manualmente o cabeçalho do PE assim. Parecia um exagero para o meu cenário, mas pode ser útil para você.

Você não especificou se precisa fazer isso no código, ou se você precisa saber se um arquivo que está vendo no seu sistema é uma montagem .NET (o que talvez você acha que exige que você escreva seu próprio código para faça isso). Se o último, você pode usar o Walker dependência para ver se ele tem uma dependência do MScoree.dll, que é o mecanismo de tempo de execução .NET.

Você poderia usar algo como:

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

Por favor, verifique também: https://msdn.microsoft.com/en-us/library/ms173100.aspx

Você pode ler os dois primeiros bytes do arquivo, se os bytes forem "MZ", então tente ler o nome da assembléia para determinar (Microsoft Way Slow) a validade da assembléia.

    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;
        }
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top