public sealed class SectionHeaderParser
{
public IReadOnlyList<SectionInfo> Parse(BinaryReader reader, NtHeaders ntHeaders, SafetyLimits limits, byte[] rawBytes)
{
var count = ntHeaders.FileHeader.NumberOfSections;
BoundsChecker.EnsureCount(count, limits.MaxSectionsCount, "Section count");
var sections = new List<SectionInfo>(count);
for (var i = 0; i < count; i++)
{
var name = System.Text.Encoding.ASCII.GetString(reader.ReadBytes(8)).TrimEnd('\0');
var virtualSize = reader.ReadUInt32();
var virtualAddress = reader.ReadUInt32();
var sizeOfRawData = reader.ReadUInt32();
var pointerToRawData = reader.ReadUInt32();
var pointerToRelocations = reader.ReadUInt32();
var pointerToLinenumbers = reader.ReadUInt32();
var numberOfRelocations = reader.ReadUInt16();
var numberOfLinenumbers = reader.ReadUInt16();
var characteristics = reader.ReadUInt32();
var entropy = CalculateEntropy(rawBytes, pointerToRawData, sizeOfRawData);
sections.Add(new SectionInfo(
name,
virtualSize,
virtualAddress,
sizeOfRawData,
pointerToRawData,
pointerToRelocations,
pointerToLinenumbers,
numberOfRelocations,
numberOfLinenumbers,
characteristics,
entropy));
}
return sections;
}
private static double CalculateEntropy(byte[] data, uint offset, uint size)
{
if (size == 0 || offset >= data.Length)
{
return 0d;
}
var maxSize = Math.Min((int)size, data.Length - (int)offset);
if (maxSize <= 0)
{
return 0d;
}
Span<int> frequencies = stackalloc int[256];
for (var i = 0; i < maxSize; i++)
{
frequencies[data[offset + i]]++;
}
double entropy = 0;
for (var i = 0; i < 256; i++)
{
if (frequencies[i] == 0)
{
continue;
}
var p = frequencies[i] / (double)maxSize;
entropy -= p * Math.Log2(p);
}
return entropy;
}
}