From d0667950f8981d644cdeed7e64e301890dcc9f82 Mon Sep 17 00:00:00 2001 From: bird_egop Date: Sun, 13 Apr 2025 02:26:49 +0300 Subject: [PATCH] Added proper REPNE prefix handling and comprehensive string instruction tests --- X86Disassembler/X86/PrefixDecoder.cs | 32 +++++- .../StringInstructionHandlerTests.cs | 104 +++++++++++++++++- 2 files changed, 128 insertions(+), 8 deletions(-) diff --git a/X86Disassembler/X86/PrefixDecoder.cs b/X86Disassembler/X86/PrefixDecoder.cs index 39f7c8b..7b5da9b 100644 --- a/X86Disassembler/X86/PrefixDecoder.cs +++ b/X86Disassembler/X86/PrefixDecoder.cs @@ -11,6 +11,7 @@ public class PrefixDecoder private bool _segmentOverridePrefix; private bool _lockPrefix; private bool _repPrefix; + private bool _repnePrefix; private string _segmentOverride = string.Empty; /// @@ -31,6 +32,7 @@ public class PrefixDecoder _segmentOverridePrefix = false; _lockPrefix = false; _repPrefix = false; + _repnePrefix = false; _segmentOverride = string.Empty; } @@ -70,11 +72,16 @@ public class PrefixDecoder _lockPrefix = true; return true; } - else if (prefix == 0xF2 || prefix == 0xF3) // REP/REPNE prefix + else if (prefix == 0xF3) // REP prefix { _repPrefix = true; return true; } + else if (prefix == 0xF2) // REPNE prefix + { + _repnePrefix = true; + return true; + } return false; } @@ -125,14 +132,23 @@ public class PrefixDecoder } /// - /// Checks if the REP/REPNE prefix is present + /// Checks if the REP prefix is present /// - /// True if the REP/REPNE prefix is present + /// True if the REP prefix is present public bool HasRepPrefix() { return _repPrefix; } + /// + /// Checks if the REPNE prefix is present + /// + /// True if the REPNE prefix is present + public bool HasRepnePrefix() + { + return _repnePrefix; + } + /// /// Applies the segment override prefix to the operands string if applicable /// @@ -154,13 +170,17 @@ public class PrefixDecoder } /// - /// Applies the REP prefix to the mnemonic if applicable + /// Applies the REP/REPNE prefix to the mnemonic if applicable /// /// The mnemonic - /// The mnemonic with REP prefix applied + /// The mnemonic with REP/REPNE prefix applied public string ApplyRepPrefix(string mnemonic) { - if (_repPrefix && !mnemonic.StartsWith("rep")) + if (_repnePrefix && !mnemonic.StartsWith("repne")) + { + return $"repne {mnemonic}"; + } + else if (_repPrefix && !mnemonic.StartsWith("rep")) { return $"rep {mnemonic}"; } diff --git a/X86DisassemblerTests/StringInstructionHandlerTests.cs b/X86DisassemblerTests/StringInstructionHandlerTests.cs index 8adce1f..e672503 100644 --- a/X86DisassemblerTests/StringInstructionHandlerTests.cs +++ b/X86DisassemblerTests/StringInstructionHandlerTests.cs @@ -11,10 +11,10 @@ using X86Disassembler.X86.Handlers.String; public class StringInstructionHandlerTests { /// - /// Tests the RepMovsHandler for decoding REP MOVS instruction + /// Tests the StringInstructionHandler for decoding REP MOVS instruction /// [Fact] - public void RepMovsHandler_DecodesRepMovs_Correctly() + public void StringInstructionHandler_DecodesRepMovs_Correctly() { // Arrange // REP MOVS (F3 A5) @@ -29,4 +29,104 @@ public class StringInstructionHandlerTests Assert.Equal("rep movs", instruction.Mnemonic); Assert.Equal("dword ptr [edi], dword ptr [esi]", instruction.Operands); } + + /// + /// Tests the StringInstructionHandler for decoding REPNE SCAS instruction + /// + [Fact] + public void StringInstructionHandler_DecodesRepneScas_Correctly() + { + // Arrange + // REPNE SCAS (F2 AF) + byte[] codeBuffer = new byte[] { 0xF2, 0xAF }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("repne scas", instruction.Mnemonic); + Assert.Equal("eax, dword ptr [edi]", instruction.Operands); + } + + /// + /// Tests the StringInstructionHandler for decoding MOVS instruction without prefix + /// + [Fact] + public void StringInstructionHandler_DecodesMovs_Correctly() + { + // Arrange + // MOVS (A5) + byte[] codeBuffer = new byte[] { 0xA5 }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("movs", instruction.Mnemonic); + Assert.Equal("dword ptr [edi], dword ptr [esi]", instruction.Operands); + } + + /// + /// Tests the StringInstructionHandler for decoding STOS instruction without prefix + /// + [Fact] + public void StringInstructionHandler_DecodesStosb_Correctly() + { + // Arrange + // STOSB (AA) + byte[] codeBuffer = new byte[] { 0xAA }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("stos", instruction.Mnemonic); + Assert.Equal("byte ptr [edi], al", instruction.Operands); + } + + /// + /// Tests the StringInstructionHandler for decoding LODS instruction without prefix + /// + [Fact] + public void StringInstructionHandler_DecodesLodsd_Correctly() + { + // Arrange + // LODSD (AD) + byte[] codeBuffer = new byte[] { 0xAD }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("lods", instruction.Mnemonic); + Assert.Equal("eax, dword ptr [esi]", instruction.Operands); + } + + /// + /// Tests the StringInstructionHandler for decoding SCAS instruction without prefix + /// + [Fact] + public void StringInstructionHandler_DecodesScasb_Correctly() + { + // Arrange + // SCASB (AE) + byte[] codeBuffer = new byte[] { 0xAE }; + var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length); + + // Act + var instruction = decoder.DecodeInstruction(); + + // Assert + Assert.NotNull(instruction); + Assert.Equal("scas", instruction.Mnemonic); + Assert.Equal("al, byte ptr [edi]", instruction.Operands); + } }