public sealed class X86Disassembler : IDisassembler
{
public Task<IReadOnlyList<ParsedInstruction>> DisassembleEntryPointAsync(PeImageInfo peInfo, int instructionCount, CancellationToken cancellationToken)
{
return Task.FromResult(Disassemble(peInfo, instructionCount));
}
private static IReadOnlyList<ParsedInstruction> Disassemble(PeImageInfo peInfo, int instructionCount)
{
var instructions = new List<ParsedInstruction>();
var raw = peInfo.RawBytes;
var ep = peInfo.NtHeaders.OptionalHeader.AddressOfEntryPoint;
var epOffset = RvaMapper.RvaToFileOffset(ep, peInfo.Sections, peInfo.NtHeaders.OptionalHeader.SizeOfHeaders);
if (epOffset is null || epOffset.Value >= raw.Length)
{
return instructions;
}
var pos = epOffset.Value;
for (var i = 0; i < instructionCount && pos < raw.Length; i++)
{
var opcode = raw[pos];
if (opcode == 0xC3)
{
instructions.Add(new ParsedInstruction((ulong)pos, new[] { opcode }, "ret", string.Empty));
pos += 1;
continue;
}
if (opcode == 0xE8 && pos + 5 <= raw.Length)
{
var bytes = new byte[5];
Buffer.BlockCopy(raw, pos, bytes, 0, 5);
instructions.Add(new ParsedInstruction((ulong)pos, bytes, "call", "rel32"));
pos += 5;
continue;
}
if (opcode == 0xE9 && pos + 5 <= raw.Length)
{
var bytes = new byte[5];
Buffer.BlockCopy(raw, pos, bytes, 0, 5);
instructions.Add(new ParsedInstruction((ulong)pos, bytes, "jmp", "rel32"));
pos += 5;
continue;
}
instructions.Add(new ParsedInstruction((ulong)pos, new[] { opcode }, "db", $"0x{opcode:X2}"));
pos += 1;
}
return instructions;
}
}