Domanda

Qual è il modo migliore per controllare se un file DLL è una DLL Win32 o se si tratta di un assembly CLR. Al momento io uso questo codice

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

Ma mi piace controllare prima di carico perché non voglio che le eccezioni (tempo).

C'è un modo migliore?

È stato utile?

Soluzione

Controlla l'intestazione PE:

  

intestazione DOS inizia al 0x0, il DWORD a   0x3C contiene un puntatore al PE   firma (di solito 0x80) che è 4   byte, i successivi 20 byte è il COFF   intestazione e poi c'è l'intestazione PE   (A 0x9. L'intestazione PE è 224 byte   e contiene la directory dei dati (a 96   byte nel PE header = 0xf. Il   15 ingresso (a 0x16 è l'intestazione CLR   descrittore (a volte chiamato il COM   descrittore, ma questo non ha   nulla a che fare con COM). Se questa è la   vuota (cioè 0 a 8 byte da 0x168   a 0x16f), allora il file non è un NET   montaggio. Se si desidera controllare se   è una DLL COM, allora si dovrebbe cercare di   vedere se si esporta GetClassObject.

Ref.

Aggiorna : c'è un modo piu 'NET' di realizzare questo:

Module.GetPEKind metodo e controllare la PortableExecutableKinds Enumeration:

  

NotAPortableExecutableImage Il file non è in eseguibile portatile   (PE) formato di file.

     

ILOnly L'eseguibile contiene solo Microsoft Intermediate Language   (MSIL), ed è quindi neutro   rispetto alle piattaforme a 32 bit o 64 bit.

     

Required32Bit L'eseguibile può essere eseguito su una piattaforma a 32 bit, oppure nel   Windows a 32 bit su Windows (WOW)   ambiente su una piattaforma a 64 bit.

     

PE32Plus L'eseguibile richiede una piattaforma a 64 bit.

     

Unmanaged32Bit L'eseguibile contiene il codice non gestito puro.

Altri suggerimenti

Se un assembly viene caricato ad esempio Assembly.LoadFile(dotNetDllorExe) e non genera alcuna eccezione, si tratta di un assembly .NET valido. Se non è allora getterà un “BadImageFormatException”.

L'idea di controllare tempo un file è di assemblaggio o no caricandola e controllando se viene generata un'eccezione o no; non sembra essere troppo puliti. Dopo che tutte le eccezioni dovrebbero essere utilizzati eccezionalmente.


assembly .NET sono file regolari Win32 PE, il sistema operativo non distinguere tra assembly .NET e Win32 binari eseguibili, sono gli stessi file PE normali. Così come il sistema funziona se una DLL o EXE è un assembly gestito per caricare il CLR?

Si convalida l'intestazione del file per verificare se si tratta di un assembly gestito o meno. Nel ECMA Specifiche Partizione II - I metadati che viene fornito insieme a .NET SDK che si vede c'è un'intestazione CLI separato nel formato PE. E 'il 15 directory dei dati nel PE opzionale intestazioni . Quindi, in termini semplici, se abbiamo valore in questa directory dei dati, allora significa che questo è un assembly .NET valido, altrimenti non lo è.

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 , Entra Ref

Di fronte lo stesso problema in passato, ho fatto ricorso ad usare il vostro approccio di riflessione perché l'alternativa è quella di leggere manualmente l'intestazione PE come questo . Proprio sembrava eccessivo per il mio scenario, ma può essere utile a voi.

Non è stato specificato se si dispone di fare questo nel codice, o se semplicemente personalmente bisogno di sapere se un file si sta guardando sul vostro sistema è un assembly .NET (che forse si pensa richiede di scrivere il proprio codice di farlo). In quest'ultimo caso, è possibile utilizzare Dependency Walker per vedere se ha una dipendenza da Mscoree.dll, che è il motore runtime .NET.

Si potrebbe usare qualcosa come:

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

Si prega di controllare anche: https://msdn.microsoft.com/en -us / library / ms173100.aspx

  

È possibile leggere i primi due byte del file, se i byte sono "MZ" quindi provare a leggere il nome di montaggio per determinare ( Microsoft Way lento) la validità del gruppo.

    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;
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top