2025-04-13 02:18:12 +03:00
|
|
|
namespace X86Disassembler.X86.Handlers.String;
|
|
|
|
|
2025-04-14 22:08:50 +03:00
|
|
|
using X86Disassembler.X86.Operands;
|
|
|
|
|
2025-04-13 02:18:12 +03:00
|
|
|
/// <summary>
|
2025-04-13 02:23:27 +03:00
|
|
|
/// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes
|
2025-04-13 02:18:12 +03:00
|
|
|
/// </summary>
|
|
|
|
public class StringInstructionHandler : InstructionHandler
|
|
|
|
{
|
2025-04-14 22:08:50 +03:00
|
|
|
// Dictionary mapping opcodes to their instruction types and operand factories
|
|
|
|
private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions = new()
|
2025-04-13 02:20:49 +03:00
|
|
|
{
|
2025-04-14 22:08:50 +03:00
|
|
|
{ 0xA4, (InstructionType.MovsB, () => new Operand[] {
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 8, "edi"),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 8, "esi")
|
|
|
|
}) }, // MOVSB
|
|
|
|
{ 0xA5, (InstructionType.MovsD, () => new Operand[] {
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 32, "edi"),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 32, "esi")
|
|
|
|
}) }, // MOVSD
|
|
|
|
{ 0xAA, (InstructionType.StosB, () => new Operand[] {
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 8, "edi"),
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8)
|
|
|
|
}) }, // STOSB
|
|
|
|
{ 0xAB, (InstructionType.StosD, () => new Operand[] {
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 32, "edi"),
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
|
|
|
|
}) }, // STOSD
|
|
|
|
{ 0xAC, (InstructionType.LodsB, () => new Operand[] {
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 8, "esi")
|
|
|
|
}) }, // LODSB
|
|
|
|
{ 0xAD, (InstructionType.LodsD, () => new Operand[] {
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 32, "esi")
|
|
|
|
}) }, // LODSD
|
|
|
|
{ 0xAE, (InstructionType.ScasB, () => new Operand[] {
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 8, "edi")
|
|
|
|
}) }, // SCASB
|
|
|
|
{ 0xAF, (InstructionType.ScasD, () => new Operand[] {
|
|
|
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
|
|
|
|
OperandFactory.CreateDirectMemoryOperand(0, 32, "edi")
|
|
|
|
}) } // SCASD
|
2025-04-13 02:20:49 +03:00
|
|
|
};
|
|
|
|
|
2025-04-13 02:23:27 +03:00
|
|
|
// REP/REPNE prefix opcodes
|
|
|
|
private const byte REP_PREFIX = 0xF3;
|
|
|
|
private const byte REPNE_PREFIX = 0xF2;
|
2025-04-14 22:08:50 +03:00
|
|
|
|
2025-04-13 02:18:12 +03:00
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the StringInstructionHandler class
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
2025-04-14 22:08:50 +03:00
|
|
|
public StringInstructionHandler(InstructionDecoder decoder)
|
|
|
|
: base(decoder)
|
2025-04-13 02:18:12 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Checks if this handler can handle the given opcode
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="opcode">The opcode to check</param>
|
|
|
|
/// <returns>True if this handler can handle the opcode</returns>
|
|
|
|
public override bool CanHandle(byte opcode)
|
|
|
|
{
|
2025-04-13 02:19:19 +03:00
|
|
|
// Check if the opcode is a string instruction
|
2025-04-13 23:24:14 +03:00
|
|
|
if (StringInstructions.ContainsKey(opcode))
|
2025-04-13 02:23:27 +03:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the opcode is a REP/REPNE prefix followed by a string instruction
|
2025-04-14 01:08:14 +03:00
|
|
|
if (opcode != REP_PREFIX && opcode != REPNE_PREFIX)
|
2025-04-13 02:23:27 +03:00
|
|
|
{
|
2025-04-14 01:08:14 +03:00
|
|
|
return false;
|
2025-04-13 02:23:27 +03:00
|
|
|
}
|
|
|
|
|
2025-04-14 01:08:14 +03:00
|
|
|
if (!Decoder.CanReadByte())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-04-14 22:08:50 +03:00
|
|
|
byte nextByte = Decoder.PeakByte();
|
2025-04-14 01:08:14 +03:00
|
|
|
return StringInstructions.ContainsKey(nextByte);
|
2025-04-13 02:18:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Decodes a string instruction
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="opcode">The opcode to decode</param>
|
|
|
|
/// <param name="instruction">The instruction to populate</param>
|
|
|
|
/// <returns>True if the instruction was successfully decoded</returns>
|
|
|
|
public override bool Decode(byte opcode, Instruction instruction)
|
|
|
|
{
|
2025-04-13 02:23:27 +03:00
|
|
|
// Check if this is a REP/REPNE prefix
|
|
|
|
bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX;
|
|
|
|
|
|
|
|
// If this is a REP/REPNE prefix, get the actual string instruction opcode
|
|
|
|
byte stringOpcode = opcode;
|
2025-04-13 23:24:14 +03:00
|
|
|
|
2025-04-13 02:23:27 +03:00
|
|
|
if (hasRepPrefix)
|
|
|
|
{
|
2025-04-13 23:24:14 +03:00
|
|
|
// Read the next byte (the actual string instruction opcode)
|
2025-04-14 01:08:14 +03:00
|
|
|
if (!Decoder.CanReadByte())
|
2025-04-13 02:23:27 +03:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-13 23:06:52 +03:00
|
|
|
stringOpcode = Decoder.ReadByte();
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-13 23:24:14 +03:00
|
|
|
if (!StringInstructions.ContainsKey(stringOpcode))
|
2025-04-13 02:23:27 +03:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-14 22:08:50 +03:00
|
|
|
// Get the instruction type and operands for the string instruction
|
2025-04-13 23:24:14 +03:00
|
|
|
if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo))
|
2025-04-13 02:20:49 +03:00
|
|
|
{
|
2025-04-14 22:08:50 +03:00
|
|
|
// Set the instruction type
|
|
|
|
instruction.Type = instructionInfo.Type;
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-14 22:08:50 +03:00
|
|
|
// Create and set the structured operands
|
|
|
|
instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-13 23:24:14 +03:00
|
|
|
return true;
|
2025-04-13 02:18:12 +03:00
|
|
|
}
|
2025-04-14 01:08:14 +03:00
|
|
|
|
2025-04-13 23:24:14 +03:00
|
|
|
// This shouldn't happen if CanHandle is called first
|
|
|
|
return false;
|
2025-04-13 02:18:12 +03:00
|
|
|
}
|
2025-04-14 01:08:14 +03:00
|
|
|
}
|