2025-04-20 19:54:52 +03:00
|
|
|
using X86Disassembler.PE.Types;
|
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
namespace X86Disassembler.PE.Parsers;
|
2025-04-12 17:12:18 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
/// <summary>
|
|
|
|
/// Parser for the Optional header of a PE file
|
|
|
|
/// </summary>
|
|
|
|
public class OptionalHeaderParser : IParser<OptionalHeader>
|
2025-04-12 17:12:18 +03:00
|
|
|
{
|
2025-04-12 18:23:18 +03:00
|
|
|
// Optional Header Magic values
|
2025-04-20 19:54:52 +03:00
|
|
|
private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
|
|
|
|
private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
|
|
|
|
|
2025-04-12 17:12:18 +03:00
|
|
|
/// <summary>
|
2025-04-12 18:23:18 +03:00
|
|
|
/// Parse the Optional header from the binary reader
|
2025-04-12 17:12:18 +03:00
|
|
|
/// </summary>
|
2025-04-12 18:23:18 +03:00
|
|
|
/// <param name="reader">The binary reader positioned at the start of the Optional header</param>
|
|
|
|
/// <returns>The parsed Optional header</returns>
|
|
|
|
public OptionalHeader Parse(BinaryReader reader)
|
2025-04-12 17:12:18 +03:00
|
|
|
{
|
2025-04-20 19:54:52 +03:00
|
|
|
var header = new OptionalHeader();
|
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// Standard fields
|
|
|
|
header.Magic = reader.ReadUInt16();
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// Determine if this is a PE32 or PE32+ file
|
2025-04-20 19:54:52 +03:00
|
|
|
var is64Bit = header.Magic == PE32PLUS_MAGIC;
|
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
header.MajorLinkerVersion = reader.ReadByte();
|
|
|
|
header.MinorLinkerVersion = reader.ReadByte();
|
|
|
|
header.SizeOfCode = reader.ReadUInt32();
|
|
|
|
header.SizeOfInitializedData = reader.ReadUInt32();
|
|
|
|
header.SizeOfUninitializedData = reader.ReadUInt32();
|
|
|
|
header.AddressOfEntryPoint = reader.ReadUInt32();
|
|
|
|
header.BaseOfCode = reader.ReadUInt32();
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// PE32 has BaseOfData, PE32+ doesn't
|
|
|
|
if (!is64Bit)
|
|
|
|
{
|
|
|
|
header.BaseOfData = reader.ReadUInt32();
|
|
|
|
}
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// Windows-specific fields
|
2025-04-20 19:54:52 +03:00
|
|
|
header.ImageBase = is64Bit
|
|
|
|
? reader.ReadUInt64()
|
|
|
|
: reader.ReadUInt32();
|
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
header.SectionAlignment = reader.ReadUInt32();
|
|
|
|
header.FileAlignment = reader.ReadUInt32();
|
|
|
|
header.MajorOperatingSystemVersion = reader.ReadUInt16();
|
|
|
|
header.MinorOperatingSystemVersion = reader.ReadUInt16();
|
|
|
|
header.MajorImageVersion = reader.ReadUInt16();
|
|
|
|
header.MinorImageVersion = reader.ReadUInt16();
|
|
|
|
header.MajorSubsystemVersion = reader.ReadUInt16();
|
|
|
|
header.MinorSubsystemVersion = reader.ReadUInt16();
|
|
|
|
header.Win32VersionValue = reader.ReadUInt32();
|
|
|
|
header.SizeOfImage = reader.ReadUInt32();
|
|
|
|
header.SizeOfHeaders = reader.ReadUInt32();
|
|
|
|
header.CheckSum = reader.ReadUInt32();
|
|
|
|
header.Subsystem = reader.ReadUInt16();
|
|
|
|
header.DllCharacteristics = reader.ReadUInt16();
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// Size fields differ between PE32 and PE32+
|
|
|
|
if (is64Bit)
|
|
|
|
{
|
|
|
|
header.SizeOfStackReserve = reader.ReadUInt64();
|
|
|
|
header.SizeOfStackCommit = reader.ReadUInt64();
|
|
|
|
header.SizeOfHeapReserve = reader.ReadUInt64();
|
|
|
|
header.SizeOfHeapCommit = reader.ReadUInt64();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
header.SizeOfStackReserve = reader.ReadUInt32();
|
|
|
|
header.SizeOfStackCommit = reader.ReadUInt32();
|
|
|
|
header.SizeOfHeapReserve = reader.ReadUInt32();
|
|
|
|
header.SizeOfHeapCommit = reader.ReadUInt32();
|
|
|
|
}
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
header.LoaderFlags = reader.ReadUInt32();
|
|
|
|
header.NumberOfRvaAndSizes = reader.ReadUInt32();
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
// Data directories
|
2025-04-20 19:54:52 +03:00
|
|
|
header.DataDirectories = new DataDirectory[header.NumberOfRvaAndSizes];
|
|
|
|
|
|
|
|
for (int i = 0; i < header.NumberOfRvaAndSizes; i++)
|
2025-04-12 17:12:18 +03:00
|
|
|
{
|
2025-04-20 19:54:52 +03:00
|
|
|
var dir = new DataDirectory();
|
2025-04-12 18:23:18 +03:00
|
|
|
dir.VirtualAddress = reader.ReadUInt32();
|
|
|
|
dir.Size = reader.ReadUInt32();
|
|
|
|
header.DataDirectories[i] = dir;
|
2025-04-12 17:12:18 +03:00
|
|
|
}
|
2025-04-20 19:54:52 +03:00
|
|
|
|
2025-04-12 18:23:18 +03:00
|
|
|
return header;
|
|
|
|
}
|
|
|
|
}
|