mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-19 20:01:17 +03:00
Added support for string instructions with REP prefix, specifically F3 A5 (REP MOVS)
This commit is contained in:
parent
bfaeba0d5f
commit
c14a92bf04
@ -109,6 +109,23 @@ public class InstructionDecoder
|
|||||||
{
|
{
|
||||||
_repPrefix = true;
|
_repPrefix = true;
|
||||||
_position++;
|
_position++;
|
||||||
|
|
||||||
|
// Special case for string instructions
|
||||||
|
if (_position < _length)
|
||||||
|
{
|
||||||
|
byte stringOp = _codeBuffer[_position];
|
||||||
|
if (stringOp == 0xA4 || stringOp == 0xA5 || // MOVS
|
||||||
|
stringOp == 0xAA || stringOp == 0xAB || // STOS
|
||||||
|
stringOp == 0xAC || stringOp == 0xAD || // LODS
|
||||||
|
stringOp == 0xAE || stringOp == 0xAF) // SCAS
|
||||||
|
{
|
||||||
|
// Skip the string operation opcode
|
||||||
|
_position++;
|
||||||
|
|
||||||
|
// Handle REP string instruction
|
||||||
|
return CreateStringInstruction(prefix, stringOp, startPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -157,6 +174,12 @@ public class InstructionDecoder
|
|||||||
instruction.Operands = "??";
|
instruction.Operands = "??";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add REP prefix to the instruction if present
|
||||||
|
if (_repPrefix && !instruction.Mnemonic.StartsWith("rep"))
|
||||||
|
{
|
||||||
|
instruction.Mnemonic = $"rep {instruction.Mnemonic}";
|
||||||
|
}
|
||||||
|
|
||||||
// Add segment override prefix to the instruction if present
|
// Add segment override prefix to the instruction if present
|
||||||
if (_segmentOverridePrefix && !string.IsNullOrEmpty(instruction.Operands))
|
if (_segmentOverridePrefix && !string.IsNullOrEmpty(instruction.Operands))
|
||||||
{
|
{
|
||||||
@ -169,9 +192,65 @@ public class InstructionDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the raw bytes
|
// Set the raw bytes
|
||||||
int instructionLength = _position - startPosition;
|
int bytesLength = _position - startPosition;
|
||||||
instruction.RawBytes = new byte[instructionLength];
|
instruction.RawBytes = new byte[bytesLength];
|
||||||
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, instructionLength);
|
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, bytesLength);
|
||||||
|
|
||||||
|
return instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instruction for a string operation with REP/REPNE prefix
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prefix">The REP/REPNE prefix (0xF2 or 0xF3)</param>
|
||||||
|
/// <param name="stringOp">The string operation opcode</param>
|
||||||
|
/// <param name="startPosition">The start position of the instruction</param>
|
||||||
|
/// <returns>The created instruction</returns>
|
||||||
|
private Instruction CreateStringInstruction(byte prefix, byte stringOp, int startPosition)
|
||||||
|
{
|
||||||
|
// Create a new instruction
|
||||||
|
Instruction instruction = new Instruction
|
||||||
|
{
|
||||||
|
Address = (uint)startPosition,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the mnemonic for the string operation
|
||||||
|
string mnemonic = OpcodeMap.GetMnemonic(stringOp);
|
||||||
|
instruction.Mnemonic = prefix == 0xF3 ? $"rep {mnemonic}" : $"repne {mnemonic}";
|
||||||
|
|
||||||
|
// Set operands based on the string operation
|
||||||
|
switch (stringOp)
|
||||||
|
{
|
||||||
|
case 0xA4: // MOVSB
|
||||||
|
instruction.Operands = "byte ptr [edi], byte ptr [esi]";
|
||||||
|
break;
|
||||||
|
case 0xA5: // MOVSD
|
||||||
|
instruction.Operands = "dword ptr [edi], dword ptr [esi]";
|
||||||
|
break;
|
||||||
|
case 0xAA: // STOSB
|
||||||
|
instruction.Operands = "byte ptr [edi], al";
|
||||||
|
break;
|
||||||
|
case 0xAB: // STOSD
|
||||||
|
instruction.Operands = "dword ptr [edi], eax";
|
||||||
|
break;
|
||||||
|
case 0xAC: // LODSB
|
||||||
|
instruction.Operands = "al, byte ptr [esi]";
|
||||||
|
break;
|
||||||
|
case 0xAD: // LODSD
|
||||||
|
instruction.Operands = "eax, dword ptr [esi]";
|
||||||
|
break;
|
||||||
|
case 0xAE: // SCASB
|
||||||
|
instruction.Operands = "al, byte ptr [edi]";
|
||||||
|
break;
|
||||||
|
case 0xAF: // SCASD
|
||||||
|
instruction.Operands = "eax, dword ptr [edi]";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the raw bytes
|
||||||
|
int length = _position - startPosition;
|
||||||
|
instruction.RawBytes = new byte[length];
|
||||||
|
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length);
|
||||||
|
|
||||||
return instruction;
|
return instruction;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,16 @@ public static class OpcodeMap
|
|||||||
OneByteOpcodes[0xA2] = "mov"; // MOV moffs8, AL
|
OneByteOpcodes[0xA2] = "mov"; // MOV moffs8, AL
|
||||||
OneByteOpcodes[0xA3] = "mov"; // MOV moffs32, EAX
|
OneByteOpcodes[0xA3] = "mov"; // MOV moffs32, EAX
|
||||||
|
|
||||||
|
// String instructions
|
||||||
|
OneByteOpcodes[0xA4] = "movs"; // MOVS byte
|
||||||
|
OneByteOpcodes[0xA5] = "movs"; // MOVS dword
|
||||||
|
OneByteOpcodes[0xAA] = "stos"; // STOS byte
|
||||||
|
OneByteOpcodes[0xAB] = "stos"; // STOS dword
|
||||||
|
OneByteOpcodes[0xAC] = "lods"; // LODS byte
|
||||||
|
OneByteOpcodes[0xAD] = "lods"; // LODS dword
|
||||||
|
OneByteOpcodes[0xAE] = "scas"; // SCAS byte
|
||||||
|
OneByteOpcodes[0xAF] = "scas"; // SCAS dword
|
||||||
|
|
||||||
// Control flow instructions
|
// Control flow instructions
|
||||||
OneByteOpcodes[0xCC] = "int3";
|
OneByteOpcodes[0xCC] = "int3";
|
||||||
OneByteOpcodes[0x90] = "nop";
|
OneByteOpcodes[0x90] = "nop";
|
||||||
@ -178,6 +188,6 @@ public static class OpcodeMap
|
|||||||
/// <returns>The mnemonic</returns>
|
/// <returns>The mnemonic</returns>
|
||||||
public static string GetMnemonic(byte opcode)
|
public static string GetMnemonic(byte opcode)
|
||||||
{
|
{
|
||||||
return "TODO UNKNOWN: " + OneByteOpcodes[opcode];
|
return OneByteOpcodes[opcode];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
X86DisassemblerTests/StringInstructionHandlerTests.cs
Normal file
32
X86DisassemblerTests/StringInstructionHandlerTests.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
namespace X86DisassemblerTests;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
using X86Disassembler.X86;
|
||||||
|
using X86Disassembler.X86.Handlers.String;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests for string instruction handlers
|
||||||
|
/// </summary>
|
||||||
|
public class StringInstructionHandlerTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tests the RepMovsHandler for decoding REP MOVS instruction
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public void RepMovsHandler_DecodesRepMovs_Correctly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// REP MOVS (F3 A5)
|
||||||
|
byte[] codeBuffer = new byte[] { 0xF3, 0xA5 };
|
||||||
|
var decoder = new InstructionDecoder(codeBuffer, codeBuffer.Length);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var instruction = decoder.DecodeInstruction();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(instruction);
|
||||||
|
Assert.Equal("rep movs", instruction.Mnemonic);
|
||||||
|
Assert.Equal("dword ptr [edi], dword ptr [esi]", instruction.Operands);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user