public sealed class NtHeadersParser
{
public NtHeaders Parse(BinaryReader reader, DosHeader dosHeader)
{
if (dosHeader.Lfanew < 0 || dosHeader.Lfanew > reader.BaseStream.Length - 4)
{
throw new SafetyException("Invalid e_lfanew.");
}
reader.BaseStream.Position = dosHeader.Lfanew;
var signature = reader.ReadUInt32();
var fileHeader = new FileHeader(
(MachineType)reader.ReadUInt16(),
reader.ReadUInt16(),
reader.ReadUInt32(),
reader.ReadUInt32(),
reader.ReadUInt32(),
reader.ReadUInt16(),
reader.ReadUInt16());
var optionalHeaderStart = reader.BaseStream.Position;
var magic = reader.ReadUInt16();
var isPe32Plus = magic == 0x20B;
var majorLinkerVersion = reader.ReadByte();
var minorLinkerVersion = reader.ReadByte();
var sizeOfCode = reader.ReadUInt32();
var sizeOfInitializedData = reader.ReadUInt32();
var sizeOfUninitializedData = reader.ReadUInt32();
var addressOfEntryPoint = reader.ReadUInt32();
var baseOfCode = reader.ReadUInt32();
uint? baseOfData = null;
ulong imageBase;
if (!isPe32Plus)
{
baseOfData = reader.ReadUInt32();
imageBase = reader.ReadUInt32();
}
else
{
imageBase = reader.ReadUInt64();
}
var sectionAlignment = reader.ReadUInt32();
var fileAlignment = reader.ReadUInt32();
var majorOsVersion = reader.ReadUInt16();
var minorOsVersion = reader.ReadUInt16();
var majorImageVersion = reader.ReadUInt16();
var minorImageVersion = reader.ReadUInt16();
var majorSubsystemVersion = reader.ReadUInt16();
var minorSubsystemVersion = reader.ReadUInt16();
var win32VersionValue = reader.ReadUInt32();
var sizeOfImage = reader.ReadUInt32();
var sizeOfHeaders = reader.ReadUInt32();
var checkSum = reader.ReadUInt32();
var subsystem = (SubsystemType)reader.ReadUInt16();
var dllCharacteristics = reader.ReadUInt16();
ulong sizeOfStackReserve;
ulong sizeOfStackCommit;
ulong sizeOfHeapReserve;
ulong sizeOfHeapCommit;
if (!isPe32Plus)
{
sizeOfStackReserve = reader.ReadUInt32();
sizeOfStackCommit = reader.ReadUInt32();
sizeOfHeapReserve = reader.ReadUInt32();
sizeOfHeapCommit = reader.ReadUInt32();
}
else
{
sizeOfStackReserve = reader.ReadUInt64();
sizeOfStackCommit = reader.ReadUInt64();
sizeOfHeapReserve = reader.ReadUInt64();
sizeOfHeapCommit = reader.ReadUInt64();
}
var loaderFlags = reader.ReadUInt32();
var numberOfRvaAndSizes = reader.ReadUInt32();
var directories = new List<DataDirectory>();
var directoryCount = (int)Math.Min(numberOfRvaAndSizes, 16);
for (var i = 0; i < directoryCount; i++)
{
directories.Add(new DataDirectory(reader.ReadUInt32(), reader.ReadUInt32()));
}
var bytesRead = reader.BaseStream.Position - optionalHeaderStart;
var remaining = fileHeader.SizeOfOptionalHeader - bytesRead;
if (remaining > 0)
{
reader.BaseStream.Position += remaining;
}
var optionalHeader = new OptionalHeader(
isPe32Plus,
magic,
majorLinkerVersion,
minorLinkerVersion,
sizeOfCode,
sizeOfInitializedData,
sizeOfUninitializedData,
addressOfEntryPoint,
baseOfCode,
baseOfData,
imageBase,
sectionAlignment,
fileAlignment,
majorOsVersion,
minorOsVersion,
majorImageVersion,
minorImageVersion,
majorSubsystemVersion,
minorSubsystemVersion,
win32VersionValue,
sizeOfImage,
sizeOfHeaders,
checkSum,
subsystem,
dllCharacteristics,
sizeOfStackReserve,
sizeOfStackCommit,
sizeOfHeapReserve,
sizeOfHeapCommit,
loaderFlags,
numberOfRvaAndSizes,
directories);
return new NtHeaders(signature, fileHeader, optionalHeader);
}
}