using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using AsmResolver.IO; using AsmResolver.PE.File.Headers; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("AsmResolver.PE.File")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Washi 2016-2022")] [assembly: AssemblyDescription("Raw PE file models for the AsmResolver executable file inspection toolsuite.")] [assembly: AssemblyFileVersion("5.1.0.0")] [assembly: AssemblyInformationalVersion("5.1.0")] [assembly: AssemblyProduct("AsmResolver.PE.File")] [assembly: AssemblyTitle("AsmResolver.PE.File")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Washi1337/AsmResolver")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("5.1.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace AsmResolver.PE.File { public interface IPEFile : ISegmentReferenceFactory, IOffsetConverter { string? FilePath { get; } DosHeader DosHeader { get; } FileHeader FileHeader { get; } OptionalHeader OptionalHeader { get; } IList Sections { get; } PEMappingMode MappingMode { get; } ISegment? ExtraSectionData { get; set; } ISegment? EofData { get; set; } PESection GetSectionContainingRva(uint rva); bool TryGetSectionContainingRva(uint rva, [NotNullWhen(true)] out PESection? section); BinaryStreamReader CreateDataDirectoryReader(DataDirectory dataDirectory); bool TryCreateDataDirectoryReader(DataDirectory dataDirectory, out BinaryStreamReader reader); BinaryStreamReader CreateReaderAtRva(uint rva); bool TryCreateReaderAtRva(uint rva, out BinaryStreamReader reader); BinaryStreamReader CreateReaderAtRva(uint rva, uint size); bool TryCreateReaderAtRva(uint rva, uint size, out BinaryStreamReader reader); BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset); bool TryCreateReaderAtFileOffset(uint fileOffset, out BinaryStreamReader reader); BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset, uint size); bool TryCreateReaderAtFileOffset(uint fileOffset, uint size, out BinaryStreamReader reader); } public class PEFile : IPEFile, ISegmentReferenceFactory, IOffsetConverter { public const uint ValidPESignature = 17744u; private readonly LazyVariable _extraSectionData; private readonly LazyVariable _eofData; private IList? _sections; public string? FilePath { get; protected set; } public DosHeader DosHeader { get; set; } public FileHeader FileHeader { get; set; } public OptionalHeader OptionalHeader { get; set; } public IList Sections { get { if (_sections == null) { Interlocked.CompareExchange(ref _sections, GetSections(), null); } return _sections; } } public PEMappingMode MappingMode { get; protected set; } public ISegment? ExtraSectionData { get { return _extraSectionData.Value; } set { _extraSectionData.Value = value; } } public ISegment? EofData { get { return _eofData.Value; } set { _eofData.Value = value; } } public PEFile() : this(new DosHeader(), new FileHeader(), new OptionalHeader()) { } public PEFile(DosHeader dosHeader, FileHeader fileHeader, OptionalHeader optionalHeader) { DosHeader = dosHeader ?? throw new ArgumentNullException("dosHeader"); FileHeader = fileHeader ?? throw new ArgumentNullException("fileHeader"); OptionalHeader = optionalHeader ?? throw new ArgumentNullException("optionalHeader"); _extraSectionData = new LazyVariable((Func)GetExtraSectionData); _eofData = new LazyVariable((Func)GetEofData); MappingMode = PEMappingMode.Unmapped; } public static PEFile FromFile(string path) { return FromFile(UncachedFileService.Instance.OpenFile(path)); } public static PEFile FromFile(IInputFile file) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) BinaryStreamReader reader = IOExtensions.CreateReader(file); PEFile pEFile = FromReader(in reader); pEFile.FilePath = file.FilePath; return pEFile; } public static PEFile FromBytes(byte[] raw) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) BinaryStreamReader reader = new BinaryStreamReader(raw); return FromReader(in reader); } public static PEFile FromModuleBaseAddress(IntPtr hInstance) { return FromModuleBaseAddress(hInstance, PEMappingMode.Mapped); } public unsafe static PEFile FromModuleBaseAddress(IntPtr hInstance, PEMappingMode mode) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown uint num = *(uint*)((byte*)(void*)hInstance + 60); uint num2 = *(uint*)((byte*)(void*)hInstance + num + 4 + 20 + 56); return FromDataSource((IDataSource)new UnmanagedDataSource(hInstance, (ulong)num2), mode); } public static PEFile FromDataSource(IDataSource dataSource, PEMappingMode mode = PEMappingMode.Unmapped) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) BinaryStreamReader reader = new BinaryStreamReader(dataSource, dataSource.BaseAddress, 0u, (uint)dataSource.Length); return FromReader(in reader, mode); } public static PEFile FromReader(in BinaryStreamReader reader, PEMappingMode mode = PEMappingMode.Unmapped) { return new SerializedPEFile(in reader, mode); } public ISegmentReference GetReferenceToRva(uint rva) { return (ISegmentReference)(object)new PESegmentReference(this, rva); } public uint FileOffsetToRva(ulong fileOffset) { return GetSectionContainingOffset(fileOffset).FileOffsetToRva(fileOffset); } public ulong RvaToFileOffset(uint rva) { return GetSectionContainingRva(rva).RvaToFileOffset(rva); } public PESection GetSectionContainingOffset(ulong fileOffset) { if (!TryGetSectionContainingOffset(fileOffset, out PESection section)) { throw new ArgumentOutOfRangeException("fileOffset"); } return section; } public bool TryGetSectionContainingOffset(ulong fileOffset, [NotNullWhen(true)] out PESection? section) { IList sections = Sections; for (int i = 0; i < sections.Count; i++) { if (sections[i].ContainsFileOffset(fileOffset)) { section = sections[i]; return true; } } section = null; return false; } public PESection GetSectionContainingRva(uint rva) { if (!TryGetSectionContainingRva(rva, out PESection section)) { throw new ArgumentOutOfRangeException("rva"); } return section; } public bool TryGetSectionContainingRva(uint rva, [NotNullWhen(true)] out PESection? section) { IList sections = Sections; for (int i = 0; i < sections.Count; i++) { if (sections[i].ContainsRva(rva)) { section = sections[i]; return true; } } section = null; return false; } public BinaryStreamReader CreateDataDirectoryReader(DataDirectory dataDirectory) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) PESection sectionContainingRva = GetSectionContainingRva(dataDirectory.VirtualAddress); ulong fileOffset = sectionContainingRva.RvaToFileOffset(dataDirectory.VirtualAddress); return sectionContainingRva.CreateReader(fileOffset, dataDirectory.Size); } public bool TryCreateDataDirectoryReader(DataDirectory dataDirectory, out BinaryStreamReader reader) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (TryGetSectionContainingRva(dataDirectory.VirtualAddress, out PESection section)) { ulong fileOffset = section.RvaToFileOffset(dataDirectory.VirtualAddress); reader = section.CreateReader(fileOffset, dataDirectory.Size); return true; } reader = default(BinaryStreamReader); return false; } public BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return Extensions.CreateReader((IReadableSegment)(object)GetSectionContainingOffset(fileOffset), (ulong)fileOffset); } public bool TryCreateReaderAtFileOffset(uint fileOffset, out BinaryStreamReader reader) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (TryGetSectionContainingOffset(fileOffset, out PESection section)) { reader = Extensions.CreateReader((IReadableSegment)(object)section, (ulong)fileOffset); return true; } reader = default(BinaryStreamReader); return false; } public BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset, uint size) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return GetSectionContainingOffset(fileOffset).CreateReader(fileOffset, size); } public bool TryCreateReaderAtFileOffset(uint fileOffset, uint size, out BinaryStreamReader reader) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (TryGetSectionContainingOffset(fileOffset, out PESection section)) { reader = section.CreateReader(fileOffset, size); return true; } reader = default(BinaryStreamReader); return false; } public BinaryStreamReader CreateReaderAtRva(uint rva) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) PESection sectionContainingRva = GetSectionContainingRva(rva); return Extensions.CreateReader((IReadableSegment)(object)sectionContainingRva, sectionContainingRva.RvaToFileOffset(rva)); } public bool TryCreateReaderAtRva(uint rva, out BinaryStreamReader reader) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (TryGetSectionContainingRva(rva, out PESection section)) { reader = Extensions.CreateReader((IReadableSegment)(object)section, section.RvaToFileOffset(rva)); return true; } reader = default(BinaryStreamReader); return false; } public BinaryStreamReader CreateReaderAtRva(uint rva, uint size) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) PESection sectionContainingRva = GetSectionContainingRva(rva); return sectionContainingRva.CreateReader(sectionContainingRva.RvaToFileOffset(rva), size); } public bool TryCreateReaderAtRva(uint rva, uint size, out BinaryStreamReader reader) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (TryGetSectionContainingRva(rva, out PESection section)) { reader = section.CreateReader(section.RvaToFileOffset(rva), size); return true; } reader = default(BinaryStreamReader); return false; } public void UpdateHeaders() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) List oldHeaders = Sections.Select((PESection x) => x.CreateHeader()).ToList(); FileHeader.NumberOfSections = (ushort)Sections.Count; RelocationParameters val = default(RelocationParameters); ((RelocationParameters)(ref val))..ctor(OptionalHeader.ImageBase, 0uL, 0u, OptionalHeader.Magic == OptionalHeaderMagic.PE32); FileHeader fileHeader = FileHeader; RelocationParameters val2 = ((RelocationParameters)(ref val)).WithOffsetRva((ulong)(DosHeader.NextHeaderOffset + 4), DosHeader.NextHeaderOffset + 4); ((SegmentBase)fileHeader).UpdateOffsets(ref val2); OptionalHeader optionalHeader = OptionalHeader; val2 = ((RelocationParameters)(ref val)).WithOffsetRva(((SegmentBase)FileHeader).Offset + ((SegmentBase)FileHeader).GetPhysicalSize(), ((SegmentBase)FileHeader).Rva + ((SegmentBase)FileHeader).GetVirtualSize()); ((SegmentBase)optionalHeader).UpdateOffsets(ref val2); FileHeader.SizeOfOptionalHeader = (ushort)((SegmentBase)OptionalHeader).GetPhysicalSize(); OptionalHeader.SizeOfHeaders = (uint)Extensions.Align(((SegmentBase)OptionalHeader).Offset + FileHeader.SizeOfOptionalHeader + (uint)(40 * Sections.Count), (ulong)OptionalHeader.FileAlignment); AlignSections(); AlignDataDirectoryEntries(oldHeaders); PESection pESection = Sections[Sections.Count - 1]; OptionalHeader.SizeOfImage = pESection.Rva + Extensions.Align(pESection.GetVirtualSize(), OptionalHeader.SectionAlignment); ISegment? eofData = EofData; if (eofData != null) { val2 = ((RelocationParameters)(ref val)).WithOffsetRva(pESection.Offset + pESection.GetPhysicalSize(), OptionalHeader.SizeOfImage); eofData.UpdateOffsets(ref val2); } } public void AlignSections() { RelocationParameters parameters = default(RelocationParameters); ((RelocationParameters)(ref parameters))..ctor(OptionalHeader.ImageBase, (ulong)Extensions.Align(OptionalHeader.SizeOfHeaders, OptionalHeader.FileAlignment), Extensions.Align(OptionalHeader.SizeOfHeaders, OptionalHeader.SectionAlignment), OptionalHeader.Magic == OptionalHeaderMagic.PE32); for (int i = 0; i < Sections.Count; i++) { PESection pESection = Sections[i]; pESection.UpdateOffsets(in parameters); ((RelocationParameters)(ref parameters)).Advance(Extensions.Align(pESection.GetPhysicalSize(), OptionalHeader.FileAlignment), Extensions.Align(pESection.GetVirtualSize(), OptionalHeader.SectionAlignment)); } } public void AlignDataDirectoryEntries(IList oldHeaders) { IList dataDirectories = OptionalHeader.DataDirectories; for (int i = 0; i < dataDirectories.Count; i++) { DataDirectory dataDirectory = dataDirectories[i]; if (!dataDirectory.IsPresentInPE) { continue; } uint virtualAddress = dataDirectory.VirtualAddress; for (int j = 0; j < oldHeaders.Count; j++) { SectionHeader sectionHeader = oldHeaders[j]; if (sectionHeader.VirtualAddress <= virtualAddress && sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData > virtualAddress) { if (Sections[j].Rva >= sectionHeader.VirtualAddress) { uint num = Sections[j].Rva - sectionHeader.VirtualAddress; virtualAddress += num; } else { uint num2 = sectionHeader.VirtualAddress - Sections[j].Rva; virtualAddress -= num2; } dataDirectories[i] = new DataDirectory(virtualAddress, dataDirectory.Size); break; } } } } public void Write(string filePath) { using FileStream stream = System.IO.File.Create(filePath); Write((Stream)stream); } public void Write(Stream stream) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown Write((IBinaryStreamWriter)new BinaryStreamWriter(stream)); } public void Write(IBinaryStreamWriter writer) { UpdateHeaders(); ((SegmentBase)DosHeader).Write(writer); writer.Offset = DosHeader.NextHeaderOffset; writer.WriteUInt32(17744u); ((SegmentBase)FileHeader).Write(writer); ((SegmentBase)OptionalHeader).Write(writer); writer.Offset = ((SegmentBase)OptionalHeader).Offset + FileHeader.SizeOfOptionalHeader; for (int i = 0; i < Sections.Count; i++) { ((SegmentBase)Sections[i].CreateHeader()).Write(writer); } ISegment? extraSectionData = ExtraSectionData; if (extraSectionData != null) { ((IWritable)extraSectionData).Write(writer); } writer.Offset = OptionalHeader.SizeOfHeaders; for (int j = 0; j < Sections.Count; j++) { PESection pESection = Sections[j]; writer.Offset = pESection.Offset; ISegment? contents = pESection.Contents; if (contents != null) { ((IWritable)contents).Write(writer); } IOExtensions.Align(writer, OptionalHeader.FileAlignment); } ISegment? eofData = EofData; if (eofData != null) { ((IWritable)eofData).Write(writer); } } protected virtual IList GetSections() { return new PESectionCollection(this); } protected virtual ISegment? GetExtraSectionData() { return null; } protected virtual ISegment? GetEofData() { return null; } } public enum PEMappingMode { Unmapped, Mapped } public class PESection : IReadableSegment, ISegment, IOffsetProvider, IWritable, IOffsetConverter { private string _name; public PEFile? ContainingFile { get; internal set; } public string Name { get { return _name; } set { SectionHeader.AssertIsValidName(value); _name = value; } } public SectionFlags Characteristics { get; set; } public bool IsContentCode { get { return (Characteristics & SectionFlags.ContentCode) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.ContentCode) | (value ? SectionFlags.ContentCode : ((SectionFlags)0u)); } } public bool IsContentInitializedData { get { return (Characteristics & SectionFlags.ContentInitializedData) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.ContentInitializedData) | (value ? SectionFlags.ContentInitializedData : ((SectionFlags)0u)); } } public bool IsContentUninitializedData { get { return (Characteristics & SectionFlags.ContentUninitializedData) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.ContentUninitializedData) | (value ? SectionFlags.ContentUninitializedData : ((SectionFlags)0u)); } } public bool IsMemoryDiscardable { get { return (Characteristics & SectionFlags.MemoryDiscardable) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryDiscardable) | (value ? SectionFlags.MemoryDiscardable : ((SectionFlags)0u)); } } public bool IsMemoryNotCached { get { return (Characteristics & SectionFlags.MemoryNotCached) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryNotCached) | (value ? SectionFlags.MemoryNotCached : ((SectionFlags)0u)); } } public bool IsMemoryNotPaged { get { return (Characteristics & SectionFlags.MemoryNotPaged) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryNotPaged) | (value ? SectionFlags.MemoryNotPaged : ((SectionFlags)0u)); } } public bool IsMemoryShared { get { return (Characteristics & SectionFlags.MemoryShared) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryShared) | (value ? SectionFlags.MemoryShared : ((SectionFlags)0u)); } } public bool IsMemoryExecute { get { return (Characteristics & SectionFlags.MemoryExecute) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryExecute) | (value ? SectionFlags.MemoryExecute : ((SectionFlags)0u)); } } public bool IsMemoryRead { get { return (Characteristics & SectionFlags.MemoryRead) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryRead) | (value ? SectionFlags.MemoryRead : ((SectionFlags)0u)); } } public bool IsMemoryWrite { get { return ((uint)Characteristics & 0x80000000u) != 0; } set { Characteristics = (Characteristics & ~SectionFlags.MemoryWrite) | (value ? SectionFlags.MemoryWrite : ((SectionFlags)0u)); } } public ISegment? Contents { get; set; } [MemberNotNullWhen(true, "Contents")] public bool IsReadable { [MemberNotNullWhen(true, "Contents")] get { return Contents is IReadableSegment; } } public ulong Offset { get { ISegment? contents = Contents; if (contents == null) { return 0uL; } return ((IOffsetProvider)contents).Offset; } } public uint Rva { get { ISegment? contents = Contents; if (contents == null) { return 0u; } return ((IOffsetProvider)contents).Rva; } } public bool CanUpdateOffsets => true; public PESection(string name, SectionFlags characteristics) { SectionHeader.AssertIsValidName(name); _name = name; Characteristics = characteristics; } public PESection(string name, SectionFlags characteristics, ISegment? contents) { SectionHeader.AssertIsValidName(name); _name = name; Characteristics = characteristics; Contents = contents; } public PESection(PESection section) : this(section.Name, section.Characteristics, section.Contents) { } public PESection(SectionHeader header, ISegment contents) { _name = header.Name; Characteristics = header.Characteristics; Contents = contents; } public void UpdateOffsets(in RelocationParameters parameters) { ISegment? contents = Contents; if (contents != null) { contents.UpdateOffsets(ref parameters); } } public uint GetPhysicalSize() { ISegment? contents = Contents; if (contents == null) { return 0u; } return ((IWritable)contents).GetPhysicalSize(); } public uint GetVirtualSize() { ISegment? contents = Contents; if (contents == null) { return 0u; } return contents.GetVirtualSize(); } public BinaryStreamReader CreateReader(ulong fileOffset, uint size) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!IsReadable) { throw new InvalidOperationException("Section contents is not readable."); } return ((IReadableSegment)Contents).CreateReader(fileOffset, size); } public SectionHeader CreateHeader() { uint num = ContainingFile?.OptionalHeader.FileAlignment ?? 512; return new SectionHeader(Name, Characteristics) { PointerToRawData = (uint)Offset, SizeOfRawData = Extensions.Align(GetPhysicalSize(), num), VirtualAddress = Rva, VirtualSize = GetVirtualSize(), NumberOfRelocations = 0, PointerToRelocations = 0u, NumberOfLineNumbers = 0, PointerToLineNumbers = 0u }; } public bool ContainsFileOffset(ulong fileOffset) { if (Offset <= fileOffset) { return fileOffset < Offset + GetPhysicalSize(); } return false; } public bool ContainsRva(uint rva) { if (Rva <= rva) { return rva < Rva + GetVirtualSize(); } return false; } public uint FileOffsetToRva(ulong fileOffset) { if (!ContainsFileOffset(fileOffset)) { throw new ArgumentOutOfRangeException("fileOffset"); } return (uint)(fileOffset - Offset + Rva); } public ulong RvaToFileOffset(uint rva) { if (!ContainsRva(rva)) { throw new ArgumentOutOfRangeException("rva"); } return rva - Rva + Offset; } public override string ToString() { return Name; } public void Write(IBinaryStreamWriter writer) { ISegment? contents = Contents; if (contents != null) { ((IWritable)contents).Write(writer); } } void ISegment.UpdateOffsets(in RelocationParameters parameters) { UpdateOffsets(in parameters); } } public class PESectionCollection : Collection { public PEFile Owner { get; } public PESectionCollection(PEFile owner) { Owner = owner ?? throw new ArgumentNullException("owner"); } private void AssertHasNoOwner(PESection section) { if (section.ContainingFile != null) { throw new ArgumentException("Section was already added to another portable executable file."); } } protected override void ClearItems() { foreach (PESection item in base.Items) { item.ContainingFile = null; } base.ClearItems(); } protected override void InsertItem(int index, PESection item) { AssertHasNoOwner(item); base.InsertItem(index, item); item.ContainingFile = Owner; } protected override void SetItem(int index, PESection item) { AssertHasNoOwner(item); RemoveItem(index); InsertItem(index, item); } protected override void RemoveItem(int index) { base.Items[index].ContainingFile = null; base.RemoveItem(index); } } public sealed class PESegmentReference : ISegmentReference, IOffsetProvider { private readonly IPEFile _peFile; public ulong Offset { get { if (!_peFile.TryGetSectionContainingRva(Rva, out PESection _)) { return 0uL; } return ((IOffsetConverter)_peFile).RvaToFileOffset(Rva); } } public uint Rva { get; } public bool CanRead { get { PESection section; return _peFile.TryGetSectionContainingRva(Rva, out section); } } public bool IsBounded => false; internal PESegmentReference(IPEFile peFile, uint rva) { _peFile = peFile; Rva = rva; } public BinaryStreamReader CreateReader() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return _peFile.CreateReaderAtRva(Rva); } public ISegment? GetSegment() { throw new InvalidOperationException(); } public override string ToString() { return $"0x{Rva:X8}"; } } public class SerializedPEFile : PEFile { private readonly List _sectionHeaders; private readonly BinaryStreamReader _reader; private readonly ulong _originalImageBase; private readonly bool _is32Bit; public SerializedPEFile(in BinaryStreamReader reader, PEMappingMode mode) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) _reader = reader; base.MappingMode = mode; base.DosHeader = AsmResolver.PE.File.Headers.DosHeader.FromReader(ref _reader); ((BinaryStreamReader)(ref _reader)).Offset = ((SegmentBase)base.DosHeader).Offset + base.DosHeader.NextHeaderOffset; if (((BinaryStreamReader)(ref _reader)).ReadUInt32() != 17744) { throw new BadImageFormatException(); } base.FileHeader = AsmResolver.PE.File.Headers.FileHeader.FromReader(ref _reader); base.OptionalHeader = AsmResolver.PE.File.Headers.OptionalHeader.FromReader(ref _reader); _originalImageBase = base.OptionalHeader.ImageBase; _is32Bit = base.OptionalHeader.Magic == OptionalHeaderMagic.PE32; ((BinaryStreamReader)(ref _reader)).Offset = ((SegmentBase)base.OptionalHeader).Offset + base.FileHeader.SizeOfOptionalHeader; _sectionHeaders = new List(base.FileHeader.NumberOfSections); for (int i = 0; i < base.FileHeader.NumberOfSections; i++) { _sectionHeaders.Add(SectionHeader.FromReader(ref _reader)); } int num = (int)(((SegmentBase)base.DosHeader).Offset + base.OptionalHeader.SizeOfHeaders - ((BinaryStreamReader)(ref _reader)).Offset); if (num != 0) { base.ExtraSectionData = (ISegment?)(object)((BinaryStreamReader)(ref _reader)).ReadSegment((uint)num); } } protected unsafe override IList GetSections() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown PESectionCollection pESectionCollection = new PESectionCollection(this); for (int i = 0; i < _sectionHeaders.Count; i++) { SectionHeader sectionHeader = _sectionHeaders[i]; object obj = base.MappingMode switch { PEMappingMode.Unmapped => (((BinaryStreamReader)(ref _reader)).StartOffset + sectionHeader.PointerToRawData, sectionHeader.SizeOfRawData), PEMappingMode.Mapped => (((BinaryStreamReader)(ref _reader)).StartOffset + sectionHeader.VirtualAddress, sectionHeader.VirtualSize), _ => throw new ArgumentOutOfRangeException(), }; ulong item = ((ValueTuple*)(&obj))->Item1; uint item2 = ((ValueTuple*)(&obj))->Item2; ISegment val = null; if (item2 != 0) { val = (ISegment)new DataSourceSegment(((BinaryStreamReader)(ref _reader)).DataSource, item, sectionHeader.VirtualAddress, item2); } VirtualSegment val2 = new VirtualSegment(val, sectionHeader.VirtualSize); RelocationParameters val3 = new RelocationParameters(_originalImageBase, item, sectionHeader.VirtualAddress, _is32Bit); val2.UpdateOffsets(ref val3); pESectionCollection.Add(new PESection(sectionHeader, (ISegment)(object)val2)); } return pESectionCollection; } protected override ISegment? GetEofData() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (base.MappingMode != 0) { return null; } SectionHeader sectionHeader = _sectionHeaders[_sectionHeaders.Count - 1]; ulong num = sectionHeader.PointerToRawData + sectionHeader.SizeOfRawData; BinaryStreamReader val = ((BinaryStreamReader)(ref _reader)).ForkAbsolute(num); if (((BinaryStreamReader)(ref val)).Length == 0) { return null; } return (ISegment?)(object)((BinaryStreamReader)(ref val)).ReadSegment(((BinaryStreamReader)(ref val)).Length); } } } namespace AsmResolver.PE.File.Headers { [Flags] public enum Characteristics : ushort { RelocsStripped = 1, Image = 2, LineNumsStripped = 4, LocalSymsStripped = 8, AggressiveWsTrim = 0x10, LargeAddressAware = 0x20, BytesReversedLo = 0x80, Machine32Bit = 0x100, DebugStripped = 0x200, RemovableRunFromSwap = 0x400, NetRunFromSwap = 0x800, System = 0x1000, Dll = 0x2000, UpSystemOnly = 0x4000, BytesReversedHi = 0x8000 } public readonly struct DataDirectory : IWritable { public const uint DataDirectorySize = 8u; public uint VirtualAddress { get; } public uint Size { get; } public bool IsPresentInPE { get { if (VirtualAddress == 0) { return Size != 0; } return true; } } public static DataDirectory FromReader(ref BinaryStreamReader reader) { return new DataDirectory(((BinaryStreamReader)(ref reader)).ReadUInt32(), ((BinaryStreamReader)(ref reader)).ReadUInt32()); } public DataDirectory(uint virtualAddress, uint size) { VirtualAddress = virtualAddress; Size = size; } public uint GetPhysicalSize() { return 8u; } public void Write(IBinaryStreamWriter writer) { writer.WriteUInt32(VirtualAddress); writer.WriteUInt32(Size); } public void Deconstruct(out uint virtualAddress, out uint size) { virtualAddress = VirtualAddress; size = Size; } public override string ToString() { return $"RVA: 0x{VirtualAddress:X8}, Size: 0x{Size:X8}"; } } public enum DataDirectoryIndex { ExportDirectory, ImportDirectory, ResourceDirectory, ExceptionDirectory, CertificateDirectory, BaseRelocationDirectory, DebugDirectory, ArchitectureDirectory, GlobalPtrDirectory, TlsDirectory, LoadConfigDirectory, BoundImportDirectory, IatDirectory, DelayImportDescrDirectory, ClrDirectory, ReservedDirectory } [Flags] public enum DllCharacteristics { HighEntropyVA = 0x20, DynamicBase = 0x40, ForceIntegrity = 0x80, NxCompat = 0x100, NoIsolation = 0x200, NoSeh = 0x400, NoBind = 0x800, AppContainer = 0x1000, WdmDriver = 0x2000, ControlFLowGuard = 0x4000, TerminalServerAware = 0x8000 } public class DosHeader : SegmentBase { public const ushort ValidPEMagic = 23117; public const int MinimalDosHeaderLength = 64; public const int NextHeaderFieldOffset = 60; public const int DefaultNewHeaderOffset = 128; private static readonly byte[] DefaultDosHeader = new byte[128] { 77, 90, 144, 0, 3, 0, 0, 0, 4, 0, 0, 0, 255, 255, 0, 0, 184, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 14, 31, 186, 14, 0, 180, 9, 205, 33, 184, 1, 76, 205, 33, 84, 104, 105, 115, 32, 112, 114, 111, 103, 114, 97, 109, 32, 99, 97, 110, 110, 111, 116, 32, 98, 101, 32, 114, 117, 110, 32, 105, 110, 32, 68, 79, 83, 32, 109, 111, 100, 101, 46, 13, 13, 10, 36, 0, 0, 0, 0, 0, 0, 0 }; private readonly byte[] _stub; public uint NextHeaderOffset { get; set; } public static DosHeader FromReader(ref BinaryStreamReader reader) { ulong offset = ((BinaryStreamReader)(ref reader)).Offset; uint rva = ((BinaryStreamReader)(ref reader)).Rva; byte[] array = new byte[128]; if (((BinaryStreamReader)(ref reader)).ReadUInt16() != 23117) { throw new BadImageFormatException(); } ((BinaryStreamReader)(ref reader)).Offset = ((BinaryStreamReader)(ref reader)).Offset + 58; uint num = ((BinaryStreamReader)(ref reader)).ReadUInt32(); if (num != 128) { Array.Resize(ref array, (int)num); } ((BinaryStreamReader)(ref reader)).Offset = ((BinaryStreamReader)(ref reader)).Offset - 64; ((BinaryStreamReader)(ref reader)).ReadBytes(array, 0, array.Length); DosHeader dosHeader = new DosHeader(array); ((SegmentBase)dosHeader).Offset = offset; ((SegmentBase)dosHeader).Rva = rva; dosHeader.NextHeaderOffset = num; return dosHeader; } public DosHeader() : this(DefaultDosHeader) { NextHeaderOffset = 128u; } private DosHeader(byte[] stub) { _stub = stub ?? throw new ArgumentNullException("stub"); } public override uint GetPhysicalSize() { return (uint)_stub.Length; } public override void Write(IBinaryStreamWriter writer) { writer.WriteBytes(_stub, 0, 60); writer.WriteUInt32(NextHeaderOffset); writer.WriteBytes(_stub, 64, _stub.Length - 60 - 4); } } public class FileHeader : SegmentBase { public const int FileHeaderSize = 20; public MachineType Machine { get; set; } = MachineType.I386; public ushort NumberOfSections { get; set; } public uint TimeDateStamp { get; set; } public uint PointerToSymbolTable { get; set; } public uint NumberOfSymbols { get; set; } public ushort SizeOfOptionalHeader { get; set; } = 224; public Characteristics Characteristics { get; set; } = Characteristics.Image | Characteristics.Machine32Bit; public static FileHeader FromReader(ref BinaryStreamReader reader) { FileHeader fileHeader = new FileHeader(); ((SegmentBase)fileHeader).Offset = ((BinaryStreamReader)(ref reader)).Offset; ((SegmentBase)fileHeader).Rva = ((BinaryStreamReader)(ref reader)).Rva; fileHeader.Machine = (MachineType)((BinaryStreamReader)(ref reader)).ReadUInt16(); fileHeader.NumberOfSections = ((BinaryStreamReader)(ref reader)).ReadUInt16(); fileHeader.TimeDateStamp = ((BinaryStreamReader)(ref reader)).ReadUInt32(); fileHeader.PointerToSymbolTable = ((BinaryStreamReader)(ref reader)).ReadUInt32(); fileHeader.NumberOfSymbols = ((BinaryStreamReader)(ref reader)).ReadUInt32(); fileHeader.SizeOfOptionalHeader = ((BinaryStreamReader)(ref reader)).ReadUInt16(); fileHeader.Characteristics = (Characteristics)((BinaryStreamReader)(ref reader)).ReadUInt16(); return fileHeader; } public override uint GetPhysicalSize() { return 20u; } public override void Write(IBinaryStreamWriter writer) { writer.WriteUInt16((ushort)Machine); writer.WriteUInt16(NumberOfSections); writer.WriteUInt32(TimeDateStamp); writer.WriteUInt32(PointerToSymbolTable); writer.WriteUInt32(NumberOfSymbols); writer.WriteUInt16(SizeOfOptionalHeader); writer.WriteUInt16((ushort)Characteristics); } } public enum MachineType : ushort { Unknown = 0, DotNetAppleOSOverride = 17988, DotNetFreeBsdOSOverride = 44484, DotNetLinuxOSOverride = 31609, DotNetNetBsdOSOverride = 6547, DotNetSunOSOverride = 6546, Am33 = 467, Amd64 = 34404, Amd64DotNetApple = 49184, Amd64DotNetFreeBsd = 11168, Amd64DotNetLinux = 64797, Amd64DotNetNetBsd = 40951, Amd64DotNetSun = 40950, Arm = 448, ArmNt = 452, ArmNtDotNetApple = 18304, ArmNtDotNetFreeBsd = 44032, ArmNtDotNetLinux = 31421, ArmNtDotNetNetBsd = 6231, Arm64 = 43620, Arm64DotNetApple = 60448, Arm64DotNetFreeBsd = 1952, Arm64DotNetLinux = 53533, Arm64DotNetNetBsd = 46071, Ebc = 3772, I386 = 332, I386DotNetApple = 18184, I386DotNetFreeBsd = 44168, I386DotNetLinux = 31285, I386DotNetNetBsd = 6367, I386DotNetSun = 6366, Ia64 = 512, M32R = 36929, Mips16 = 614, MipsFpu = 870, MipsFpu16 = 1126, PowerPc = 496, PowerPcFp = 497, R4000 = 358, Sh3 = 418, Sh3Dsp = 419, Sh4 = 422, Sh5 = 424, Thumb = 450, WceMipsV2 = 361, RiscV32 = 20530, RiscV64 = 20580, RiscV128 = 20776 } public class OptionalHeader : SegmentBase { public const uint OptionalHeaderSizeOfImageFieldOffset = 56u; public const uint OptionalHeader32SizeExcludingDataDirectories = 96u; public const uint OptionalHeader64SizeExcludingDataDirectories = 112u; public const int DefaultNumberOfRvasAndSizes = 16; public OptionalHeaderMagic Magic { get; set; } = OptionalHeaderMagic.PE32; public byte MajorLinkerVersion { get; set; } = 48; public byte MinorLinkerVersion { get; set; } = 24; public uint SizeOfCode { get; set; } public uint SizeOfInitializedData { get; set; } public uint SizeOfUninitializedData { get; set; } public uint AddressOfEntryPoint { get; set; } public uint BaseOfCode { get; set; } public uint BaseOfData { get; set; } public ulong ImageBase { get; set; } = 4194304uL; public uint SectionAlignment { get; set; } = 8192u; public uint FileAlignment { get; set; } = 512u; public ushort MajorOperatingSystemVersion { get; set; } = 4; public ushort MinorOperatingSystemVersion { get; set; } public ushort MajorImageVersion { get; set; } public ushort MinorImageVersion { get; set; } public ushort MajorSubsystemVersion { get; set; } = 4; public ushort MinorSubsystemVersion { get; set; } public uint Win32VersionValue { get; set; } public uint SizeOfImage { get; set; } public uint SizeOfHeaders { get; set; } public uint CheckSum { get; set; } public SubSystem SubSystem { get; set; } = SubSystem.WindowsCui; public DllCharacteristics DllCharacteristics { get; set; } = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompat | DllCharacteristics.TerminalServerAware; public ulong SizeOfStackReserve { get; set; } = 16777216uL; public ulong SizeOfStackCommit { get; set; } = 4096uL; public ulong SizeOfHeapReserve { get; set; } = 16777216uL; public ulong SizeOfHeapCommit { get; set; } = 4096uL; public uint LoaderFlags { get; set; } public uint NumberOfRvaAndSizes { get; set; } = 16u; public IList DataDirectories { get; } = new DataDirectory[16].ToList(); public static OptionalHeader FromReader(ref BinaryStreamReader reader, bool ignoreNumberOfRvasAndSizes = true) { OptionalHeader optionalHeader = new OptionalHeader(); ((SegmentBase)optionalHeader).Offset = ((BinaryStreamReader)(ref reader)).Offset; ((SegmentBase)optionalHeader).Rva = ((BinaryStreamReader)(ref reader)).Rva; optionalHeader.Magic = (OptionalHeaderMagic)((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader.MajorLinkerVersion = ((BinaryStreamReader)(ref reader)).ReadByte(); optionalHeader.MinorLinkerVersion = ((BinaryStreamReader)(ref reader)).ReadByte(); optionalHeader.SizeOfCode = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader.SizeOfInitializedData = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader.SizeOfUninitializedData = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader.AddressOfEntryPoint = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader.BaseOfCode = ((BinaryStreamReader)(ref reader)).ReadUInt32(); OptionalHeader optionalHeader2 = optionalHeader; switch (optionalHeader2.Magic) { case OptionalHeaderMagic.PE32: optionalHeader2.BaseOfData = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.ImageBase = ((BinaryStreamReader)(ref reader)).ReadUInt32(); break; case OptionalHeaderMagic.PE32Plus: optionalHeader2.ImageBase = ((BinaryStreamReader)(ref reader)).ReadUInt64(); break; default: throw new BadImageFormatException("Unrecognized or unsupported optional header format."); } optionalHeader2.SectionAlignment = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.FileAlignment = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.MajorOperatingSystemVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.MinorOperatingSystemVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.MajorImageVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.MinorImageVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.MajorSubsystemVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.MinorSubsystemVersion = ((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.Win32VersionValue = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SizeOfImage = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SizeOfHeaders = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.CheckSum = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SubSystem = (SubSystem)((BinaryStreamReader)(ref reader)).ReadUInt16(); optionalHeader2.DllCharacteristics = (DllCharacteristics)((BinaryStreamReader)(ref reader)).ReadUInt16(); if (optionalHeader2.Magic == OptionalHeaderMagic.PE32) { optionalHeader2.SizeOfStackReserve = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SizeOfStackCommit = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SizeOfHeapReserve = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.SizeOfHeapCommit = ((BinaryStreamReader)(ref reader)).ReadUInt32(); } else { optionalHeader2.SizeOfStackReserve = ((BinaryStreamReader)(ref reader)).ReadUInt64(); optionalHeader2.SizeOfStackCommit = ((BinaryStreamReader)(ref reader)).ReadUInt64(); optionalHeader2.SizeOfHeapReserve = ((BinaryStreamReader)(ref reader)).ReadUInt64(); optionalHeader2.SizeOfHeapCommit = ((BinaryStreamReader)(ref reader)).ReadUInt64(); } optionalHeader2.LoaderFlags = ((BinaryStreamReader)(ref reader)).ReadUInt32(); optionalHeader2.NumberOfRvaAndSizes = ((BinaryStreamReader)(ref reader)).ReadUInt32(); int num = (int)(ignoreNumberOfRvasAndSizes ? 16 : optionalHeader2.NumberOfRvaAndSizes); optionalHeader2.DataDirectories.Clear(); for (int i = 0; i < num; i++) { optionalHeader2.DataDirectories.Add(DataDirectory.FromReader(ref reader)); } return optionalHeader2; } public DataDirectory GetDataDirectory(DataDirectoryIndex index) { return DataDirectories[(int)index]; } public override uint GetPhysicalSize() { if (Magic != OptionalHeaderMagic.PE32) { return 240u; } return 224u; } public override void Write(IBinaryStreamWriter writer) { ulong offset = writer.Offset; writer.WriteUInt16((ushort)Magic); writer.WriteByte(MajorLinkerVersion); writer.WriteByte(MinorLinkerVersion); writer.WriteUInt32(SizeOfCode); writer.WriteUInt32(SizeOfInitializedData); writer.WriteUInt32(SizeOfUninitializedData); writer.WriteUInt32(AddressOfEntryPoint); writer.WriteUInt32(BaseOfCode); switch (Magic) { case OptionalHeaderMagic.PE32: writer.WriteUInt32(BaseOfData); writer.WriteUInt32((uint)ImageBase); break; case OptionalHeaderMagic.PE32Plus: writer.WriteUInt64(ImageBase); break; default: throw new BadImageFormatException("Unrecognized or unsupported optional header format."); } writer.WriteUInt32(SectionAlignment); writer.WriteUInt32(FileAlignment); writer.WriteUInt16(MajorOperatingSystemVersion); writer.WriteUInt16(MinorOperatingSystemVersion); writer.WriteUInt16(MajorImageVersion); writer.WriteUInt16(MinorImageVersion); writer.WriteUInt16(MajorSubsystemVersion); writer.WriteUInt16(MinorSubsystemVersion); writer.WriteUInt32(Win32VersionValue); writer.WriteUInt32(SizeOfImage); writer.WriteUInt32(SizeOfHeaders); writer.WriteUInt32(CheckSum); writer.WriteUInt16((ushort)SubSystem); writer.WriteUInt16((ushort)DllCharacteristics); if (Magic == OptionalHeaderMagic.PE32) { writer.WriteUInt32((uint)SizeOfStackReserve); writer.WriteUInt32((uint)SizeOfStackCommit); writer.WriteUInt32((uint)SizeOfHeapReserve); writer.WriteUInt32((uint)SizeOfHeapCommit); } else { writer.WriteUInt64(SizeOfStackReserve); writer.WriteUInt64(SizeOfStackCommit); writer.WriteUInt64(SizeOfHeapReserve); writer.WriteUInt64(SizeOfHeapCommit); } writer.WriteUInt32(LoaderFlags); writer.WriteUInt32(NumberOfRvaAndSizes); foreach (DataDirectory dataDirectory in DataDirectories) { dataDirectory.Write(writer); } IOExtensions.WriteZeroes(writer, (int)(((SegmentBase)this).GetPhysicalSize() - (writer.Offset - offset))); } } public enum OptionalHeaderMagic : ushort { PE32 = 267, PE32Plus = 523, PE64 = 523 } [Flags] public enum SectionFlags : uint { TypeDsect = 1u, TypeNoLoad = 2u, TypeGroup = 4u, TypeNoPadded = 8u, TypeCopy = 0x10u, ContentCode = 0x20u, ContentInitializedData = 0x40u, ContentUninitializedData = 0x80u, LinkOther = 0x100u, LinkInfo = 0x200u, TypeOver = 0x400u, LinkRemove = 0x800u, LinkComDat = 0x1000u, NoDeferSpecExceptions = 0x4000u, RelativeGp = 0x8000u, MemPurgeable = 0x20000u, Memory16Bit = 0x20000u, MemoryLocked = 0x40000u, MemoryPreload = 0x80000u, Align1Bytes = 0x100000u, Align2Bytes = 0x200000u, Align4Bytes = 0x300000u, Align8Bytes = 0x400000u, Align16Bytes = 0x500000u, Align32Bytes = 0x600000u, Align64Bytes = 0x700000u, Align128Bytes = 0x800000u, Align256Bytes = 0x900000u, Align512Bytes = 0xA00000u, Align1024Bytes = 0xB00000u, Align2048Bytes = 0xC00000u, Align4096Bytes = 0xD00000u, Align8192Bytes = 0xE00000u, LinkExtendedRelocationOverflow = 0x1000000u, MemoryDiscardable = 0x2000000u, MemoryNotCached = 0x4000000u, MemoryNotPaged = 0x8000000u, MemoryShared = 0x10000000u, MemoryExecute = 0x20000000u, MemoryRead = 0x40000000u, MemoryWrite = 0x80000000u } public class SectionHeader : SegmentBase, IOffsetConverter { public const uint SectionHeaderSize = 40u; private string _name; public string Name { get { return _name; } set { if (Encoding.UTF8.GetByteCount(value) > 8) { throw new ArgumentException("Name is too long."); } _name = value; } } public uint VirtualSize { get; set; } public uint VirtualAddress { get; set; } public uint SizeOfRawData { get; set; } public uint PointerToRawData { get; set; } public uint PointerToRelocations { get; set; } public uint PointerToLineNumbers { get; set; } public ushort NumberOfRelocations { get; set; } public ushort NumberOfLineNumbers { get; set; } public SectionFlags Characteristics { get; set; } public static SectionHeader FromReader(ref BinaryStreamReader reader) { ulong offset = ((BinaryStreamReader)(ref reader)).Offset; uint rva = ((BinaryStreamReader)(ref reader)).Rva; byte[] array = new byte[8]; ((BinaryStreamReader)(ref reader)).ReadBytes(array, 0, array.Length); SectionHeader sectionHeader = new SectionHeader(Encoding.UTF8.GetString(array).Replace("\0", ""), (SectionFlags)0u); ((SegmentBase)sectionHeader).Offset = offset; ((SegmentBase)sectionHeader).Rva = rva; sectionHeader.VirtualSize = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.VirtualAddress = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.SizeOfRawData = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.PointerToRawData = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.PointerToRelocations = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.PointerToLineNumbers = ((BinaryStreamReader)(ref reader)).ReadUInt32(); sectionHeader.NumberOfRelocations = ((BinaryStreamReader)(ref reader)).ReadUInt16(); sectionHeader.NumberOfLineNumbers = ((BinaryStreamReader)(ref reader)).ReadUInt16(); sectionHeader.Characteristics = (SectionFlags)((BinaryStreamReader)(ref reader)).ReadUInt32(); return sectionHeader; } public SectionHeader(string name, SectionFlags characteristics) { AssertIsValidName(name); _name = name; Characteristics = characteristics; } public SectionHeader(SectionHeader value) { ((SegmentBase)this).Offset = ((SegmentBase)value).Offset; ((SegmentBase)this).Rva = ((SegmentBase)value).Rva; _name = value.Name; VirtualSize = value.VirtualSize; VirtualAddress = value.VirtualAddress; SizeOfRawData = value.SizeOfRawData; PointerToRawData = value.PointerToRawData; PointerToRelocations = value.PointerToRelocations; PointerToLineNumbers = value.PointerToLineNumbers; NumberOfRelocations = value.NumberOfRelocations; NumberOfLineNumbers = value.NumberOfLineNumbers; Characteristics = value.Characteristics; } public override uint GetPhysicalSize() { return 40u; } public bool ContainsFileOffset(ulong fileOffset) { if (PointerToRawData <= fileOffset) { return fileOffset < PointerToRawData + SizeOfRawData; } return false; } public bool ContainsRva(uint rva) { if (VirtualAddress <= rva) { return rva < VirtualAddress + VirtualSize; } return false; } public uint FileOffsetToRva(ulong fileOffset) { if (!ContainsFileOffset(fileOffset)) { throw new ArgumentOutOfRangeException("fileOffset"); } return (uint)(fileOffset - PointerToRawData + VirtualAddress); } public ulong RvaToFileOffset(uint rva) { if (!ContainsRva(rva)) { throw new ArgumentOutOfRangeException("rva"); } return rva - VirtualAddress + PointerToRawData; } public override void Write(IBinaryStreamWriter writer) { byte[] bytes = Encoding.UTF8.GetBytes(Name); IOExtensions.WriteBytes(writer, bytes); IOExtensions.WriteZeroes(writer, 8 - bytes.Length); writer.WriteUInt32(VirtualSize); writer.WriteUInt32(VirtualAddress); writer.WriteUInt32(SizeOfRawData); writer.WriteUInt32(PointerToRawData); writer.WriteUInt32(PointerToRelocations); writer.WriteUInt32(PointerToLineNumbers); writer.WriteUInt16(NumberOfRelocations); writer.WriteUInt16(NumberOfLineNumbers); writer.WriteUInt32((uint)Characteristics); } public override string ToString() { return $"{Name} ({"VirtualAddress"}: {VirtualAddress:X8}, {"VirtualSize"}: {VirtualSize:X8}, {"PointerToRawData"}: {PointerToRawData:X8}, {"SizeOfRawData"}: {SizeOfRawData:X8}, {"Characteristics"}: {Characteristics})"; } internal static void AssertIsValidName(string value) { if (Encoding.UTF8.GetByteCount(value) > 8) { throw new ArgumentException("Section name cannot be longer than 8 characters."); } } } public enum SubSystem { Unknown = 0, Native = 1, WindowsGui = 2, WindowsCui = 3, PosixCui = 7, NativeWindows = 8, WindowsCeGui = 9, EfiApplication = 10, EfiBootServiceDriver = 11, EfiRuntime = 12, EfiRom = 13, Xbox = 14, WindowsBootApplication = 16 } }