From 410211fcc6beb9532980c52451dd13f3dfeabfb8 Mon Sep 17 00:00:00 2001 From: bird_egop Date: Sun, 13 Apr 2025 02:18:12 +0300 Subject: [PATCH] Converted StringInstructionDecoder to StringInstructionHandler for better consistency with handler pattern --- .../X86/Handlers/InstructionHandlerFactory.cs | 1 + .../String/StringInstructionHandler.cs | 88 +++++++++++++++++ X86Disassembler/X86/InstructionDecoder.cs | 16 --- .../X86/StringInstructionDecoder.cs | 98 ------------------- 4 files changed, 89 insertions(+), 114 deletions(-) create mode 100644 X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs delete mode 100644 X86Disassembler/X86/StringInstructionDecoder.cs diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index 8a30c22..2494279 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -307,6 +307,7 @@ public class InstructionHandlerFactory { // Add String instruction handlers _handlers.Add(new RepMovsHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new StringInstructionHandler(_codeBuffer, _decoder, _length)); } /// diff --git a/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs new file mode 100644 index 0000000..0abe386 --- /dev/null +++ b/X86Disassembler/X86/Handlers/String/StringInstructionHandler.cs @@ -0,0 +1,88 @@ +namespace X86Disassembler.X86.Handlers.String; + +/// +/// Handler for string instructions (MOVS, STOS, LODS, SCAS) +/// +public class StringInstructionHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the StringInstructionHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public StringInstructionHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) + : base(codeBuffer, decoder, length) + { + } + + /// + /// Checks if this handler can handle the given opcode + /// + /// The opcode to check + /// True if this handler can handle the opcode + public override bool CanHandle(byte opcode) + { + return IsStringInstruction(opcode); + } + + /// + /// Decodes a string instruction + /// + /// The opcode to decode + /// The instruction to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the mnemonic + instruction.Mnemonic = OpcodeMap.GetMnemonic(opcode); + + // Set the operands + instruction.Operands = GetStringOperands(opcode); + + return true; + } + + /// + /// Checks if the opcode is a string instruction + /// + /// The opcode to check + /// True if the opcode is a string instruction + private bool IsStringInstruction(byte opcode) + { + return opcode == 0xA4 || opcode == 0xA5 || // MOVS + opcode == 0xAA || opcode == 0xAB || // STOS + opcode == 0xAC || opcode == 0xAD || // LODS + opcode == 0xAE || opcode == 0xAF; // SCAS + } + + /// + /// Gets the operands for a string instruction + /// + /// The string operation opcode + /// The operands string + private string GetStringOperands(byte stringOp) + { + switch (stringOp) + { + case 0xA4: // MOVSB + return "byte ptr [edi], byte ptr [esi]"; + case 0xA5: // MOVSD + return "dword ptr [edi], dword ptr [esi]"; + case 0xAA: // STOSB + return "byte ptr [edi], al"; + case 0xAB: // STOSD + return "dword ptr [edi], eax"; + case 0xAC: // LODSB + return "al, byte ptr [esi]"; + case 0xAD: // LODSD + return "eax, dword ptr [esi]"; + case 0xAE: // SCASB + return "al, byte ptr [edi]"; + case 0xAF: // SCASD + return "eax, dword ptr [edi]"; + default: + return "??"; + } + } +} diff --git a/X86Disassembler/X86/InstructionDecoder.cs b/X86Disassembler/X86/InstructionDecoder.cs index 5af5ddb..d140156 100644 --- a/X86Disassembler/X86/InstructionDecoder.cs +++ b/X86Disassembler/X86/InstructionDecoder.cs @@ -22,7 +22,6 @@ public class InstructionDecoder // Specialized decoders private readonly PrefixDecoder _prefixDecoder; private readonly ModRMDecoder _modRMDecoder; - private readonly StringInstructionDecoder _stringDecoder; /// /// Initializes a new instance of the InstructionDecoder class @@ -38,7 +37,6 @@ public class InstructionDecoder // Create specialized decoders _prefixDecoder = new PrefixDecoder(); _modRMDecoder = new ModRMDecoder(codeBuffer, this, length); - _stringDecoder = new StringInstructionDecoder(codeBuffer, length); // Create the instruction handler factory _handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length); @@ -75,20 +73,6 @@ public class InstructionDecoder if (_prefixDecoder.DecodePrefix(prefix)) { _position++; - - // Special case for REP/REPNE prefix followed by string instruction - if ((prefix == 0xF2 || prefix == 0xF3) && _position < _length) - { - byte nextByte = _codeBuffer[_position]; - if (_stringDecoder.IsStringInstruction(nextByte)) - { - // Skip the string operation opcode - _position++; - - // Handle REP string instruction - return _stringDecoder.CreateStringInstruction(prefix, nextByte, startPosition, _position); - } - } } else { diff --git a/X86Disassembler/X86/StringInstructionDecoder.cs b/X86Disassembler/X86/StringInstructionDecoder.cs deleted file mode 100644 index 7c893d4..0000000 --- a/X86Disassembler/X86/StringInstructionDecoder.cs +++ /dev/null @@ -1,98 +0,0 @@ -namespace X86Disassembler.X86; - -/// -/// Handles decoding of string instructions -/// -public class StringInstructionDecoder -{ - // The buffer containing the code to decode - private readonly byte[] _codeBuffer; - - // The length of the buffer - private readonly int _length; - - /// - /// Initializes a new instance of the StringInstructionDecoder class - /// - /// The buffer containing the code to decode - /// The length of the buffer - public StringInstructionDecoder(byte[] codeBuffer, int length) - { - _codeBuffer = codeBuffer; - _length = length; - } - - /// - /// Checks if the opcode is a string instruction - /// - /// The opcode to check - /// True if the opcode is a string instruction - public bool IsStringInstruction(byte opcode) - { - return opcode == 0xA4 || opcode == 0xA5 || // MOVS - opcode == 0xAA || opcode == 0xAB || // STOS - opcode == 0xAC || opcode == 0xAD || // LODS - opcode == 0xAE || opcode == 0xAF; // SCAS - } - - /// - /// Creates an instruction for a string operation with REP/REPNE prefix - /// - /// The REP/REPNE prefix (0xF2 or 0xF3) - /// The string operation opcode - /// The start position of the instruction - /// The current position after reading the string opcode - /// The created instruction - public Instruction CreateStringInstruction(byte prefix, byte stringOp, int startPosition, int currentPosition) - { - // Create a new instruction - Instruction instruction = new Instruction - { - Address = (uint)startPosition, - }; - - // Get the mnemonic for the string operation - string mnemonic = OpcodeMap.GetMnemonic(stringOp); - instruction.Mnemonic = prefix == 0xF3 ? $"rep {mnemonic}" : $"repne {mnemonic}"; - - // Set operands based on the string operation - instruction.Operands = GetStringOperands(stringOp); - - // Set the raw bytes - int length = currentPosition - startPosition; - instruction.RawBytes = new byte[length]; - Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length); - - return instruction; - } - - /// - /// Gets the operands for a string instruction - /// - /// The string operation opcode - /// The operands string - private string GetStringOperands(byte stringOp) - { - switch (stringOp) - { - case 0xA4: // MOVSB - return "byte ptr [edi], byte ptr [esi]"; - case 0xA5: // MOVSD - return "dword ptr [edi], dword ptr [esi]"; - case 0xAA: // STOSB - return "byte ptr [edi], al"; - case 0xAB: // STOSD - return "dword ptr [edi], eax"; - case 0xAC: // LODSB - return "al, byte ptr [esi]"; - case 0xAD: // LODSD - return "eax, dword ptr [esi]"; - case 0xAE: // SCASB - return "al, byte ptr [edi]"; - case 0xAF: // SCASD - return "eax, dword ptr [edi]"; - default: - return "??"; - } - } -}