Il modo migliore per controllare se un file DLL è un assembly CLR in C #
-
21-09-2019 - |
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?
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.
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();
}
}
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;
}
}