namespace X86Disassembler.X86; using X86Disassembler.X86.Handlers; /// /// Decodes x86 instructions /// public class InstructionDecoder { // Instruction prefix bytes private const byte PREFIX_LOCK = 0xF0; private const byte PREFIX_REPNE = 0xF2; private const byte PREFIX_REP = 0xF3; private const byte PREFIX_CS = 0x2E; private const byte PREFIX_SS = 0x36; private const byte PREFIX_DS = 0x3E; private const byte PREFIX_ES = 0x26; private const byte PREFIX_FS = 0x64; private const byte PREFIX_GS = 0x65; private const byte PREFIX_OPERAND_SIZE = 0x66; private const byte PREFIX_ADDRESS_SIZE = 0x67; // Buffer containing the code to decode private readonly byte[] _codeBuffer; // Current position in the code buffer private int _position; // Length of the buffer private readonly int _length; // List of instruction handlers private readonly List _handlers; /// /// Initializes a new instance of the InstructionDecoder class /// /// The buffer containing the code to decode public InstructionDecoder(byte[] codeBuffer) { _codeBuffer = codeBuffer; _position = 0; _length = codeBuffer.Length; // Initialize the instruction handlers _handlers = new List { new Group1Handler(_codeBuffer, this, _length), new FloatingPointHandler(_codeBuffer, this, _length), new DataTransferHandler(_codeBuffer, this, _length), new ControlFlowHandler(_codeBuffer, this, _length) }; } /// /// Decodes an instruction at the current position in the code buffer /// /// The instruction object to populate /// The number of bytes read public int Decode(Instruction instruction) { // Store the starting position int startPosition = _position; // Check if we've reached the end of the buffer if (_position >= _length) { return 0; } // Handle instruction prefixes bool hasPrefix = true; bool operandSizePrefix = false; bool addressSizePrefix = false; string segmentOverride = string.Empty; while (hasPrefix && _position < _length) { byte prefix = _codeBuffer[_position]; switch (prefix) { case PREFIX_LOCK: case PREFIX_REPNE: case PREFIX_REP: _position++; break; case PREFIX_CS: segmentOverride = "cs"; _position++; break; case PREFIX_SS: segmentOverride = "ss"; _position++; break; case PREFIX_DS: segmentOverride = "ds"; _position++; break; case PREFIX_ES: segmentOverride = "es"; _position++; break; case PREFIX_FS: segmentOverride = "fs"; _position++; break; case PREFIX_GS: segmentOverride = "gs"; _position++; break; case PREFIX_OPERAND_SIZE: operandSizePrefix = true; _position++; break; case PREFIX_ADDRESS_SIZE: addressSizePrefix = true; _position++; break; default: hasPrefix = false; break; } } // We've reached the end of the buffer after processing prefixes if (_position >= _length) { return _position - startPosition; } // Read the opcode byte opcode = _codeBuffer[_position++]; // Try to find a handler for this opcode bool handled = false; foreach (var handler in _handlers) { if (handler.CanHandle(opcode)) { handled = handler.Decode(opcode, instruction); if (handled) { break; } } } // If no handler was found or the instruction couldn't be decoded, // use a default mnemonic from the opcode map if (!handled) { instruction.Mnemonic = OpcodeMap.GetMnemonic(opcode); instruction.Operands = string.Empty; } // Copy the instruction bytes int bytesRead = _position - startPosition; instruction.Bytes = new byte[bytesRead]; Array.Copy(_codeBuffer, startPosition, instruction.Bytes, 0, bytesRead); return bytesRead; } /// /// Sets the current position in the code buffer /// /// The new position public void SetPosition(int position) { _position = position; } /// /// Gets the current position in the code buffer /// /// The current position public int GetPosition() { return _position; } /// /// Decodes an instruction at the specified position in the code buffer /// /// The position in the code buffer /// The instruction object to populate /// The number of bytes read public int DecodeAt(int position, Instruction instruction) { _position = position; return Decode(instruction); } }