public sealed class CertificateDirectoryParser
{
public IReadOnlyList<CertificateInfo> Parse(byte[] rawBytes, NtHeaders nt)
{
if (nt.OptionalHeader.DataDirectories.Count <= 4)
{
return Array.Empty<CertificateInfo>();
}
var dir = nt.OptionalHeader.DataDirectories[4];
if (dir.VirtualAddress == 0 || dir.Size == 0)
{
return Array.Empty<CertificateInfo>();
}
// Certificate directory uses file offsets, not RVA.
var pos = (int)dir.VirtualAddress;
var end = Math.Min(rawBytes.Length, pos + (int)dir.Size);
var items = new List<CertificateInfo>();
while (pos + 8 <= end)
{
var length = BitConverter.ToUInt32(rawBytes, pos);
var revision = BitConverter.ToUInt16(rawBytes, pos + 4);
var type = BitConverter.ToUInt16(rawBytes, pos + 6);
if (length < 8 || pos + length > end)
{
break;
}
var dataLen = (int)length - 8;
var data = new byte[dataLen];
Buffer.BlockCopy(rawBytes, pos + 8, data, 0, dataLen);
items.Add(new CertificateInfo(length, revision, type, data));
var aligned = (int)length + 7 & ~7;
pos += aligned;
}
return items;
}
}