public sealed class ExceptionDirectoryParser
{
    public IReadOnlyList<ExceptionEntryInfo> Parse(byte[] rawBytes, NtHeaders nt, IReadOnlyList<SectionInfo> sections)
    {
        if (nt.OptionalHeader.DataDirectories.Count <= 3)
        {
            return Array.Empty<ExceptionEntryInfo>();
        }

        var dir = nt.OptionalHeader.DataDirectories[3];
        if (dir.VirtualAddress == 0 || dir.Size == 0)
        {
            return Array.Empty<ExceptionEntryInfo>();
        }

        var offset = RvaMapper.RvaToFileOffset(dir.VirtualAddress, sections, nt.OptionalHeader.SizeOfHeaders);
        if (offset is null)
        {
            return Array.Empty<ExceptionEntryInfo>();
        }

        var items = new List<ExceptionEntryInfo>();
        var entrySize = 12;
        var count = (int)(dir.Size / entrySize);

        for (var i = 0; i < count; i++)
        {
            var pos = offset.Value + i * entrySize;
            if (pos + entrySize > rawBytes.Length)
            {
                break;
            }

            items.Add(new ExceptionEntryInfo(
                BitConverter.ToUInt32(rawBytes, pos),
                BitConverter.ToUInt32(rawBytes, pos + 4),
                BitConverter.ToUInt32(rawBytes, pos + 8)));
        }

        return items;
    }
}