public sealed class DosHeaderParser
{
public DosHeader Parse(BinaryReader reader)
{
reader.BaseStream.Position = 0;
var magic = reader.ReadUInt16();
var cblp = reader.ReadUInt16();
var cp = reader.ReadUInt16();
var crlc = reader.ReadUInt16();
var cparhdr = reader.ReadUInt16();
var minAlloc = reader.ReadUInt16();
var maxAlloc = reader.ReadUInt16();
var ss = reader.ReadUInt16();
var sp = reader.ReadUInt16();
var csum = reader.ReadUInt16();
var ip = reader.ReadUInt16();
var cs = reader.ReadUInt16();
var lfarlc = reader.ReadUInt16();
var ovno = reader.ReadUInt16();
var res = new ushort[4];
for (var i = 0; i < 4; i++) res[i] = reader.ReadUInt16();
var oemId = reader.ReadUInt16();
var oemInfo = reader.ReadUInt16();
var res2 = new ushort[10];
for (var i = 0; i < 10; i++) res2[i] = reader.ReadUInt16();
var lfanew = reader.ReadInt32();
return new DosHeader(
magic,
cblp,
cp,
crlc,
cparhdr,
minAlloc,
maxAlloc,
ss,
sp,
csum,
ip,
cs,
lfarlc,
ovno,
res,
oemId,
oemInfo,
res2,
lfanew);
}
public byte[] ParseDosStub(byte[] rawBytes, int lfanew)
{
var dosHeaderSize = 64;
if (lfanew <= dosHeaderSize || lfanew > rawBytes.Length)
{
return Array.Empty<byte>();
}
var size = lfanew - dosHeaderSize;
var stub = new byte[size];
Buffer.BlockCopy(rawBytes, dosHeaderSize, stub, 0, size);
return stub;
}
public RichHeaderInfo? ParseRichHeader(byte[] rawBytes, int lfanew)
{
if (lfanew <= 0 || lfanew > rawBytes.Length)
{
return null;
}
var richIndex = FindAscii(rawBytes, 0, lfanew, "Rich");
if (richIndex < 0 || richIndex + 8 > lfanew)
{
return null;
}
var xorKey = BitConverter.ToUInt32(rawBytes, richIndex + 4);
var dansIndex = FindXorAscii(rawBytes, 0, richIndex, "DanS", xorKey);
if (dansIndex < 0)
{
return null;
}
var entries = new List<RichHeaderEntry>();
for (var pos = dansIndex + 16; pos + 8 <= richIndex; pos += 8)
{
var compId = BitConverter.ToUInt32(rawBytes, pos) ^ xorKey;
var count = BitConverter.ToUInt32(rawBytes, pos + 4) ^ xorKey;
entries.Add(new RichHeaderEntry(compId, count));
}
return new RichHeaderInfo(xorKey, entries);
}
private static int FindAscii(byte[] data, int start, int end, string text)
{
var pattern = System.Text.Encoding.ASCII.GetBytes(text);
for (var i = start; i <= end - pattern.Length; i++)
{
var matched = true;
for (var j = 0; j < pattern.Length; j++)
{
if (data[i + j] != pattern[j])
{
matched = false;
break;
}
}
if (matched)
{
return i;
}
}
return -1;
}
private static int FindXorAscii(byte[] data, int start, int end, string text, uint xorKey)
{
var pattern = System.Text.Encoding.ASCII.GetBytes(text);
var xorBytes = BitConverter.GetBytes(xorKey);
for (var i = start; i <= end - pattern.Length; i++)
{
var matched = true;
for (var j = 0; j < pattern.Length; j++)
{
if ((byte)(data[i + j] ^ xorBytes[j % 4]) != pattern[j])
{
matched = false;
break;
}
}
if (matched)
{
return i;
}
}
return -1;
}
}