/// <summary> /// Gets metadata about CLI Assembly in Microsoft PE format. /// </summary> /// <param name="stream">The stream.</param> /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param> /// <returns>The metadata or null if the stream does not represent a CLI assembly.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="stream"/> is null.</exception> public static AssemblyMetadata GetAssemblyMetadata(Stream stream, AssemblyMetadataFields fields) { if (stream == null) { throw new ArgumentNullException("stream"); } return(AssemblyMetadata.ReadAssemblyMetadata(stream, fields)); }
/// <summary> /// Gets the Major and Minor components of the CLI runtime version of a CLI Assembly in Microsoft PE format. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param> /// <returns>The version, of which only the major and minor components are populated, /// or null if the stream does not represent a CLI assembly.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="filePath"/> is null.</exception> public static AssemblyMetadata GetAssemblyMetadata(string filePath, AssemblyMetadataFields fields) { if (filePath == null) { throw new ArgumentNullException("filePath"); } if (!File.Exists(filePath)) { return(null); } using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { return(AssemblyMetadata.ReadAssemblyMetadata(stream, fields)); } }
internal static AssemblyMetadata ReadAssemblyMetadata(Stream stream, AssemblyMetadataFields fields) { long length = stream.Length; if (length < 0x40) { return(null); } BinaryReader reader = new BinaryReader(stream); // Read the pointer to the PE header. stream.Position = 0x3c; uint peHeaderPtr = reader.ReadUInt32(); if (peHeaderPtr == 0) { peHeaderPtr = 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 (peHeaderPtr > length - 256) { return(null); } // Check the PE signature. Should equal 'PE\0\0'. stream.Position = peHeaderPtr; uint peSignature = reader.ReadUInt32(); if (peSignature != 0x00004550) { return(null); } // Read PE header fields. ushort machine = reader.ReadUInt16(); ushort numberOfSections = reader.ReadUInt16(); uint timeStamp = reader.ReadUInt32(); uint symbolTablePtr = reader.ReadUInt32(); uint numberOfSymbols = reader.ReadUInt32(); ushort optionalHeaderSize = reader.ReadUInt16(); ushort characteristics = reader.ReadUInt16(); // Read PE magic number from Standard Fields to determine format. PEFormat peFormat = (PEFormat)reader.ReadUInt16(); if (peFormat != PEFormat.PE32 && peFormat != PEFormat.PE32Plus) { return(null); } // 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. stream.Position = peHeaderPtr + (peFormat == PEFormat.PE32 ? 232 : 248); uint cliHeaderRva = reader.ReadUInt32(); if (cliHeaderRva == 0) { return(null); } // Read section headers. Each one is 40 bytes. // 8 byte Name // 4 byte Virtual Size // 4 byte Virtual Address // 4 byte Data Size // 4 byte Data Pointer // ... total of 40 bytes uint sectionTablePtr = peHeaderPtr + 24 + optionalHeaderSize; Section[] sections = new Section[numberOfSections]; for (int i = 0; i < numberOfSections; i++) { stream.Position = sectionTablePtr + i * 40 + 8; Section section = new Section(); section.VirtualSize = reader.ReadUInt32(); section.VirtualAddress = reader.ReadUInt32(); reader.ReadUInt32(); section.Pointer = reader.ReadUInt32(); sections[i] = section; } // Read parts of the CLI header. uint cliHeaderPtr = ResolveRva(sections, cliHeaderRva); if (cliHeaderPtr == 0) { return(null); } stream.Position = cliHeaderPtr + 4; ushort majorRuntimeVersion = reader.ReadUInt16(); ushort minorRuntimeVersion = reader.ReadUInt16(); uint metadataRva = reader.ReadUInt32(); uint metadataSize = reader.ReadUInt32(); CorFlags corflags = (CorFlags)reader.ReadUInt32(); // Read optional fields. AssemblyName assemblyName = null; IList <AssemblyName> assemblyReferences = null; string runtimeVersion = null; if ((fields & AssemblyMetadataFields.RuntimeVersion) != 0) { uint metadataPtr = ResolveRva(sections, metadataRva); stream.Position = metadataPtr + 12; int paddedRuntimeVersionLength = reader.ReadInt32(); byte[] runtimeVersionBytes = reader.ReadBytes(paddedRuntimeVersionLength); int runtimeVersionLength = 0; while (runtimeVersionLength < paddedRuntimeVersionLength && runtimeVersionBytes[runtimeVersionLength] != 0) { runtimeVersionLength += 1; } runtimeVersion = Encoding.UTF8.GetString(runtimeVersionBytes, 0, runtimeVersionLength); } if ((fields & (AssemblyMetadataFields.AssemblyName | AssemblyMetadataFields.AssemblyReferences)) != 0) { // Using Cecil. stream.Position = 0; var imageReader = new ImageReader(stream); if ((fields & AssemblyMetadataFields.AssemblyName) != 0) { assemblyName = imageReader.GetAssemblyName(); } if ((fields & AssemblyMetadataFields.AssemblyReferences) != 0) { assemblyReferences = imageReader.GetAssemblyReferences(); } } // Done. return(new AssemblyMetadata(majorRuntimeVersion, minorRuntimeVersion, corflags, peFormat, assemblyName, assemblyReferences, runtimeVersion)); }
/// <summary> /// Gets metadata about CLI Assembly in Microsoft PE format. /// </summary> /// <param name="stream">The stream.</param> /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param> /// <returns>The metadata or null if the stream does not represent a CLI assembly.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="stream"/> is null.</exception> public static AssemblyMetadata GetAssemblyMetadata(Stream stream, AssemblyMetadataFields fields) { if (stream == null) throw new ArgumentNullException("stream"); return AssemblyMetadata.ReadAssemblyMetadata(stream, fields); }
/// <summary> /// Gets the Major and Minor components of the CLI runtime version of a CLI Assembly in Microsoft PE format. /// </summary> /// <param name="filePath">The file path.</param> /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param> /// <returns>The version, of which only the major and minor components are populated, /// or null if the stream does not represent a CLI assembly.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="filePath"/> is null.</exception> public static AssemblyMetadata GetAssemblyMetadata(string filePath, AssemblyMetadataFields fields) { if (filePath == null) throw new ArgumentNullException("filePath"); if (!File.Exists(filePath)) return null; using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { return AssemblyMetadata.ReadAssemblyMetadata(stream, fields); } }
internal static AssemblyMetadata ReadAssemblyMetadata(Stream stream, AssemblyMetadataFields fields) { long length = stream.Length; if (length < 0x40) return null; BinaryReader reader = new BinaryReader(stream); // Read the pointer to the PE header. stream.Position = 0x3c; uint peHeaderPtr = reader.ReadUInt32(); if (peHeaderPtr == 0) peHeaderPtr = 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 (peHeaderPtr > length - 256) return null; // Check the PE signature. Should equal 'PE\0\0'. stream.Position = peHeaderPtr; uint peSignature = reader.ReadUInt32(); if (peSignature != 0x00004550) return null; // Read PE header fields. ushort machine = reader.ReadUInt16(); ushort numberOfSections = reader.ReadUInt16(); uint timeStamp = reader.ReadUInt32(); uint symbolTablePtr = reader.ReadUInt32(); uint numberOfSymbols = reader.ReadUInt32(); ushort optionalHeaderSize = reader.ReadUInt16(); ushort characteristics = reader.ReadUInt16(); // Read PE magic number from Standard Fields to determine format. PEFormat peFormat = (PEFormat)reader.ReadUInt16(); if (peFormat != PEFormat.PE32 && peFormat != PEFormat.PE32Plus) return null; // 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. stream.Position = peHeaderPtr + (peFormat == PEFormat.PE32 ? 232 : 248); uint cliHeaderRva = reader.ReadUInt32(); if (cliHeaderRva == 0) return null; // Read section headers. Each one is 40 bytes. // 8 byte Name // 4 byte Virtual Size // 4 byte Virtual Address // 4 byte Data Size // 4 byte Data Pointer // ... total of 40 bytes uint sectionTablePtr = peHeaderPtr + 24 + optionalHeaderSize; Section[] sections = new Section[numberOfSections]; for (int i = 0; i < numberOfSections; i++) { stream.Position = sectionTablePtr + i * 40 + 8; Section section = new Section(); section.VirtualSize = reader.ReadUInt32(); section.VirtualAddress = reader.ReadUInt32(); reader.ReadUInt32(); section.Pointer = reader.ReadUInt32(); sections[i] = section; } // Read parts of the CLI header. uint cliHeaderPtr = ResolveRva(sections, cliHeaderRva); if (cliHeaderPtr == 0) return null; stream.Position = cliHeaderPtr + 4; ushort majorRuntimeVersion = reader.ReadUInt16(); ushort minorRuntimeVersion = reader.ReadUInt16(); uint metadataRva = reader.ReadUInt32(); uint metadataSize = reader.ReadUInt32(); CorFlags corflags = (CorFlags)reader.ReadUInt32(); // Read optional fields. AssemblyName assemblyName = null; IList<AssemblyName> assemblyReferences = null; string runtimeVersion = null; if ((fields & AssemblyMetadataFields.RuntimeVersion) != 0) { uint metadataPtr = ResolveRva(sections, metadataRva); stream.Position = metadataPtr + 12; int paddedRuntimeVersionLength = reader.ReadInt32(); byte[] runtimeVersionBytes = reader.ReadBytes(paddedRuntimeVersionLength); int runtimeVersionLength = 0; while (runtimeVersionLength < paddedRuntimeVersionLength && runtimeVersionBytes[runtimeVersionLength] != 0) runtimeVersionLength += 1; runtimeVersion = Encoding.UTF8.GetString(runtimeVersionBytes, 0, runtimeVersionLength); } if ((fields & (AssemblyMetadataFields.AssemblyName | AssemblyMetadataFields.AssemblyReferences)) != 0) { // Using Cecil. stream.Position = 0; var imageReader = new ImageReader(stream); if ((fields & AssemblyMetadataFields.AssemblyName) != 0) assemblyName = imageReader.GetAssemblyName(); if ((fields & AssemblyMetadataFields.AssemblyReferences) != 0) assemblyReferences = imageReader.GetAssemblyReferences(); } // Done. return new AssemblyMetadata(majorRuntimeVersion, minorRuntimeVersion, corflags, peFormat, assemblyName, assemblyReferences, runtimeVersion); }