private PEImage(byte[] originalImage) : this() { OriginalImage = originalImage; using BinaryReader reader = new BinaryReader(new MemoryStream(OriginalImage)); // MZ if (reader.BaseStream.Length < 2) { throw new PEImageParseException(0, "DOS signature not found."); } if (reader.ReadUInt16() != 0x5a4d) { throw new PEImageParseException(0, "DOS header not found."); } // DOS Header if (reader.BaseStream.Length - reader.BaseStream.Position < 64) { throw new PEImageParseException((int)reader.BaseStream.Position, "DOS header incomplete."); } DosHeader = new ImageDosHeader { LastPageSize = reader.ReadUInt16(), PageCount = reader.ReadUInt16(), RelocationCount = reader.ReadUInt16(), HeaderSize = reader.ReadUInt16(), MinAlloc = reader.ReadUInt16(), MaxAlloc = reader.ReadUInt16(), InitialSS = reader.ReadUInt16(), InitialSP = reader.ReadUInt16(), Checksum = reader.ReadUInt16(), InitialIP = reader.ReadUInt16(), InitialCS = reader.ReadUInt16(), RelocationOffset = reader.ReadUInt16(), OverlayNumber = reader.ReadUInt16(), Reserved1 = reader.ReadUInt16(), Reserved2 = reader.ReadUInt16(), Reserved3 = reader.ReadUInt16(), Reserved4 = reader.ReadUInt16(), OemIdentifier = reader.ReadUInt16(), OemInformation = reader.ReadUInt16(), Reserved5 = reader.ReadUInt16(), Reserved6 = reader.ReadUInt16(), Reserved7 = reader.ReadUInt16(), Reserved8 = reader.ReadUInt16(), Reserved9 = reader.ReadUInt16(), Reserved10 = reader.ReadUInt16(), Reserved11 = reader.ReadUInt16(), Reserved12 = reader.ReadUInt16(), Reserved13 = reader.ReadUInt16(), Reserved14 = reader.ReadUInt16(), PEHeaderOffset = reader.ReadUInt32() }; // DOS Stub if (reader.BaseStream.Length < DosHeader.PEHeaderOffset) { throw new PEImageParseException((int)reader.BaseStream.Position, "DOS stub incomplete."); } DosStub = reader.ReadBytes((int)(DosHeader.PEHeaderOffset - reader.BaseStream.Position)); // COFF Header if (reader.ReadUInt32() != 0x4550) { throw new PEImageParseException((int)reader.BaseStream.Position - 4, "COFF header not found."); } if (reader.BaseStream.Length - reader.BaseStream.Position < 20) { throw new PEImageParseException((int)reader.BaseStream.Position, "COFF header incomplete."); } CoffHeader = new ImageCoffHeader { Machine = (ImageMachineType)reader.ReadUInt16(), NumberOfSections = reader.ReadUInt16(), TimeDateStamp = reader.ReadUInt32(), PointerToSymbolTable = reader.ReadUInt32(), NumberOfSymbols = reader.ReadUInt32(), SizeOfOptionalHeader = reader.ReadUInt16(), Characteristics = (ImageCharacteristics)reader.ReadUInt16() }; // Optional Header if (reader.BaseStream.Length - reader.BaseStream.Position < 2) { throw new PEImageParseException((int)reader.BaseStream.Position, "Optional header not found."); } ushort magic = reader.ReadUInt16(); if (magic == 0x10b) { if (reader.BaseStream.Length - reader.BaseStream.Position < 94) { throw new PEImageParseException((int)reader.BaseStream.Position, "Optional header incomplete."); } OptionalHeader = new ImageOptionalHeader32 { MajorLinkerVersion = reader.ReadByte(), MinorLinkerVersion = reader.ReadByte(), SizeOfCode = reader.ReadUInt32(), SizeOfInitializedData = reader.ReadUInt32(), SizeOfUninitializedData = reader.ReadUInt32(), AddressOfEntryPoint = reader.ReadUInt32(), BaseOfCode = reader.ReadUInt32(), BaseOfData = reader.ReadUInt32(), ImageBase = reader.ReadUInt32(), SectionAlignment = reader.ReadUInt32(), FileAlignment = reader.ReadUInt32(), MajorOperatingSystemVersion = reader.ReadUInt16(), MinorOperatingSystemVersion = reader.ReadUInt16(), MajorImageVersion = reader.ReadUInt16(), MinorImageVersion = reader.ReadUInt16(), MajorSubsystemVersion = reader.ReadUInt16(), MinorSubsystemVersion = reader.ReadUInt16(), Win32VersionValue = reader.ReadUInt32(), SizeOfImage = reader.ReadUInt32(), SizeOfHeaders = reader.ReadUInt32(), Checksum = reader.ReadUInt32(), Subsystem = (ImageSubsystem)reader.ReadUInt16(), DllCharacteristics = (ImageDllCharacteristics)reader.ReadUInt16(), SizeOfStackReserve = reader.ReadUInt32(), SizeOfStackCommit = reader.ReadUInt32(), SizeOfHeapReserve = reader.ReadUInt32(), SizeOfHeapCommit = reader.ReadUInt32(), LoaderFlags = reader.ReadUInt32(), NumberOfRvaAndSizes = reader.ReadUInt32() }; } else if (magic == 0x20b) { if (reader.BaseStream.Length - reader.BaseStream.Position < 110) { throw new PEImageParseException((int)reader.BaseStream.Position, "Optional header incomplete."); } OptionalHeader = new ImageOptionalHeader64 { MajorLinkerVersion = reader.ReadByte(), MinorLinkerVersion = reader.ReadByte(), SizeOfCode = reader.ReadUInt32(), SizeOfInitializedData = reader.ReadUInt32(), SizeOfUninitializedData = reader.ReadUInt32(), AddressOfEntryPoint = reader.ReadUInt32(), BaseOfCode = reader.ReadUInt32(), ImageBase = reader.ReadUInt64(), SectionAlignment = reader.ReadUInt32(), FileAlignment = reader.ReadUInt32(), MajorOperatingSystemVersion = reader.ReadUInt16(), MinorOperatingSystemVersion = reader.ReadUInt16(), MajorImageVersion = reader.ReadUInt16(), MinorImageVersion = reader.ReadUInt16(), MajorSubsystemVersion = reader.ReadUInt16(), MinorSubsystemVersion = reader.ReadUInt16(), Win32VersionValue = reader.ReadUInt32(), SizeOfImage = reader.ReadUInt32(), SizeOfHeaders = reader.ReadUInt32(), Checksum = reader.ReadUInt32(), Subsystem = (ImageSubsystem)reader.ReadUInt16(), DllCharacteristics = (ImageDllCharacteristics)reader.ReadUInt16(), SizeOfStackReserve = reader.ReadUInt64(), SizeOfStackCommit = reader.ReadUInt64(), SizeOfHeapReserve = reader.ReadUInt64(), SizeOfHeapCommit = reader.ReadUInt64(), LoaderFlags = reader.ReadUInt32(), NumberOfRvaAndSizes = reader.ReadUInt32() }; } else if (magic == 0x107) { throw new PEImageParseException((int)reader.BaseStream.Position - 2, "Optional header for ROM's is not supported."); } else { throw new PEImageParseException((int)reader.BaseStream.Position - 2, "Optional header magic value of '0x" + magic.ToString("x4") + "' unknown."); } // Data Directories if (reader.BaseStream.Length - reader.BaseStream.Position < OptionalHeader.NumberOfRvaAndSizes * 8) { throw new PEImageParseException((int)reader.BaseStream.Position, "Data directories incomplete."); } OptionalHeader.DataDirectories = Create.Array((int)OptionalHeader.NumberOfRvaAndSizes, i => new ImageDataDirectory((ImageDataDirectoryName)i, reader.ReadUInt32(), reader.ReadUInt32())); // Section Headers if (reader.BaseStream.Length - reader.BaseStream.Position < CoffHeader.NumberOfSections * 40) { throw new PEImageParseException((int)reader.BaseStream.Position, "Section headers incomplete."); } Sections = Create .Enumerable(CoffHeader.NumberOfSections, i => new ImageSectionHeader { Name = reader.ReadBytes(8).TakeWhile(c => c != 0).ToArray().ToUTF8String(), VirtualSize = reader.ReadUInt32(), VirtualAddress = reader.ReadUInt32(), SizeOfRawData = reader.ReadUInt32(), PointerToRawData = reader.ReadUInt32(), PointerToRelocations = reader.ReadUInt32(), PointerToLineNumbers = reader.ReadUInt32(), NumberOfRelocations = reader.ReadUInt16(), NumberOfLineNumbers = reader.ReadUInt16(), Characteristics = (ImageSectionFlags)reader.ReadUInt32() }) .Select(header => { if (header.PointerToRawData + header.SizeOfRawData <= reader.BaseStream.Length) { return(new ImageSection(header, OriginalImage.GetBytes((int)header.PointerToRawData, (int)header.SizeOfRawData))); } else { throw new PEImageParseException((int)reader.BaseStream.Position, "Section '" + header.Name + "' incomplete."); } }) .ToArray(); }
/// <summary> /// Assembles this PE image file information into a binary file and returns the file as a <see cref="byte" />[]. /// </summary> /// <returns> /// A <see cref="byte" />[] representing the assembly of this instance. /// </returns> public byte[] ToBinary() { Check.ArgumentNull(DosHeader, nameof(DosHeader)); Check.ArgumentNull(DosStub, nameof(DosStub)); Check.ArgumentNull(CoffHeader, nameof(CoffHeader)); Check.ArgumentNull(OptionalHeader, nameof(OptionalHeader)); Check.ArgumentEx.ArrayValuesNotNull(OptionalHeader.DataDirectories, nameof(OptionalHeader) + "." + nameof(ImageOptionalHeader.DataDirectories)); Check.ArgumentNull(Sections, nameof(Sections)); Check.ArgumentEx.ArrayValuesNotNull(Sections, nameof(Sections)); Check.ArgumentEx.ArrayValuesNotNull(Sections.Select(section => section.Header), nameof(Sections) + "." + nameof(ImageSection.Header)); Check.ArgumentEx.ArrayValuesNotNull(Sections.Select(section => section.Data), nameof(Sections) + "." + nameof(ImageSection.Data)); using MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter writer = new BinaryWriter(memoryStream)) { // MZ writer.Write((ushort)0x5a4d); // DOS Header writer.Write(DosHeader.LastPageSize); writer.Write(DosHeader.PageCount); writer.Write(DosHeader.RelocationCount); writer.Write(DosHeader.HeaderSize); writer.Write(DosHeader.MinAlloc); writer.Write(DosHeader.MaxAlloc); writer.Write(DosHeader.InitialSS); writer.Write(DosHeader.InitialSP); writer.Write(DosHeader.Checksum); writer.Write(DosHeader.InitialIP); writer.Write(DosHeader.InitialCS); writer.Write(DosHeader.RelocationOffset); writer.Write(DosHeader.OverlayNumber); writer.Write(DosHeader.Reserved1); writer.Write(DosHeader.Reserved2); writer.Write(DosHeader.Reserved3); writer.Write(DosHeader.Reserved4); writer.Write(DosHeader.OemIdentifier); writer.Write(DosHeader.OemInformation); writer.Write(DosHeader.Reserved5); writer.Write(DosHeader.Reserved6); writer.Write(DosHeader.Reserved7); writer.Write(DosHeader.Reserved8); writer.Write(DosHeader.Reserved9); writer.Write(DosHeader.Reserved10); writer.Write(DosHeader.Reserved11); writer.Write(DosHeader.Reserved12); writer.Write(DosHeader.Reserved13); writer.Write(DosHeader.Reserved14); writer.Write(DosHeader.PEHeaderOffset); // DOS Stub writer.Write(DosStub); // COFF Header writer.Write(0x4550); writer.Write((ushort)CoffHeader.Machine); writer.Write(CoffHeader.NumberOfSections); writer.Write(CoffHeader.TimeDateStamp); writer.Write(CoffHeader.PointerToSymbolTable); writer.Write(CoffHeader.NumberOfSymbols); writer.Write(CoffHeader.SizeOfOptionalHeader); writer.Write((ushort)CoffHeader.Characteristics); // Optional Header if (OptionalHeader is ImageOptionalHeader32) { ImageOptionalHeader32 optionalHeader32 = (ImageOptionalHeader32)OptionalHeader; writer.Write((ushort)0x10b); writer.Write(optionalHeader32.MajorLinkerVersion); writer.Write(optionalHeader32.MinorLinkerVersion); writer.Write(optionalHeader32.SizeOfCode); writer.Write(optionalHeader32.SizeOfInitializedData); writer.Write(optionalHeader32.SizeOfUninitializedData); writer.Write(optionalHeader32.AddressOfEntryPoint); writer.Write(optionalHeader32.BaseOfCode); writer.Write(optionalHeader32.BaseOfData); writer.Write(optionalHeader32.ImageBase); writer.Write(optionalHeader32.SectionAlignment); writer.Write(optionalHeader32.FileAlignment); writer.Write(optionalHeader32.MajorOperatingSystemVersion); writer.Write(optionalHeader32.MinorOperatingSystemVersion); writer.Write(optionalHeader32.MajorImageVersion); writer.Write(optionalHeader32.MinorImageVersion); writer.Write(optionalHeader32.MajorSubsystemVersion); writer.Write(optionalHeader32.MinorSubsystemVersion); writer.Write(optionalHeader32.Win32VersionValue); writer.Write(optionalHeader32.SizeOfImage); writer.Write(optionalHeader32.SizeOfHeaders); writer.Write(optionalHeader32.Checksum); writer.Write((ushort)optionalHeader32.Subsystem); writer.Write((ushort)optionalHeader32.DllCharacteristics); writer.Write(optionalHeader32.SizeOfStackReserve); writer.Write(optionalHeader32.SizeOfStackCommit); writer.Write(optionalHeader32.SizeOfHeapReserve); writer.Write(optionalHeader32.SizeOfHeapCommit); writer.Write(optionalHeader32.LoaderFlags); writer.Write(optionalHeader32.NumberOfRvaAndSizes); } else if (OptionalHeader is ImageOptionalHeader64) { ImageOptionalHeader64 optionalHeader64 = (ImageOptionalHeader64)OptionalHeader; writer.Write((ushort)0x20b); writer.Write(optionalHeader64.MajorLinkerVersion); writer.Write(optionalHeader64.MinorLinkerVersion); writer.Write(optionalHeader64.SizeOfCode); writer.Write(optionalHeader64.SizeOfInitializedData); writer.Write(optionalHeader64.SizeOfUninitializedData); writer.Write(optionalHeader64.AddressOfEntryPoint); writer.Write(optionalHeader64.BaseOfCode); writer.Write(optionalHeader64.ImageBase); writer.Write(optionalHeader64.SectionAlignment); writer.Write(optionalHeader64.FileAlignment); writer.Write(optionalHeader64.MajorOperatingSystemVersion); writer.Write(optionalHeader64.MinorOperatingSystemVersion); writer.Write(optionalHeader64.MajorImageVersion); writer.Write(optionalHeader64.MinorImageVersion); writer.Write(optionalHeader64.MajorSubsystemVersion); writer.Write(optionalHeader64.MinorSubsystemVersion); writer.Write(optionalHeader64.Win32VersionValue); writer.Write(optionalHeader64.SizeOfImage); writer.Write(optionalHeader64.SizeOfHeaders); writer.Write(optionalHeader64.Checksum); writer.Write((ushort)optionalHeader64.Subsystem); writer.Write((ushort)optionalHeader64.DllCharacteristics); writer.Write(optionalHeader64.SizeOfStackReserve); writer.Write(optionalHeader64.SizeOfStackCommit); writer.Write(optionalHeader64.SizeOfHeapReserve); writer.Write(optionalHeader64.SizeOfHeapCommit); writer.Write(optionalHeader64.LoaderFlags); writer.Write(optionalHeader64.NumberOfRvaAndSizes); } else { throw Throw.InvalidOperation("Optional header type not recognized."); } // Data Directories foreach (ImageDataDirectory dataDirectory in OptionalHeader.DataDirectories) { writer.Write(dataDirectory.VirtualAddress); writer.Write(dataDirectory.Size); } // Section Headers foreach (ImageSectionHeader sectionHeader in Sections.Select(section => section.Header)) { writer.Write(sectionHeader.Name.PadRight(8, '\0').ToUTF8Bytes()); writer.Write(sectionHeader.VirtualSize); writer.Write(sectionHeader.VirtualAddress); writer.Write(sectionHeader.SizeOfRawData); writer.Write(sectionHeader.PointerToRawData); writer.Write(sectionHeader.PointerToRelocations); writer.Write(sectionHeader.PointerToLineNumbers); writer.Write(sectionHeader.NumberOfRelocations); writer.Write(sectionHeader.NumberOfLineNumbers); writer.Write((uint)sectionHeader.Characteristics); } // Section Data foreach (ImageSection section in Sections) { memoryStream.Seek((int)section.Header.PointerToRawData, SeekOrigin.Begin); writer.Write(section.Data); } } return(memoryStream.ToArray()); }