diff --git a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs index fca6e3f..bf04948 100644 --- a/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs +++ b/X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs @@ -206,6 +206,11 @@ public class InstructionHandlerFactory { // Add Or handlers _handlers.Add(new OrR8Rm8Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrR32Rm32Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrAlImmHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrEaxImmHandler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrImmWithRm32Handler(_codeBuffer, _decoder, _length)); + _handlers.Add(new OrImmWithRm32SignExtendedHandler(_codeBuffer, _decoder, _length)); } /// diff --git a/X86Disassembler/X86/Handlers/Or/OrAlImmHandler.cs b/X86Disassembler/X86/Handlers/Or/OrAlImmHandler.cs new file mode 100644 index 0000000..af2b790 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrAlImmHandler.cs @@ -0,0 +1,56 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR AL, imm8 instruction (0x0C) +/// +public class OrAlImmHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the OrAlImmHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrAlImmHandler(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 == 0x0C; + } + + /// + /// Decodes an OR AL, 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) + { + int position = Decoder.GetPosition(); + + if (position >= Length) + { + return false; + } + + // Read the immediate byte + byte imm8 = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Set the mnemonic + instruction.Mnemonic = "or"; + + // Set the operands + instruction.Operands = $"al, 0x{imm8:X2}"; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Or/OrEaxImmHandler.cs b/X86Disassembler/X86/Handlers/Or/OrEaxImmHandler.cs new file mode 100644 index 0000000..a4c40ec --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrEaxImmHandler.cs @@ -0,0 +1,60 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR EAX, imm32 instruction (0x0D) +/// +public class OrEaxImmHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the OrEaxImmHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrEaxImmHandler(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 == 0x0D; + } + + /// + /// Decodes an OR EAX, imm32 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 + 3 >= Length) + { + return false; + } + + // Read the immediate dword (little-endian) + byte b0 = CodeBuffer[position++]; + byte b1 = CodeBuffer[position++]; + byte b2 = CodeBuffer[position++]; + byte b3 = CodeBuffer[position++]; + uint imm32 = (uint)(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); + Decoder.SetPosition(position); + + // Set the mnemonic + instruction.Mnemonic = "or"; + + // Set the operands + instruction.Operands = $"eax, 0x{imm32:X8}"; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Or/OrImmWithRm32Handler.cs b/X86Disassembler/X86/Handlers/Or/OrImmWithRm32Handler.cs new file mode 100644 index 0000000..85abeb2 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrImmWithRm32Handler.cs @@ -0,0 +1,115 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR r/m32, imm32 instruction (0x81 /1) +/// +public class OrImmWithRm32Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the OrImmWithRm32Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrImmWithRm32Handler(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 == 0x81; + } + + /// + /// Decodes an OR r/m32, imm32 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++]; + + // 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); + + // Check if this is an OR instruction (reg field = 1) + if (reg != 1) + { + return false; + } + + // Process SIB and displacement bytes if needed + if (mod != 3 && rm == 4) // SIB byte present + { + if (position >= Length) + { + return false; + } + position++; // Skip SIB byte + } + + // Handle displacement + if ((mod == 1 && position >= Length) || (mod == 2 && position + 3 >= Length)) + { + return false; + } + + if (mod == 1) // 8-bit displacement + { + position++; + } + else if (mod == 2) // 32-bit displacement + { + position += 4; + } + + // Read the immediate dword + if (position + 3 >= Length) + { + return false; + } + + byte b0 = CodeBuffer[position++]; + byte b1 = CodeBuffer[position++]; + byte b2 = CodeBuffer[position++]; + byte b3 = CodeBuffer[position++]; + uint imm32 = (uint)(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); + Decoder.SetPosition(position); + + // Set the mnemonic + instruction.Mnemonic = "or"; + + // Get the operand string + string operand; + if (mod != 3) // Memory operand + { + operand = ModRMDecoder.DecodeModRM(mod, rm, false); + } + else // Register operand + { + operand = GetRegister32(rm); + } + + // Set the operands + instruction.Operands = $"{operand}, 0x{imm32:X8}"; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Or/OrImmWithRm32SignExtendedHandler.cs b/X86Disassembler/X86/Handlers/Or/OrImmWithRm32SignExtendedHandler.cs new file mode 100644 index 0000000..5f07ac4 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrImmWithRm32SignExtendedHandler.cs @@ -0,0 +1,111 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR r/m32, imm8 sign-extended instruction (0x83 /1) +/// +public class OrImmWithRm32SignExtendedHandler : InstructionHandler +{ + /// + /// Initializes a new instance of the OrImmWithRm32SignExtendedHandler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrImmWithRm32SignExtendedHandler(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 == 0x83; + } + + /// + /// Decodes an OR r/m32, imm8 sign-extended 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++]; + + // 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); + + // Check if this is an OR instruction (reg field = 1) + if (reg != 1) + { + return false; + } + + // Process SIB and displacement bytes if needed + if (mod != 3 && rm == 4) // SIB byte present + { + if (position >= Length) + { + return false; + } + position++; // Skip SIB byte + } + + // Handle displacement + if ((mod == 1 && position >= Length) || (mod == 2 && position + 3 >= Length)) + { + return false; + } + + if (mod == 1) // 8-bit displacement + { + position++; + } + else if (mod == 2) // 32-bit displacement + { + position += 4; + } + + // Read the immediate byte + if (position >= Length) + { + return false; + } + + byte imm8 = CodeBuffer[position++]; + Decoder.SetPosition(position); + + // Set the mnemonic + instruction.Mnemonic = "or"; + + // Get the operand string + string operand; + if (mod != 3) // Memory operand + { + operand = ModRMDecoder.DecodeModRM(mod, rm, false); + } + else // Register operand + { + operand = GetRegister32(rm); + } + + // Set the operands + instruction.Operands = $"{operand}, {imm8}"; + + return true; + } +} diff --git a/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs b/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs new file mode 100644 index 0000000..28bd853 --- /dev/null +++ b/X86Disassembler/X86/Handlers/Or/OrR32Rm32Handler.cs @@ -0,0 +1,73 @@ +namespace X86Disassembler.X86.Handlers.Or; + +/// +/// Handler for OR r32, r/m32 instruction (0x0B) +/// +public class OrR32Rm32Handler : InstructionHandler +{ + /// + /// Initializes a new instance of the OrR32Rm32Handler class + /// + /// The buffer containing the code to decode + /// The instruction decoder that owns this handler + /// The length of the buffer + public OrR32Rm32Handler(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 == 0x0B; + } + + /// + /// Decodes an OR r32, 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) + { + 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); + + // Set the mnemonic + instruction.Mnemonic = "or"; + + // Get the register name + string regName = GetRegister32(reg); + + // For memory operands, set the operand + if (mod != 3) // Memory operand + { + string operand = ModRMDecoder.DecodeModRM(mod, rm, false); + instruction.Operands = $"{regName}, {operand}"; + } + else // Register operand + { + string rmName = GetRegister32(rm); + instruction.Operands = $"{regName}, {rmName}"; + } + + return true; + } +} diff --git a/X86DisassemblerTests/OrInstructionTests.cs b/X86DisassemblerTests/OrInstructionTests.cs index 887e05f..014c034 100644 --- a/X86DisassemblerTests/OrInstructionTests.cs +++ b/X86DisassemblerTests/OrInstructionTests.cs @@ -46,4 +46,118 @@ public class OrInstructionTests Assert.Equal("or", instructions[0].Mnemonic); Assert.Equal("al, byte ptr [eax]", instructions[0].Operands); } + + /// + /// Tests the OR r32, r/m32 instruction (0x0B) + /// + [Fact] + public void TestOrR32Rm32() + { + // Arrange + byte[] code = { 0x0B, 0xC8 }; // OR ECX, EAX + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("ecx, eax", instructions[0].Operands); + } + + /// + /// Tests the OR r32, m32 instruction (0x0B) with memory operand + /// + [Fact] + public void TestOrR32M32() + { + // Arrange + byte[] code = { 0x0B, 0x00 }; // OR EAX, DWORD PTR [EAX] + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("eax, dword ptr [eax]", instructions[0].Operands); + } + + /// + /// Tests the OR AL, imm8 instruction (0x0C) + /// + [Fact] + public void TestOrAlImm8() + { + // Arrange + byte[] code = { 0x0C, 0x42 }; // OR AL, 0x42 + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("al, 0x42", instructions[0].Operands); + } + + /// + /// Tests the OR EAX, imm32 instruction (0x0D) + /// + [Fact] + public void TestOrEaxImm32() + { + // Arrange + byte[] code = { 0x0D, 0x78, 0x56, 0x34, 0x12 }; // OR EAX, 0x12345678 + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("eax, 0x12345678", instructions[0].Operands); + } + + /// + /// Tests the OR r/m32, imm32 instruction (0x81 /1) + /// + [Fact] + public void TestOrRm32Imm32() + { + // Arrange + byte[] code = { 0x81, 0xC8, 0x78, 0x56, 0x34, 0x12 }; // OR EAX, 0x12345678 + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("eax, 0x12345678", instructions[0].Operands); + } + + /// + /// Tests the OR r/m32, imm8 sign-extended instruction (0x83 /1) + /// + [Fact] + public void TestOrRm32Imm8SignExtended() + { + // Arrange + byte[] code = { 0x83, 0xC8, 0x42 }; // OR EAX, 0x42 + + // Act + Disassembler disassembler = new Disassembler(code, 0x1000); + var instructions = disassembler.Disassemble(); + + // Assert + Assert.Single(instructions); + Assert.Equal("or", instructions[0].Mnemonic); + Assert.Equal("eax, 0x00000042", instructions[0].Operands); + } }