using System.Diagnostics; namespace X86Disassembler.X86; using Handlers; /// /// Decodes x86 instructions from a byte buffer /// public class InstructionDecoder { // The buffer containing the code to decode private readonly byte[] _codeBuffer; // The length of the buffer private readonly int _length; // The current position in the buffer private int _position; // The instruction handler factory private readonly InstructionHandlerFactory _handlerFactory; // Specialized decoders private readonly PrefixDecoder _prefixDecoder; private readonly ModRMDecoder _modRMDecoder; /// /// Initializes a new instance of the InstructionDecoder class /// /// The buffer containing the code to decode /// The length of the buffer public InstructionDecoder(byte[] codeBuffer, int length) { _codeBuffer = codeBuffer; _length = length; _position = 0; // Create specialized decoders _prefixDecoder = new PrefixDecoder(); _modRMDecoder = new ModRMDecoder(codeBuffer, this, length); // Create the instruction handler factory _handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length); } /// /// Decodes an instruction at the current position /// /// The decoded instruction, or null if the decoding failed public Instruction? DecodeInstruction() { if (_position >= _length) { return null; } // Reset prefix flags _prefixDecoder.Reset(); // Save the start position of the instruction int startPosition = _position; // Create a new instruction Instruction instruction = new Instruction { Address = (uint)startPosition, }; // Handle prefixes while (_position < _length) { byte prefix = _codeBuffer[_position]; if (_prefixDecoder.DecodePrefix(prefix)) { _position++; } else { break; } } if (_position >= _length) { // If we reached the end of the buffer while processing prefixes, // create an instruction with just the prefix information if (_prefixDecoder.HasSegmentOverridePrefix()) { instruction.Mnemonic = _prefixDecoder.GetSegmentOverride(); instruction.Operands = ""; // Set the raw bytes int length = _position - startPosition; instruction.RawBytes = new byte[length]; Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length); return instruction; } return null; } // Read the opcode byte opcode = _codeBuffer[_position++]; // Get a handler for the opcode var handler = _handlerFactory.GetHandler(opcode); Debug.WriteLine($"Resolved handler {handler?.GetType().Name}"); bool handlerSuccess = false; // Try to decode with a handler first if (handler != null) { // Store the current segment override state bool hasSegmentOverride = _prefixDecoder.HasSegmentOverridePrefix(); string segmentOverride = _prefixDecoder.GetSegmentOverride(); // Decode the instruction handlerSuccess = handler.Decode(opcode, instruction); // Apply segment override prefix to the operands if needed if (handlerSuccess && hasSegmentOverride) { instruction.Operands = _prefixDecoder.ApplySegmentOverride(instruction.Operands); } } // If no handler is found or decoding fails, create a default instruction if (!handlerSuccess) { instruction.Mnemonic = OpcodeMap.GetMnemonic(opcode); instruction.Operands = "??"; } // Apply REP/REPNE prefix to the mnemonic if needed instruction.Mnemonic = _prefixDecoder.ApplyRepPrefix(instruction.Mnemonic); // Set the raw bytes int bytesLength = _position - startPosition; instruction.RawBytes = new byte[bytesLength]; Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, bytesLength); return instruction; } /// /// Gets the current position in the buffer /// /// The current position public int GetPosition() { return _position; } /// /// Sets the current position in the buffer /// /// The new position public void SetPosition(int position) { _position = position; } /// /// Checks if the operand size prefix is present /// /// True if the operand size prefix is present public bool HasOperandSizePrefix() { return _prefixDecoder.HasOperandSizePrefix(); } /// /// Checks if the address size prefix is present /// /// True if the address size prefix is present public bool HasAddressSizePrefix() { return _prefixDecoder.HasAddressSizePrefix(); } /// /// Checks if a segment override prefix is present /// /// True if a segment override prefix is present public bool HasSegmentOverridePrefix() { return _prefixDecoder.HasSegmentOverridePrefix(); } /// /// Gets the segment override prefix /// /// The segment override prefix, or an empty string if none is present public string GetSegmentOverride() { return _prefixDecoder.GetSegmentOverride(); } /// /// Checks if the LOCK prefix is present /// /// True if the LOCK prefix is present public bool HasLockPrefix() { return _prefixDecoder.HasLockPrefix(); } /// /// Checks if the REP/REPNE prefix is present /// /// True if the REP/REPNE prefix is present public bool HasRepPrefix() { return _prefixDecoder.HasRepPrefix(); } /// /// Checks if the instruction has an operand size override prefix (0x66) /// /// True if the instruction has an operand size override prefix public bool HasOperandSizeOverridePrefix() { return _prefixDecoder.HasOperandSizePrefix(); } /// /// Reads a byte from the buffer and advances the position /// /// The byte read public byte ReadByte() { if (_position >= _length) { return 0; } return _codeBuffer[_position++]; } /// /// Reads a 16-bit value from the buffer and advances the position /// /// The 16-bit value read public ushort ReadUInt16() { if (_position + 1 >= _length) { return 0; } ushort value = (ushort)(_codeBuffer[_position] | (_codeBuffer[_position + 1] << 8)); _position += 2; return value; } /// /// Reads a 32-bit value from the buffer and advances the position /// /// The 32-bit value read public uint ReadUInt32() { if (_position + 3 >= _length) { return 0; } uint value = (uint)(_codeBuffer[_position] | (_codeBuffer[_position + 1] << 8) | (_codeBuffer[_position + 2] << 16) | (_codeBuffer[_position + 3] << 24)); _position += 4; return value; } }