/// <summary> /// Constructor /// </summary> /// <param name="reader">PE file reader pointing to the start of this section</param> /// <param name="runtime">Runtime reader kind</param> /// <param name="verify">Verify section</param> /// <exception cref="BadImageFormatException">Thrown if verification fails</exception> public MetadataHeader(ref DataReader reader, CLRRuntimeReaderKind runtime, bool verify) { SetStartOffset(ref reader); signature = reader.ReadUInt32(); if (verify && signature != 0x424A5342) { throw new BadImageFormatException("Invalid metadata header signature"); } majorVersion = reader.ReadUInt16(); minorVersion = reader.ReadUInt16(); reserved1 = reader.ReadUInt32(); stringLength = reader.ReadUInt32(); versionString = ReadString(ref reader, stringLength, runtime); offset2ndPart = (FileOffset)reader.CurrentOffset; flags = (StorageFlags)reader.ReadByte(); reserved2 = reader.ReadByte(); streams = reader.ReadUInt16(); streamHeaders = new StreamHeader[streams]; for (int i = 0; i < streamHeaders.Count; i++) { // Mono doesn't verify all of these so we can't either var sh = new StreamHeader(ref reader, throwOnError: false, verify, runtime, out bool failedVerification); if (failedVerification || (ulong)sh.Offset + sh.StreamSize > reader.EndOffset) { sh = new StreamHeader(0, 0, "<invalid>"); } streamHeaders[i] = sh; } SetEndoffset(ref reader); }
internal StreamHeader(ref DataReader reader, bool throwOnError, bool verify, CLRRuntimeReaderKind runtime, out bool failedVerification) { failedVerification = false; SetStartOffset(ref reader); offset = reader.ReadUInt32(); streamSize = reader.ReadUInt32(); name = ReadString(ref reader, 32, verify, ref failedVerification); SetEndoffset(ref reader); if (runtime == CLRRuntimeReaderKind.Mono) { if (offset > reader.Length) { offset = reader.Length; } // Mono ignores the size (eg. it can be 0 or max value) so set it to the max possible value streamSize = reader.Length - offset; } if (verify && offset + size < offset) { failedVerification = true; } if (throwOnError && failedVerification) { throw new BadImageFormatException("Invalid stream header"); } }
internal static MetadataBase Load(IntPtr addr, CLRRuntimeReaderKind runtime) { IPEImage peImage = null; // We don't know what layout it is. Memory is more common so try that first. try { return(Load(peImage = new PEImage(addr, ImageLayout.Memory, true), runtime)); } catch { if (!(peImage is null)) { peImage.Dispose(); } peImage = null; } try { return(Load(peImage = new PEImage(addr, ImageLayout.File, true), runtime)); } catch { if (!(peImage is null)) { peImage.Dispose(); } throw; } }
static string ReadString(ref DataReader reader, uint maxLength, CLRRuntimeReaderKind runtime) { ulong endOffset = (ulong)reader.CurrentOffset + maxLength; if (runtime == CLRRuntimeReaderKind.Mono) { endOffset = (endOffset + 3) / 4 * 4; } if (endOffset > reader.EndOffset) { throw new BadImageFormatException("Invalid MD version string"); } var utf8Bytes = new byte[maxLength]; uint i; for (i = 0; i < maxLength; i++) { byte b = reader.ReadByte(); if (b == 0) { break; } utf8Bytes[i] = b; } reader.CurrentOffset = (uint)endOffset; return(Encoding.UTF8.GetString(utf8Bytes, 0, (int)i)); }
/// <summary> /// Create a standalone portable PDB <see cref="MetadataBase"/> instance /// </summary> /// <param name="mdReaderFactory">Metadata stream</param> /// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param> /// <returns>A new <see cref="MetadataBase"/> instance</returns> internal static MetadataBase CreateStandalonePortablePDB(DataReaderFactory mdReaderFactory, bool verify) { const CLRRuntimeReaderKind runtime = CLRRuntimeReaderKind.CLR; MetadataBase md = null; try { var reader = mdReaderFactory.CreateReader(); var mdHeader = new MetadataHeader(ref reader, runtime, verify); if (verify) { foreach (var sh in mdHeader.StreamHeaders) { if (sh.Offset + sh.StreamSize < sh.Offset || sh.Offset + sh.StreamSize > reader.Length) { throw new BadImageFormatException("Invalid stream header"); } } } md = GetMetadataType(mdHeader.StreamHeaders, runtime) switch { MetadataType.Compressed => new CompressedMetadata(mdHeader, true, runtime), MetadataType.ENC => new ENCMetadata(mdHeader, true, runtime), _ => throw new BadImageFormatException("No #~ or #- stream found"), }; md.Initialize(mdReaderFactory); return(md); } catch { md?.Dispose(); throw; } }
/// <summary> /// Create a <see cref="MetadataBase"/> instance /// </summary> /// <param name="peImage">The PE image</param> /// <param name="runtime">Runtime reader kind</param> /// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param> /// <returns>A new <see cref="MetadataBase"/> instance</returns> static MetadataBase Create(IPEImage peImage, CLRRuntimeReaderKind runtime, bool verify) { MetadataBase md = null; try { var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14]; // Mono doesn't check that the Size field is >= 0x48 if (dotNetDir.VirtualAddress == 0) { throw new BadImageFormatException(".NET data directory RVA is 0"); } var cor20HeaderReader = peImage.CreateReader(dotNetDir.VirtualAddress, 0x48); var cor20Header = new ImageCor20Header(ref cor20HeaderReader, verify && runtime == CLRRuntimeReaderKind.CLR); if (cor20Header.Metadata.VirtualAddress == 0) { throw new BadImageFormatException(".NET metadata RVA is 0"); } var mdRva = cor20Header.Metadata.VirtualAddress; // Don't use the size field, Mono ignores it. Create a reader that can read to EOF. var mdHeaderReader = peImage.CreateReader(mdRva); var mdHeader = new MetadataHeader(ref mdHeaderReader, runtime, verify); if (verify) { foreach (var sh in mdHeader.StreamHeaders) { if ((ulong)sh.Offset + sh.StreamSize > mdHeaderReader.EndOffset) { throw new BadImageFormatException("Invalid stream header"); } } } switch (GetMetadataType(mdHeader.StreamHeaders, runtime)) { case MetadataType.Compressed: md = new CompressedMetadata(peImage, cor20Header, mdHeader, runtime); break; case MetadataType.ENC: md = new ENCMetadata(peImage, cor20Header, mdHeader, runtime); break; default: throw new BadImageFormatException("No #~ or #- stream found"); } md.Initialize(null); return(md); } catch { if (!(md is null)) { md.Dispose(); } throw; } }
static MetadataType GetMetadataType(IList <StreamHeader> streamHeaders, CLRRuntimeReaderKind runtime) { MetadataType?mdType = null; if (runtime == CLRRuntimeReaderKind.CLR) { foreach (var sh in streamHeaders) { if (mdType is null) { if (sh.Name == "#~") { mdType = MetadataType.Compressed; } else if (sh.Name == "#-") { mdType = MetadataType.ENC; } } if (sh.Name == "#Schema") { mdType = MetadataType.ENC; } } } else if (runtime == CLRRuntimeReaderKind.Mono) { foreach (var sh in streamHeaders) { if (sh.Name == "#~") { mdType = MetadataType.Compressed; } else if (sh.Name == "#-") { mdType = MetadataType.ENC; break; } } } else { throw new ArgumentOutOfRangeException(nameof(runtime)); } if (mdType is null) { return(MetadataType.Unknown); } return(mdType.Value); }
internal static MetadataBase Load(IntPtr addr, ImageLayout imageLayout, CLRRuntimeReaderKind runtime) { IPEImage peImage = null; try { return(Load(peImage = new PEImage(addr, imageLayout, true), runtime)); } catch { if (!(peImage is null)) { peImage.Dispose(); } throw; } }
internal static MetadataBase Load(byte[] data, CLRRuntimeReaderKind runtime) { IPEImage peImage = null; try { return(Load(peImage = new PEImage(data), runtime)); } catch { if (!(peImage is null)) { peImage.Dispose(); } throw; } }
internal static MetadataBase Load(string fileName, CLRRuntimeReaderKind runtime) { IPEImage peImage = null; try { return(Load(peImage = new PEImage(fileName), runtime)); } catch { if (peImage is not null) { peImage.Dispose(); } throw; } }
/// <inheritdoc/> internal CompressedMetadata(MetadataHeader mdHeader, bool isStandalonePortablePdb, CLRRuntimeReaderKind runtime) : base(mdHeader, isStandalonePortablePdb) { this.runtime = runtime; }
/// <inheritdoc/> public CompressedMetadata(IPEImage peImage, ImageCor20Header cor20Header, MetadataHeader mdHeader, CLRRuntimeReaderKind runtime) : base(peImage, cor20Header, mdHeader) { this.runtime = runtime; }
internal static MetadataBase Load(IPEImage peImage, CLRRuntimeReaderKind runtime) => Create(peImage, runtime, true);
/// <summary> /// Create a <see cref="Metadata"/> instance /// </summary> /// <param name="peImage">The PE image</param> /// <param name="runtime">Runtime reader kind</param> /// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param> /// <returns>A new <see cref="Metadata"/> instance</returns> public static Metadata CreateMetadata(IPEImage peImage, CLRRuntimeReaderKind runtime, bool verify) => Create(peImage, runtime, verify);
/// <summary> /// Create a <see cref="Metadata"/> instance /// </summary> /// <param name="peImage">The PE image</param> /// <param name="runtime">Runtime reader kind</param> /// <returns>A new <see cref="Metadata"/> instance</returns> public static Metadata CreateMetadata(IPEImage peImage, CLRRuntimeReaderKind runtime) => Create(peImage, runtime, true);