lubos hasko引用的答案很好,但它不适用于64位程序集.这是一个更正版本(灵感来自http://apichange.codeplex.com/SourceControl/changeset/view/76c98b8c7311#ApiChange.Api/src/Introspection/CorFlagsReader.cs)
public static bool IsManagedAssembly(string fileName) { using (Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) using (BinaryReader binaryReader = new BinaryReader(fileStream)) { if (fileStream.Length < 64) { return false; } //PE Header starts @ 0x3C (60). Its a 4 byte header. fileStream.Position = 0x3C; uint peHeaderPointer = binaryReader.ReadUInt32(); if (peHeaderPointer == 0) { peHeaderPointer = 0x80; } // Ensure there is at least enough room for the following structures: // 24 byte PE Signature & Header // 28 byte Standard Fields (24 bytes for PE32+) // 68 byte NT Fields (88 bytes for PE32+) // >= 128 byte Data Dictionary Table if (peHeaderPointer > fileStream.Length - 256) { return false; } // Check the PE signature. Should equal 'PE\0\0'. fileStream.Position = peHeaderPointer; uint peHeaderSignature = binaryReader.ReadUInt32(); if (peHeaderSignature != 0x00004550) { return false; } // skip over the PEHeader fields fileStream.Position += 20; const ushort PE32 = 0x10b; const ushort PE32Plus = 0x20b; // Read PE magic number from Standard Fields to determine format. var peFormat = binaryReader.ReadUInt16(); if (peFormat != PE32 && peFormat != PE32Plus) { return false; } // Read the 15th Data Dictionary RVA field which contains the CLI header RVA. // When this is non-zero then the file contains CLI data otherwise not. ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248)); fileStream.Position = dataDictionaryStart; uint cliHeaderRva = binaryReader.ReadUInt32(); if (cliHeaderRva == 0) { return false; } return true; } }
缺少的部分是根据我们是PE32还是PE32Plus而以不同的方式偏移到数据字典:
// Read PE magic number from Standard Fields to determine format. var peFormat = binaryReader.ReadUInt16(); if (peFormat != PE32 && peFormat != PE32Plus) { return false; } // Read the 15th Data Dictionary RVA field which contains the CLI header RVA. // When this is non-zero then the file contains CLI data otherwise not. ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248));
lubos hasko.. 17
如何确定文件是否是.NET程序集?
public static bool IsManagedAssembly(string fileName) { 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(fileName, 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(); } fs.Close(); if (dataDictionaryRVA[14] == 0) return false; else return true; }
Wolfwyrd.. 5
我担心这样做的唯一真正方法是调用System.Reflection.AssemblyName.GetAssemblyName
将完整路径传递给要检查的文件.这将尝试从清单中提取名称而不将完整程序集加载到域中.如果文件是托管程序集,那么它将以字符串形式返回程序集的名称,否则它将抛出一个BadImageFormatException
可以在跳过程序集并移动到其他插件之前捕获并忽略的程序.
lubos hasko引用的答案很好,但它不适用于64位程序集.这是一个更正版本(灵感来自http://apichange.codeplex.com/SourceControl/changeset/view/76c98b8c7311#ApiChange.Api/src/Introspection/CorFlagsReader.cs)
public static bool IsManagedAssembly(string fileName) { using (Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) using (BinaryReader binaryReader = new BinaryReader(fileStream)) { if (fileStream.Length < 64) { return false; } //PE Header starts @ 0x3C (60). Its a 4 byte header. fileStream.Position = 0x3C; uint peHeaderPointer = binaryReader.ReadUInt32(); if (peHeaderPointer == 0) { peHeaderPointer = 0x80; } // Ensure there is at least enough room for the following structures: // 24 byte PE Signature & Header // 28 byte Standard Fields (24 bytes for PE32+) // 68 byte NT Fields (88 bytes for PE32+) // >= 128 byte Data Dictionary Table if (peHeaderPointer > fileStream.Length - 256) { return false; } // Check the PE signature. Should equal 'PE\0\0'. fileStream.Position = peHeaderPointer; uint peHeaderSignature = binaryReader.ReadUInt32(); if (peHeaderSignature != 0x00004550) { return false; } // skip over the PEHeader fields fileStream.Position += 20; const ushort PE32 = 0x10b; const ushort PE32Plus = 0x20b; // Read PE magic number from Standard Fields to determine format. var peFormat = binaryReader.ReadUInt16(); if (peFormat != PE32 && peFormat != PE32Plus) { return false; } // Read the 15th Data Dictionary RVA field which contains the CLI header RVA. // When this is non-zero then the file contains CLI data otherwise not. ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248)); fileStream.Position = dataDictionaryStart; uint cliHeaderRva = binaryReader.ReadUInt32(); if (cliHeaderRva == 0) { return false; } return true; } }
缺少的部分是根据我们是PE32还是PE32Plus而以不同的方式偏移到数据字典:
// Read PE magic number from Standard Fields to determine format. var peFormat = binaryReader.ReadUInt16(); if (peFormat != PE32 && peFormat != PE32Plus) { return false; } // Read the 15th Data Dictionary RVA field which contains the CLI header RVA. // When this is non-zero then the file contains CLI data otherwise not. ushort dataDictionaryStart = (ushort)(peHeaderPointer + (peFormat == PE32 ? 232 : 248));
如何确定文件是否是.NET程序集?
public static bool IsManagedAssembly(string fileName) { 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(fileName, 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(); } fs.Close(); if (dataDictionaryRVA[14] == 0) return false; else return true; }
我担心这样做的唯一真正方法是调用System.Reflection.AssemblyName.GetAssemblyName
将完整路径传递给要检查的文件.这将尝试从清单中提取名称而不将完整程序集加载到域中.如果文件是托管程序集,那么它将以字符串形式返回程序集的名称,否则它将抛出一个BadImageFormatException
可以在跳过程序集并移动到其他插件之前捕获并忽略的程序.