diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index a0e2d13..9d69a35 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -149,9 +149,14 @@ public class InstructionHandlerFactory /// private void RegisterJumpHandlers() { - // JMP handlers - _handlers.Add(new JmpRel32Handler(_decoder)); - _handlers.Add(new JmpRel8Handler(_decoder)); + // JMP handlers for relative jumps + _handlers.Add(new JmpRel32Handler(_decoder)); // JMP rel32 (opcode E9) + _handlers.Add(new JmpRel8Handler(_decoder)); // JMP rel8 (opcode EB) + + // JMP handler for register/memory operands + _handlers.Add(new JmpRm32Handler(_decoder)); // JMP r/m32 (opcode FF /4) + + // Conditional jump handlers _handlers.Add(new JgeRel8Handler(_decoder)); _handlers.Add(new ConditionalJumpHandler(_decoder)); _handlers.Add(new TwoByteConditionalJumpHandler(_decoder)); diff --git a/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs b/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs new file mode 100644 index 0000000..0bbaee0 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Jump/JmpRm32Handler.cs @@ -0,0 +1,76 @@ +using X86Disassembler.X86.Operands; + +namespace X86Disassembler.X86.Handlers.Jump; + +/// +/// Handler for JMP r/m32 instruction (opcode FF /4) +/// +public class JmpRm32Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the JmpRm32Handler class + /// + /// The instruction decoder that owns this handler + public JmpRm32Handler(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) + { + // JMP r/m32 is encoded as FF /4 + if (opcode != 0xFF) + { + return false; + } + + // Check if we have enough bytes to read the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Extract the reg field (bits 3-5) + var reg = ModRMDecoder.PeakModRMReg(); + + // JMP r/m32 is encoded as FF /4 (reg field = 4) + return reg == 4; + } + + /// + /// Decodes a JMP r/m32 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.Jmp; + + // Check if we have enough bytes for the ModR/M byte + if (!Decoder.CanReadByte()) + { + return false; + } + + // Read the ModR/M byte + // For JMP r/m32 (FF /4): + // - The r/m field with mod specifies the operand (register or memory) + var (_, _, _, operand) = ModRMDecoder.ReadModRM(); + + // Set the structured operands + // JMP has only one operand + instruction.StructuredOperands = + [ + operand + ]; + + return true; + } +} diff --git a/X86DisassemblerTests/TestData/jmp_tests.csv b/X86DisassemblerTests/TestData/jmp_tests.csv index 2b272ea..ca5f9c1 100644 --- a/X86DisassemblerTests/TestData/jmp_tests.csv +++ b/X86DisassemblerTests/TestData/jmp_tests.csv @@ -41,10 +41,11 @@ FF6610;[{ "Type": "Jmp", "Operands": ["dword ptr [esi+0x10]"] }] FF6710;[{ "Type": "Jmp", "Operands": ["dword ptr [edi+0x10]"] }] # JMP m32 (opcode FF /4) with SIB byte -FF24C5;[{ "Type": "Jmp", "Operands": ["dword ptr [eax*8+ebp]"] }] -FF24CD;[{ "Type": "Jmp", "Operands": ["dword ptr [ecx*8+ebp]"] }] -FF24D5;[{ "Type": "Jmp", "Operands": ["dword ptr [edx*8+ebp]"] }] -FF24DD;[{ "Type": "Jmp", "Operands": ["dword ptr [ebx*8+ebp]"] }] +# not recognized by ghidra or online disasms +# FF24C5;[{ "Type": "Jmp", "Operands": ["dword ptr [eax*8+ebp]"] }] +# FF24CD;[{ "Type": "Jmp", "Operands": ["dword ptr [ecx*8+ebp]"] }] +# FF24D5;[{ "Type": "Jmp", "Operands": ["dword ptr [edx*8+ebp]"] }] +# FF24DD;[{ "Type": "Jmp", "Operands": ["dword ptr [ebx*8+ebp]"] }] # JMP m32 (opcode FF /4) with direct memory operand FF2578563412;[{ "Type": "Jmp", "Operands": ["dword ptr [0x12345678]"] }]