diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index 7f345ec..e9c4bc5 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -3,14 +3,15 @@ using X86Disassembler.X86.Handlers.ArithmeticUnary; using X86Disassembler.X86.Handlers.Call; using X86Disassembler.X86.Handlers.FloatingPoint; using X86Disassembler.X86.Handlers.Jump; +using X86Disassembler.X86.Handlers.Lea; using X86Disassembler.X86.Handlers.Mov; using X86Disassembler.X86.Handlers.Or; using X86Disassembler.X86.Handlers.Pop; using X86Disassembler.X86.Handlers.Push; using X86Disassembler.X86.Handlers.Ret; using X86Disassembler.X86.Handlers.Test; -using X86Disassembler.X86.Handlers.Xchg; using X86Disassembler.X86.Handlers.Xor; +using X86Disassembler.X86.Handlers.Xchg; namespace X86Disassembler.X86.Handlers; @@ -69,6 +70,9 @@ public class InstructionHandlerFactory // Register Or handlers RegisterOrHandlers(); + // Register Lea handlers + RegisterLeaHandlers(); + // Register Data Transfer handlers RegisterDataTransferHandlers(); @@ -212,6 +216,15 @@ public class InstructionHandlerFactory _handlers.Add(new OrImmWithRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); } + /// + /// Registers all Lea instruction handlers + /// + private void RegisterLeaHandlers() + { + // Add Lea handlers + _handlers.Add(new LeaR32MHandler(_codeBuffer, _decoder, _length)); + } + /// /// Registers all Data Transfer instruction handlers /// diff --git a/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs b/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs new file mode 100644 index 0000000..5be1a09 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Lea/LeaR32MHandler.cs @@ -0,0 +1,76 @@ +namespace X86Disassembler.X86.Handlers.Lea; + +/// +/// Handler for LEA r32, m instruction (0x8D) +/// +public class LeaR32MHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the LeaR32MHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public LeaR32MHandler(byte[] codeBuffer, InstructionDecoder decoder, int length) + : base(codeBuffer, decoder, length) + { + } + + /// + /// 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) + { + return opcode == 0x8D; + } + + /// + /// Decodes a LEA r32, m 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the ModR/M byte + byte modRM = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Extract the fields from the ModR/M byte + byte mod = (byte)((modRM & 0xC0) >> 6); + byte reg = (byte)((modRM & 0x38) >> 3); + byte rm = (byte)(modRM & 0x07); + + // LEA only works with memory operands, not registers + if (mod == 3) + { + return false; + } + + // Set the mnemonic + instruction.Mnemonic = "lea"; + + // Get the register name + string regName = GetRegister32(reg); + + // Get the memory operand without the size prefix + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + + // Remove the "dword ptr" prefix for LEA instructions + operand = operand.Replace("dword ptr ", ""); + + // Set the operands + instruction.Operands = $"{regName}, {operand}"; + + return true; + } +} diff --git a/X86Disassembler/X86/OpcodeMap.cs b/X86Disassembler/X86/OpcodeMap.cs index 5cd9736..6e72cd9 100644 --- a/X86Disassembler/X86/OpcodeMap.cs +++ b/X86Disassembler/X86/OpcodeMap.cs @@ -47,6 +47,9 @@ public static class OpcodeMap OneByteOpcodes[0x0C] = "or"; // OR AL, imm8 OneByteOpcodes[0x0D] = "or"; // OR EAX, imm32 + // LEA instruction + OneByteOpcodes[0x8D] = "lea"; // LEA r32, m + // Group 1 instructions (ADD, OR, ADC, SBB, AND, SUB, XOR, CMP) OneByteOpcodes[0x80] = "group1b"; OneByteOpcodes[0x81] = "group1d"; diff --git a/X86DisassemblerTests/LeaInstructionTests.cs b/X86DisassemblerTests/LeaInstructionTests.cs new file mode 100644 index 0000000..b46961d --- /dev/null +++ b/X86DisassemblerTests/LeaInstructionTests.cs @@ -0,0 +1,87 @@ +namespace X86DisassemblerTests; + +using System; +using Xunit; +using X86Disassembler.X86; + +/// +/// Tests for LEA instruction handlers +/// +public class LeaInstructionTests +{ + /// + /// Tests the LEA r32, m instruction (0x8D) with simple memory operand + /// + [Fact] + public void TestLeaR32M_Simple() + { + // Arrange + byte[] code = { 0x8D, 0x00 }; // LEA EAX, [EAX] + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("lea", instructions[0].Mnemonic); + Assert.Equal("eax, [eax]", instructions[0].Operands); + } + + /// + /// Tests the LEA r32, m instruction (0x8D) with displacement + /// + [Fact] + public void TestLeaR32M_WithDisplacement() + { + // Arrange + byte[] code = { 0x8D, 0x7E, 0xFC }; // LEA EDI, [ESI - 0x4] + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("lea", instructions[0].Mnemonic); + Assert.Equal("edi, [esi-0x04]", instructions[0].Operands); + } + + /// + /// Tests the LEA r32, m instruction (0x8D) with SIB byte + /// + [Fact] + public void TestLeaR32M_WithSIB() + { + // Arrange + byte[] code = { 0x8D, 0x04, 0x11 }; // LEA EAX, [ECX+EDX] + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("lea", instructions[0].Mnemonic); + Assert.Equal("eax, [ecx+edx]", instructions[0].Operands); + } + + /// + /// Tests the LEA r32, m instruction (0x8D) with complex addressing + /// + [Fact] + public void TestLeaR32M_Complex() + { + // Arrange + byte[] code = { 0x8D, 0x44, 0x8A, 0x10 }; // LEA EAX, [EDX + ECX*4 + 0x10] + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("lea", instructions[0].Mnemonic); + Assert.Equal("eax, [edx+ecx*4+0x10]", instructions[0].Operands); + } +}