diff --git a/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs b/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs new file mode 100644 index 0000000..f29c170 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Add/AddAxImmHandler.cs @@ -0,0 +1,71 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Add; + +/// +/// Handler for ADD AX, imm16 instruction (0x05 with 0x66 prefix) +/// +public class AddAxImmHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the AddAxImmHandler class + /// + /// The instruction decoder that owns this handler + public AddAxImmHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // ADD AX, imm16 is encoded as 0x05 with 0x66 prefix + if (opcode != 0x05) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an ADD AX, imm16 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Add; + + // Check if we have enough bytes for the immediate value + if (!Decoder.CanReadUShort()) + { + return false; + } + + // Read the immediate value + ushort imm16 = Decoder.ReadUInt16(); + + // Create the AX register operand + var axOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16); + + // Create the immediate operand + var immOperand = OperandFactory.CreateImmediateOperand(imm16); + + // Set the structured operands + instruction.StructuredOperands = + [ + axOperand, + immOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs b/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs new file mode 100644 index 0000000..fb005c9 --- /dev/null +++ b/X86Disassembler/X86/Handlers/And/AndAxImmHandler.cs @@ -0,0 +1,71 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.And; + +/// +/// Handler for AND AX, imm16 instruction (0x25 with 0x66 prefix) +/// +public class AndAxImmHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the AndAxImmHandler class + /// + /// The instruction decoder that owns this handler + public AndAxImmHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // AND AX, imm16 is encoded as 0x25 with 0x66 prefix + if (opcode != 0x25) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an AND AX, imm16 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.And; + + // Check if we have enough bytes for the immediate value + if (!Decoder.CanReadUShort()) + { + return false; + } + + // Read the immediate value + ushort imm16 = Decoder.ReadUInt16(); + + // Create the AX register operand + var axOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16); + + // Create the immediate operand + var immOperand = OperandFactory.CreateImmediateOperand(imm16); + + // Set the structured operands + instruction.StructuredOperands = + [ + axOperand, + immOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs b/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs new file mode 100644 index 0000000..d706ac1 --- /dev/null +++ b/X86Disassembler/X86/Handlers/And/AndImmToRm16Handler.cs @@ -0,0 +1,84 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.And; + +/// +/// Handler for AND r/m16, imm16 instruction (0x81 /4 with 0x66 prefix) +/// +public class AndImmToRm16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the AndImmToRm16Handler class + /// + /// The instruction decoder that owns this handler + public AndImmToRm16Handler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // AND r/m16, imm16 is encoded as 0x81 with 0x66 prefix + if (opcode != 0x81) + { + return false; + } + + // Only handle when the operand size prefix is present + if (!Decoder.HasOperandSizePrefix()) + { + return false; + } + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Check if the reg field of the ModR/M byte is 4 (AND) + var reg = ModRMDecoder.PeakModRMReg(); + return reg == 4; // 4 = AND + } + + /// + /// Decodes an AND r/m16, imm16 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.And; + + // Read the ModR/M byte to get the destination operand + var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16(); + + // Check if we have enough bytes for the immediate value + if (!Decoder.CanReadUShort()) + { + return false; + } + + // Read the immediate value + ushort imm16 = Decoder.ReadUInt16(); + + // Create the immediate operand + var sourceOperand = OperandFactory.CreateImmediateOperand(imm16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs b/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs new file mode 100644 index 0000000..84ed642 --- /dev/null +++ b/X86Disassembler/X86/Handlers/And/AndImmToRm16SignExtendedHandler.cs @@ -0,0 +1,86 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.And; + +/// +/// Handler for AND r/m16, imm8 instruction (0x83 /4 with 0x66 prefix) +/// +public class AndImmToRm16SignExtendedHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the AndImmToRm16SignExtendedHandler class + /// + /// The instruction decoder that owns this handler + public AndImmToRm16SignExtendedHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // AND r/m16, imm8 is encoded as 0x83 with 0x66 prefix + if (opcode != 0x83) + { + return false; + } + + // Only handle when the operand size prefix is present + if (!Decoder.HasOperandSizePrefix()) + { + return false; + } + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Check if the reg field of the ModR/M byte is 4 (AND) + var reg = ModRMDecoder.PeakModRMReg(); + return reg == 4; // 4 = AND + } + + /// + /// Decodes an AND r/m16, imm8 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.And; + + // Read the ModR/M byte to get the destination operand + var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16(); + + // Check if we have enough bytes for the immediate value + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the immediate value and sign-extend it to 16 bits + sbyte imm8 = (sbyte)Decoder.ReadByte(); + short signExtendedImm = imm8; + ushort imm16 = (ushort)signExtendedImm; + + // Create the immediate operand + var sourceOperand = OperandFactory.CreateImmediateOperand(imm16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs b/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs new file mode 100644 index 0000000..64bdd42 --- /dev/null +++ b/X86Disassembler/X86/Handlers/And/AndR16Rm16Handler.cs @@ -0,0 +1,70 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.And; + +/// +/// Handler for AND r16, r/m16 instruction (0x23 with 0x66 prefix) +/// +public class AndR16Rm16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the AndR16Rm16Handler class + /// + /// The instruction decoder that owns this handler + public AndR16Rm16Handler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // AND r16, r/m16 is encoded as 0x23 with 0x66 prefix + if (opcode != 0x23) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an AND r16, r/m16 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.And; + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // For AND r16, r/m16 (0x23 with 0x66 prefix): + // - The reg field of the ModR/M byte specifies the destination register + // - The r/m field with mod specifies the source operand (register or memory) + var (_, reg, _, sourceOperand) = ModRMDecoder.ReadModRM16(); + + // Create the destination register operand with 16-bit size + var destinationOperand = OperandFactory.CreateRegisterOperand(reg, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/And/AndRm16R16Handler.cs b/X86Disassembler/X86/Handlers/And/AndRm16R16Handler.cs new file mode 100644 index 0000000..dcdfe86 --- /dev/null +++ b/X86Disassembler/X86/Handlers/And/AndRm16R16Handler.cs @@ -0,0 +1,70 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.And; + +/// +/// Handler for AND r/m16, r16 instruction (0x21 with 0x66 prefix) +/// +public class AndRm16R16Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the AndRm16R16Handler class + /// + /// The instruction decoder that owns this handler + public AndRm16R16Handler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // AND r/m16, r16 is encoded as 0x21 with 0x66 prefix + if (opcode != 0x21) + { + return false; + } + + // Only handle when the operand size prefix is present + return Decoder.HasOperandSizePrefix(); + } + + /// + /// Decodes an AND r/m16, r16 instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.And; + + // Check if we can read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // For AND r/m16, r16 (0x21 with 0x66 prefix): + // - The reg field of the ModR/M byte specifies the source register + // - The r/m field with mod specifies the destination operand (register or memory) + var (_, reg, _, destinationOperand) = ModRMDecoder.ReadModRM16(); + + // Create the source register operand with 16-bit size + var sourceOperand = OperandFactory.CreateRegisterOperand(reg, 16); + + // Set the structured operands + instruction.StructuredOperands = + [ + destinationOperand, + sourceOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index f46b081..8990779 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -12,6 +12,7 @@ using X86Disassembler.X86.Handlers.Imul; using X86Disassembler.X86.Handlers.Inc; using X86Disassembler.X86.Handlers.Jump; using X86Disassembler.X86.Handlers.Lea; +using X86Disassembler.X86.Handlers.Misc; using X86Disassembler.X86.Handlers.Mov; using X86Disassembler.X86.Handlers.Mul; using X86Disassembler.X86.Handlers.Neg; @@ -36,21 +37,15 @@ namespace X86Disassembler.X86.Handlers; public class InstructionHandlerFactory { private readonly List _handlers = []; - private readonly byte[] _codeBuffer; private readonly InstructionDecoder _decoder; - private readonly int _length; /// /// Initializes a new instance of the InstructionHandlerFactory class /// - /// The buffer containing the code to decode /// The instruction decoder that owns this factory - /// The length of the buffer - public InstructionHandlerFactory(byte[] codeBuffer, InstructionDecoder decoder, int length) + public InstructionHandlerFactory(InstructionDecoder decoder) { - _codeBuffer = codeBuffer; _decoder = decoder; - _length = length; RegisterAllHandlers(); } @@ -61,7 +56,7 @@ public class InstructionHandlerFactory private void RegisterAllHandlers() { // Register specific instruction handlers - _handlers.Add(new Int3Handler(_decoder)); + _handlers.Add(new Nop.Int3Handler(_decoder)); // Register handlers in order of priority (most specific first) RegisterSbbHandlers(); // SBB instructions @@ -95,7 +90,7 @@ public class InstructionHandlerFactory RegisterSubHandlers(); // Register SUB handlers RegisterNopHandlers(); // Register NOP handlers RegisterBitHandlers(); // Register bit manipulation handlers - RegisterAndHandlers(); // Register AND handlers + RegisterMiscHandlers(); // Register miscellaneous instructions } /// @@ -471,11 +466,29 @@ public class InstructionHandlerFactory private void RegisterNopHandlers() { // Register NOP handlers - _handlers.Add(new NopHandler(_decoder)); // NOP (opcode 0x90) + _handlers.Add(new Nop.NopHandler(_decoder)); // NOP (opcode 0x90) _handlers.Add(new TwoByteNopHandler(_decoder)); // 2-byte NOP (opcode 0x66 0x90) _handlers.Add(new MultiByteNopHandler(_decoder)); // Multi-byte NOP (opcode 0F 1F /0) } + /// + /// Registers all miscellaneous instruction handlers + /// + private void RegisterMiscHandlers() + { + // Register miscellaneous instruction handlers + _handlers.Add(new IntHandler(_decoder)); // INT (opcode 0xCD) + _handlers.Add(new IntoHandler(_decoder)); // INTO (opcode 0xCE) + _handlers.Add(new IretHandler(_decoder)); // IRET (opcode 0xCF) + _handlers.Add(new CpuidHandler(_decoder)); // CPUID (opcode 0x0F 0xA2) + _handlers.Add(new RdtscHandler(_decoder)); // RDTSC (opcode 0x0F 0x31) + _handlers.Add(new HltHandler(_decoder)); // HLT (opcode 0xF4) + _handlers.Add(new WaitHandler(_decoder)); // WAIT (opcode 0x9B) + _handlers.Add(new LockHandler(_decoder)); // LOCK (opcode 0xF0) + _handlers.Add(new InHandler(_decoder)); // IN (opcodes 0xE4, 0xE5, 0xEC, 0xED) + _handlers.Add(new OutHandler(_decoder)); // OUT (opcodes 0xE6, 0xE7, 0xEE, 0xEF) + } + /// /// Registers all bit manipulation instruction handlers /// diff --git a/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs b/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs new file mode 100644 index 0000000..df9cd51 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/CpuidHandler.cs @@ -0,0 +1,59 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for CPUID instruction (0x0F 0xA2) +/// +public class CpuidHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the CpuidHandler class + /// + /// The instruction decoder that owns this handler + public CpuidHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // CPUID is encoded as 0x0F 0xA2 + if (opcode != 0x0F) + return false; + + // Check if we can read the second byte + if (!Decoder.CanReadByte()) + return false; + + // Check if the second byte is 0xA2 + byte secondByte = Decoder.PeakByte(); + return secondByte == 0xA2; + } + + /// + /// Decodes a CPUID instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Cpuid; + + // Read and discard the second byte (0xA2) + if (!Decoder.CanReadByte()) + return false; + + Decoder.ReadByte(); + + // CPUID has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/HltHandler.cs b/X86Disassembler/X86/Handlers/Misc/HltHandler.cs new file mode 100644 index 0000000..0590427 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/HltHandler.cs @@ -0,0 +1,44 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for HLT instruction (0xF4) +/// +public class HltHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the HltHandler class + /// + /// The instruction decoder that owns this handler + public HltHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // HLT is encoded as 0xF4 + return opcode == 0xF4; + } + + /// + /// Decodes a HLT instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Hlt; + + // HLT has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/InHandler.cs b/X86Disassembler/X86/Handlers/Misc/InHandler.cs new file mode 100644 index 0000000..34970fe --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/InHandler.cs @@ -0,0 +1,97 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for IN instruction (0xE4, 0xE5, 0xEC, 0xED) +/// +public class InHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the InHandler class + /// + /// The instruction decoder that owns this handler + public InHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // IN AL, imm8 is encoded as 0xE4 + // IN EAX, imm8 is encoded as 0xE5 + // IN AL, DX is encoded as 0xEC + // IN EAX, DX is encoded as 0xED + return opcode == 0xE4 || opcode == 0xE5 || opcode == 0xEC || opcode == 0xED; + } + + /// + /// Decodes an IN instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.In; + + // Determine the operands based on the opcode + Operand destOperand; + Operand srcOperand; + + switch (opcode) + { + case 0xE4: // IN AL, imm8 + destOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL); + + // Check if we can read the immediate byte + if (!Decoder.CanReadByte()) + return false; + + // Read the immediate byte (port number) + byte imm8 = Decoder.ReadByte(); + srcOperand = OperandFactory.CreateImmediateOperand(imm8); + break; + + case 0xE5: // IN EAX, imm8 + destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32); + + // Check if we can read the immediate byte + if (!Decoder.CanReadByte()) + return false; + + // Read the immediate byte (port number) + imm8 = Decoder.ReadByte(); + srcOperand = OperandFactory.CreateImmediateOperand(imm8); + break; + + case 0xEC: // IN AL, DX + destOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL); + srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16); + break; + + case 0xED: // IN EAX, DX + destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32); + srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16); + break; + + default: + return false; + } + + // Set the structured operands + instruction.StructuredOperands = + [ + destOperand, + srcOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/IntHandler.cs b/X86Disassembler/X86/Handlers/Misc/IntHandler.cs new file mode 100644 index 0000000..a5e4ee6 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/IntHandler.cs @@ -0,0 +1,61 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +using X86Disassembler.X86.Operands; + +/// +/// Handler for INT instruction (0xCD) +/// +public class IntHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the IntHandler class + /// + /// The instruction decoder that owns this handler + public IntHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // INT is encoded as 0xCD + return opcode == 0xCD; + } + + /// + /// Decodes an INT instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Int; + + // Check if we can read the immediate byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the immediate byte (interrupt vector) + byte imm8 = Decoder.ReadByte(); + + // Create an immediate operand for the interrupt vector + var operand = OperandFactory.CreateImmediateOperand(imm8); + + // Set the structured operands + instruction.StructuredOperands = + [ + operand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs b/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs new file mode 100644 index 0000000..7a1a252 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/IntoHandler.cs @@ -0,0 +1,44 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for INTO instruction (0xCE) +/// +public class IntoHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the IntoHandler class + /// + /// The instruction decoder that owns this handler + public IntoHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // INTO is encoded as 0xCE + return opcode == 0xCE; + } + + /// + /// Decodes an INTO instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Into; + + // INTO has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/IretHandler.cs b/X86Disassembler/X86/Handlers/Misc/IretHandler.cs new file mode 100644 index 0000000..ad7e4c6 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/IretHandler.cs @@ -0,0 +1,44 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for IRET/IRETD instruction (0xCF) +/// +public class IretHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the IretHandler class + /// + /// The instruction decoder that owns this handler + public IretHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // IRET/IRETD is encoded as 0xCF + return opcode == 0xCF; + } + + /// + /// Decodes an IRET/IRETD instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Iret; + + // IRET/IRETD has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/LockHandler.cs b/X86Disassembler/X86/Handlers/Misc/LockHandler.cs new file mode 100644 index 0000000..3d13645 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/LockHandler.cs @@ -0,0 +1,44 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for LOCK prefix (0xF0) +/// +public class LockHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the LockHandler class + /// + /// The instruction decoder that owns this handler + public LockHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // LOCK prefix is encoded as 0xF0 + return opcode == 0xF0; + } + + /// + /// Decodes a LOCK prefix + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Lock; + + // LOCK prefix has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/OutHandler.cs b/X86Disassembler/X86/Handlers/Misc/OutHandler.cs new file mode 100644 index 0000000..97d6f39 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/OutHandler.cs @@ -0,0 +1,95 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for OUT instruction (0xE6, 0xE7, 0xEE, 0xEF) +/// +public class OutHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the OutHandler class + /// + /// The instruction decoder that owns this handler + public OutHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // OUT imm8, AL is encoded as 0xE6 + // OUT imm8, EAX is encoded as 0xE7 + // OUT DX, AL is encoded as 0xEE + // OUT DX, EAX is encoded as 0xEF + return opcode == 0xE6 || opcode == 0xE7 || opcode == 0xEE || opcode == 0xEF; + } + + /// + /// Decodes an OUT instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Out; + + // Determine the operands based on the opcode + Operand destOperand; + Operand srcOperand; + + switch (opcode) + { + case 0xE6: // OUT imm8, AL + // Check if we can read the immediate byte + if (!Decoder.CanReadByte()) + return false; + + // Read the immediate byte (port number) + byte imm8 = Decoder.ReadByte(); + destOperand = OperandFactory.CreateImmediateOperand(imm8); + srcOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL); + break; + + case 0xE7: // OUT imm8, EAX + // Check if we can read the immediate byte + if (!Decoder.CanReadByte()) + return false; + + // Read the immediate byte (port number) + imm8 = Decoder.ReadByte(); + destOperand = OperandFactory.CreateImmediateOperand(imm8); + srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32); + break; + + case 0xEE: // OUT DX, AL + destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16); + srcOperand = OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL); + break; + + case 0xEF: // OUT DX, EAX + destOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.D, 16); + srcOperand = OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32); + break; + + default: + return false; + } + + // Set the structured operands + instruction.StructuredOperands = + [ + destOperand, + srcOperand + ]; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs b/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs new file mode 100644 index 0000000..daa08a0 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/RdtscHandler.cs @@ -0,0 +1,59 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for RDTSC instruction (0x0F 0x31) +/// +public class RdtscHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the RdtscHandler class + /// + /// The instruction decoder that owns this handler + public RdtscHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // RDTSC is encoded as 0x0F 0x31 + if (opcode != 0x0F) + return false; + + // Check if we can read the second byte + if (!Decoder.CanReadByte()) + return false; + + // Check if the second byte is 0x31 + byte secondByte = Decoder.PeakByte(); + return secondByte == 0x31; + } + + /// + /// Decodes a RDTSC instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Rdtsc; + + // Read and discard the second byte (0x31) + if (!Decoder.CanReadByte()) + return false; + + Decoder.ReadByte(); + + // RDTSC has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs b/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs new file mode 100644 index 0000000..7ae2d51 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Misc/WaitHandler.cs @@ -0,0 +1,44 @@ +namespace X86Disassembler.X86.Handlers.Misc; + +/// +/// Handler for WAIT/FWAIT instruction (0x9B) +/// +public class WaitHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the WaitHandler class + /// + /// The instruction decoder that owns this handler + public WaitHandler(InstructionDecoder decoder) + : base(decoder) + { + } + + /// + /// Checks if this handler can decode the given opcode + /// + /// The opcode to check + /// True if this handler can decode the opcode + public override bool CanHandle(byte opcode) + { + // WAIT/FWAIT is encoded as 0x9B + return opcode == 0x9B; + } + + /// + /// Decodes a WAIT/FWAIT instruction + /// + /// The opcode of the instruction + /// The instruction object to populate + /// True if the instruction was successfully decoded + public override bool Decode(byte opcode, Instruction instruction) + { + // Set the instruction type + instruction.Type = InstructionType.Wait; + + // WAIT/FWAIT has no operands + instruction.StructuredOperands = []; + + return true; + } +} diff --git a/X86Disassembler/X86/InstructionDecoder.cs b/X86Disassembler/X86/InstructionDecoder.cs index 3affd5a..22be9cb 100644 --- a/X86Disassembler/X86/InstructionDecoder.cs +++ b/X86Disassembler/X86/InstructionDecoder.cs @@ -45,7 +45,7 @@ public class InstructionDecoder _prefixDecoder = new PrefixDecoder(); // Create the instruction handler factory - _handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length); + _handlerFactory = new InstructionHandlerFactory(this); } /// @@ -131,15 +131,6 @@ public class InstructionDecoder } } } - - // For MOV instructions with segment override prefixes in tests, skip the remaining bytes - // This is a special case handling for the segment override tests - if (handlerSuccess && hasSegmentOverride && instruction.Type == InstructionType.Mov) - { - // Skip to the end of the buffer for MOV instructions with segment override prefixes - // This is needed for the segment override tests - _position = _length; - } } else { @@ -159,16 +150,24 @@ public class InstructionDecoder if (_prefixDecoder.HasRepPrefix()) { // Map instruction types with REP prefix to specific REP-prefixed instruction types + // Note: REP and REPE are the same prefix (0xF3) instruction.Type = instruction.Type switch { InstructionType.MovsB => InstructionType.RepMovsB, + InstructionType.MovsW => InstructionType.RepMovsW, InstructionType.MovsD => InstructionType.RepMovsD, InstructionType.StosB => InstructionType.RepStosB, + InstructionType.StosW => InstructionType.RepStosW, InstructionType.StosD => InstructionType.RepStosD, InstructionType.LodsB => InstructionType.RepLodsB, + InstructionType.LodsW => InstructionType.RepLodsW, InstructionType.LodsD => InstructionType.RepLodsD, InstructionType.ScasB => InstructionType.RepScasB, + InstructionType.ScasW => InstructionType.RepScasW, InstructionType.ScasD => InstructionType.RepScasD, + InstructionType.CmpsB => InstructionType.RepeCmpsB, + InstructionType.CmpsW => InstructionType.RepeCmpsW, + InstructionType.CmpsD => InstructionType.RepeCmpsD, _ => instruction.Type // Keep original type for other instructions }; } @@ -177,8 +176,15 @@ public class InstructionDecoder // Map instruction types with REPNE prefix to specific REPNE-prefixed instruction types instruction.Type = instruction.Type switch { + InstructionType.StosB => InstructionType.RepneStosB, + InstructionType.StosW => InstructionType.RepneStosW, + InstructionType.StosD => InstructionType.RepneStosD, InstructionType.ScasB => InstructionType.RepneScasB, + InstructionType.ScasW => InstructionType.RepneScasW, InstructionType.ScasD => InstructionType.RepneScasD, + InstructionType.CmpsB => InstructionType.RepneCmpsB, + InstructionType.CmpsW => InstructionType.RepneCmpsW, + InstructionType.CmpsD => InstructionType.RepneCmpsD, _ => instruction.Type // Keep original type for other instructions }; } diff --git a/X86Disassembler/X86/PrefixDecoder.cs b/X86Disassembler/X86/PrefixDecoder.cs index 7b5da9b..14ed32b 100644 --- a/X86Disassembler/X86/PrefixDecoder.cs +++ b/X86Disassembler/X86/PrefixDecoder.cs @@ -148,43 +148,4 @@ public class PrefixDecoder { return _repnePrefix; } - - /// - /// Applies the segment override prefix to the operands string if applicable - /// - /// The operands string - /// The operands string with segment override applied - public string ApplySegmentOverride(string operands) - { - if (_segmentOverridePrefix && !string.IsNullOrEmpty(operands)) - { - // If the instruction has memory operands, add the segment override - if (operands.Contains("[")) - { - // Replace the first '[' with the segment override - return operands.Replace("[", $"{_segmentOverride}:[" ); - } - } - - return operands; - } - - /// - /// Applies the REP/REPNE prefix to the mnemonic if applicable - /// - /// The mnemonic - /// The mnemonic with REP/REPNE prefix applied - public string ApplyRepPrefix(string mnemonic) - { - if (_repnePrefix && !mnemonic.StartsWith("repne")) - { - return $"repne {mnemonic}"; - } - else if (_repPrefix && !mnemonic.StartsWith("rep")) - { - return $"rep {mnemonic}"; - } - - return mnemonic; - } } diff --git a/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs b/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs index 6ed748d..3426f78 100644 --- a/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs +++ b/X86DisassemblerTests/InstructionTests/DebugHandlerRegistration.cs @@ -27,7 +27,7 @@ public class DebugHandlerRegistration // Create a factory byte[] codeBuffer = new byte[1]; var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - var sut = new InstructionHandlerFactory(codeBuffer, decoder, codeBuffer.Length); + var sut = new InstructionHandlerFactory(decoder); // Get the handlers registered in the factory var handlers = (List)sut.GetType() diff --git a/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs b/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs index 2472b80..f87fec3 100644 --- a/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs +++ b/X86DisassemblerTests/InstructionTests/HandlerSelectionTests.cs @@ -18,7 +18,7 @@ public class HandlerSelectionTests // Arrange byte[] codeBuffer = new byte[] {0x83, 0xC1, 0x04}; // ADD ecx, 0x04 var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); - var factory = new InstructionHandlerFactory(codeBuffer, decoder, codeBuffer.Length); + var factory = new InstructionHandlerFactory(decoder); // Act var handler = factory.GetHandler(0x83); diff --git a/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs b/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs index 5d3d51e..350fe3e 100644 --- a/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs +++ b/X86DisassemblerTests/InstructionTests/InstructionHandlerFactoryTests.cs @@ -10,7 +10,7 @@ public class InstructionHandlerFactoryTests public void Factory_ShouldNotContainDuplicates() { byte[] code = new byte[] {0xCC, 0xCC, 0xCC}; - var sut = new InstructionHandlerFactory(code, new InstructionDecoder(code, code.Length), code.Length); + var sut = new InstructionHandlerFactory(new InstructionDecoder(code, code.Length)); var handlers = (List) sut.GetType() .GetField("_handlers", BindingFlags.Instance | BindingFlags.NonPublic)! @@ -26,7 +26,7 @@ public class InstructionHandlerFactoryTests public void Factory_ShouldContainAllKnownHandlers() { byte[] code = new byte[] {0xCC, 0xCC, 0xCC}; - var sut = new InstructionHandlerFactory(code, new InstructionDecoder(code, code.Length), code.Length); + var sut = new InstructionHandlerFactory(new InstructionDecoder(code, code.Length)); var handlers = (List) sut.GetType() .GetField("_handlers", BindingFlags.Instance | BindingFlags.NonPublic)!