mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-19 20:01:17 +03:00
Refactored instruction decoder to improve modularity. Created StringInstructionDecoder and updated PrefixDecoder. Fixed handler registration in InstructionHandlerFactory.
This commit is contained in:
parent
c14a92bf04
commit
9dfa559045
@ -13,6 +13,7 @@ using X86Disassembler.X86.Handlers.Or;
|
|||||||
using X86Disassembler.X86.Handlers.Pop;
|
using X86Disassembler.X86.Handlers.Pop;
|
||||||
using X86Disassembler.X86.Handlers.Push;
|
using X86Disassembler.X86.Handlers.Push;
|
||||||
using X86Disassembler.X86.Handlers.Ret;
|
using X86Disassembler.X86.Handlers.Ret;
|
||||||
|
using X86Disassembler.X86.Handlers.String;
|
||||||
using X86Disassembler.X86.Handlers.Test;
|
using X86Disassembler.X86.Handlers.Test;
|
||||||
using X86Disassembler.X86.Handlers.Xchg;
|
using X86Disassembler.X86.Handlers.Xchg;
|
||||||
using X86Disassembler.X86.Handlers.Xor;
|
using X86Disassembler.X86.Handlers.Xor;
|
||||||
@ -41,32 +42,36 @@ public class InstructionHandlerFactory
|
|||||||
_decoder = decoder;
|
_decoder = decoder;
|
||||||
_length = length;
|
_length = length;
|
||||||
|
|
||||||
RegisterHandlers();
|
RegisterAllHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers all handlers
|
/// Registers all handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void RegisterHandlers()
|
private void RegisterAllHandlers()
|
||||||
{
|
{
|
||||||
// Register specific instruction handlers
|
// Register specific instruction handlers
|
||||||
_handlers.Add(new Int3Handler(_codeBuffer, _decoder, _length));
|
_handlers.Add(new Int3Handler(_codeBuffer, _decoder, _length));
|
||||||
|
|
||||||
RegisterArithmeticUnaryHandlers();
|
|
||||||
RegisterArithmeticImmediateHandlers();
|
RegisterArithmeticImmediateHandlers();
|
||||||
RegisterReturnHandlers();
|
RegisterArithmeticUnaryHandlers();
|
||||||
RegisterCallHandlers();
|
RegisterAddHandlers();
|
||||||
RegisterJumpHandlers();
|
RegisterCmpHandlers();
|
||||||
RegisterTestHandlers();
|
|
||||||
RegisterXorHandlers();
|
RegisterXorHandlers();
|
||||||
RegisterOrHandlers();
|
RegisterOrHandlers();
|
||||||
RegisterLeaHandlers();
|
RegisterTestHandlers();
|
||||||
RegisterCmpHandlers();
|
RegisterDataTransferHandlers();
|
||||||
|
RegisterJumpHandlers();
|
||||||
|
RegisterCallHandlers();
|
||||||
|
RegisterReturnHandlers();
|
||||||
RegisterDecHandlers();
|
RegisterDecHandlers();
|
||||||
RegisterIncHandlers();
|
RegisterIncHandlers();
|
||||||
RegisterAddHandlers();
|
RegisterPushHandlers();
|
||||||
RegisterDataTransferHandlers();
|
RegisterPopHandlers();
|
||||||
|
RegisterLeaHandlers();
|
||||||
RegisterFloatingPointHandlers();
|
RegisterFloatingPointHandlers();
|
||||||
|
RegisterStringHandlers();
|
||||||
|
RegisterMovHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -295,6 +300,51 @@ public class InstructionHandlerFactory
|
|||||||
_handlers.Add(new LoadStoreInt16Handler(_codeBuffer, _decoder, _length));
|
_handlers.Add(new LoadStoreInt16Handler(_codeBuffer, _decoder, _length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers all String instruction handlers
|
||||||
|
/// </summary>
|
||||||
|
private void RegisterStringHandlers()
|
||||||
|
{
|
||||||
|
// Add String instruction handlers
|
||||||
|
_handlers.Add(new RepMovsHandler(_codeBuffer, _decoder, _length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers all MOV instruction handlers
|
||||||
|
/// </summary>
|
||||||
|
private void RegisterMovHandlers()
|
||||||
|
{
|
||||||
|
// Add MOV handlers
|
||||||
|
_handlers.Add(new MovRegMemHandler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovMemRegHandler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovRegImm32Handler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovRegImm8Handler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovEaxMoffsHandler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovMoffsEaxHandler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovRm32Imm32Handler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new MovRm8Imm8Handler(_codeBuffer, _decoder, _length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers all PUSH instruction handlers
|
||||||
|
/// </summary>
|
||||||
|
private void RegisterPushHandlers()
|
||||||
|
{
|
||||||
|
// Add PUSH handlers
|
||||||
|
_handlers.Add(new PushRegHandler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new PushImm32Handler(_codeBuffer, _decoder, _length));
|
||||||
|
_handlers.Add(new PushImm8Handler(_codeBuffer, _decoder, _length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers all POP instruction handlers
|
||||||
|
/// </summary>
|
||||||
|
private void RegisterPopHandlers()
|
||||||
|
{
|
||||||
|
// Add POP handlers
|
||||||
|
_handlers.Add(new PopRegHandler(_codeBuffer, _decoder, _length));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the handler that can decode the given opcode
|
/// Gets the handler that can decode the given opcode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,13 +19,10 @@ public class InstructionDecoder
|
|||||||
// The instruction handler factory
|
// The instruction handler factory
|
||||||
private readonly InstructionHandlerFactory _handlerFactory;
|
private readonly InstructionHandlerFactory _handlerFactory;
|
||||||
|
|
||||||
// Instruction prefixes
|
// Specialized decoders
|
||||||
private bool _operandSizePrefix;
|
private readonly PrefixDecoder _prefixDecoder;
|
||||||
private bool _addressSizePrefix;
|
private readonly ModRMDecoder _modRMDecoder;
|
||||||
private bool _segmentOverridePrefix;
|
private readonly StringInstructionDecoder _stringDecoder;
|
||||||
private bool _lockPrefix;
|
|
||||||
private bool _repPrefix;
|
|
||||||
private string _segmentOverride;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the InstructionDecoder class
|
/// Initializes a new instance of the InstructionDecoder class
|
||||||
@ -37,7 +34,11 @@ public class InstructionDecoder
|
|||||||
_codeBuffer = codeBuffer;
|
_codeBuffer = codeBuffer;
|
||||||
_length = length;
|
_length = length;
|
||||||
_position = 0;
|
_position = 0;
|
||||||
_segmentOverride = "";
|
|
||||||
|
// Create specialized decoders
|
||||||
|
_prefixDecoder = new PrefixDecoder();
|
||||||
|
_modRMDecoder = new ModRMDecoder(codeBuffer, this, length);
|
||||||
|
_stringDecoder = new StringInstructionDecoder(codeBuffer, length);
|
||||||
|
|
||||||
// Create the instruction handler factory
|
// Create the instruction handler factory
|
||||||
_handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length);
|
_handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length);
|
||||||
@ -55,12 +56,7 @@ public class InstructionDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset prefix flags
|
// Reset prefix flags
|
||||||
_operandSizePrefix = false;
|
_prefixDecoder.Reset();
|
||||||
_addressSizePrefix = false;
|
|
||||||
_segmentOverridePrefix = false;
|
|
||||||
_lockPrefix = false;
|
|
||||||
_repPrefix = false;
|
|
||||||
_segmentOverride = string.Empty;
|
|
||||||
|
|
||||||
// Save the start position of the instruction
|
// Save the start position of the instruction
|
||||||
int startPosition = _position;
|
int startPosition = _position;
|
||||||
@ -76,54 +72,21 @@ public class InstructionDecoder
|
|||||||
{
|
{
|
||||||
byte prefix = _codeBuffer[_position];
|
byte prefix = _codeBuffer[_position];
|
||||||
|
|
||||||
if (prefix == 0x66) // Operand size prefix
|
if (_prefixDecoder.DecodePrefix(prefix))
|
||||||
{
|
{
|
||||||
_operandSizePrefix = true;
|
|
||||||
_position++;
|
|
||||||
}
|
|
||||||
else if (prefix == 0x67) // Address size prefix
|
|
||||||
{
|
|
||||||
_addressSizePrefix = true;
|
|
||||||
_position++;
|
|
||||||
}
|
|
||||||
else if ((prefix >= 0x26 && prefix <= 0x3E && (prefix & 0x7) == 0x6) || prefix == 0x64 || prefix == 0x65) // Segment override prefix
|
|
||||||
{
|
|
||||||
_segmentOverridePrefix = true;
|
|
||||||
switch (prefix)
|
|
||||||
{
|
|
||||||
case 0x26: _segmentOverride = "es"; break;
|
|
||||||
case 0x2E: _segmentOverride = "cs"; break;
|
|
||||||
case 0x36: _segmentOverride = "ss"; break;
|
|
||||||
case 0x3E: _segmentOverride = "ds"; break;
|
|
||||||
case 0x64: _segmentOverride = "fs"; break;
|
|
||||||
case 0x65: _segmentOverride = "gs"; break;
|
|
||||||
}
|
|
||||||
_position++;
|
|
||||||
}
|
|
||||||
else if (prefix == 0xF0) // LOCK prefix
|
|
||||||
{
|
|
||||||
_lockPrefix = true;
|
|
||||||
_position++;
|
|
||||||
}
|
|
||||||
else if (prefix == 0xF2 || prefix == 0xF3) // REP/REPNE prefix
|
|
||||||
{
|
|
||||||
_repPrefix = true;
|
|
||||||
_position++;
|
_position++;
|
||||||
|
|
||||||
// Special case for string instructions
|
// Special case for REP/REPNE prefix followed by string instruction
|
||||||
if (_position < _length)
|
if ((prefix == 0xF2 || prefix == 0xF3) && _position < _length)
|
||||||
{
|
{
|
||||||
byte stringOp = _codeBuffer[_position];
|
byte nextByte = _codeBuffer[_position];
|
||||||
if (stringOp == 0xA4 || stringOp == 0xA5 || // MOVS
|
if (_stringDecoder.IsStringInstruction(nextByte))
|
||||||
stringOp == 0xAA || stringOp == 0xAB || // STOS
|
|
||||||
stringOp == 0xAC || stringOp == 0xAD || // LODS
|
|
||||||
stringOp == 0xAE || stringOp == 0xAF) // SCAS
|
|
||||||
{
|
{
|
||||||
// Skip the string operation opcode
|
// Skip the string operation opcode
|
||||||
_position++;
|
_position++;
|
||||||
|
|
||||||
// Handle REP string instruction
|
// Handle REP string instruction
|
||||||
return CreateStringInstruction(prefix, stringOp, startPosition);
|
return _stringDecoder.CreateStringInstruction(prefix, nextByte, startPosition, _position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,9 +100,9 @@ public class InstructionDecoder
|
|||||||
{
|
{
|
||||||
// If we reached the end of the buffer while processing prefixes,
|
// If we reached the end of the buffer while processing prefixes,
|
||||||
// create an instruction with just the prefix information
|
// create an instruction with just the prefix information
|
||||||
if (_segmentOverridePrefix)
|
if (_prefixDecoder.HasSegmentOverridePrefix())
|
||||||
{
|
{
|
||||||
instruction.Mnemonic = _segmentOverride;
|
instruction.Mnemonic = _prefixDecoder.GetSegmentOverride();
|
||||||
instruction.Operands = "";
|
instruction.Operands = "";
|
||||||
|
|
||||||
// Set the raw bytes
|
// Set the raw bytes
|
||||||
@ -174,22 +137,9 @@ public class InstructionDecoder
|
|||||||
instruction.Operands = "??";
|
instruction.Operands = "??";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add REP prefix to the instruction if present
|
// Apply prefixes to the instruction
|
||||||
if (_repPrefix && !instruction.Mnemonic.StartsWith("rep"))
|
instruction.Mnemonic = _prefixDecoder.ApplyRepPrefix(instruction.Mnemonic);
|
||||||
{
|
instruction.Operands = _prefixDecoder.ApplySegmentOverride(instruction.Operands);
|
||||||
instruction.Mnemonic = $"rep {instruction.Mnemonic}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add segment override prefix to the instruction if present
|
|
||||||
if (_segmentOverridePrefix && !string.IsNullOrEmpty(instruction.Operands))
|
|
||||||
{
|
|
||||||
// If the instruction has memory operands, add the segment override
|
|
||||||
if (instruction.Operands.Contains("["))
|
|
||||||
{
|
|
||||||
// Replace the first '[' with the segment override
|
|
||||||
instruction.Operands = instruction.Operands.Replace("[", $"{_segmentOverride}:[" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the raw bytes
|
// Set the raw bytes
|
||||||
int bytesLength = _position - startPosition;
|
int bytesLength = _position - startPosition;
|
||||||
@ -199,62 +149,6 @@ public class InstructionDecoder
|
|||||||
return instruction;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current position in the buffer
|
/// Gets the current position in the buffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -279,7 +173,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>True if the operand size prefix is present</returns>
|
/// <returns>True if the operand size prefix is present</returns>
|
||||||
public bool HasOperandSizePrefix()
|
public bool HasOperandSizePrefix()
|
||||||
{
|
{
|
||||||
return _operandSizePrefix;
|
return _prefixDecoder.HasOperandSizePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -288,7 +182,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>True if the address size prefix is present</returns>
|
/// <returns>True if the address size prefix is present</returns>
|
||||||
public bool HasAddressSizePrefix()
|
public bool HasAddressSizePrefix()
|
||||||
{
|
{
|
||||||
return _addressSizePrefix;
|
return _prefixDecoder.HasAddressSizePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -297,7 +191,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>True if a segment override prefix is present</returns>
|
/// <returns>True if a segment override prefix is present</returns>
|
||||||
public bool HasSegmentOverridePrefix()
|
public bool HasSegmentOverridePrefix()
|
||||||
{
|
{
|
||||||
return _segmentOverridePrefix;
|
return _prefixDecoder.HasSegmentOverridePrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -306,7 +200,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>The segment override prefix, or an empty string if none is present</returns>
|
/// <returns>The segment override prefix, or an empty string if none is present</returns>
|
||||||
public string GetSegmentOverride()
|
public string GetSegmentOverride()
|
||||||
{
|
{
|
||||||
return _segmentOverride;
|
return _prefixDecoder.GetSegmentOverride();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -315,7 +209,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>True if the LOCK prefix is present</returns>
|
/// <returns>True if the LOCK prefix is present</returns>
|
||||||
public bool HasLockPrefix()
|
public bool HasLockPrefix()
|
||||||
{
|
{
|
||||||
return _lockPrefix;
|
return _prefixDecoder.HasLockPrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -324,7 +218,7 @@ public class InstructionDecoder
|
|||||||
/// <returns>True if the REP/REPNE prefix is present</returns>
|
/// <returns>True if the REP/REPNE prefix is present</returns>
|
||||||
public bool HasRepPrefix()
|
public bool HasRepPrefix()
|
||||||
{
|
{
|
||||||
return _repPrefix;
|
return _prefixDecoder.HasRepPrefix();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -352,7 +246,7 @@ public class InstructionDecoder
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort value = BitConverter.ToUInt16(_codeBuffer, _position);
|
ushort value = (ushort)(_codeBuffer[_position] | (_codeBuffer[_position + 1] << 8));
|
||||||
_position += 2;
|
_position += 2;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -368,7 +262,10 @@ public class InstructionDecoder
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint value = BitConverter.ToUInt32(_codeBuffer, _position);
|
uint value = (uint)(_codeBuffer[_position] |
|
||||||
|
(_codeBuffer[_position + 1] << 8) |
|
||||||
|
(_codeBuffer[_position + 2] << 16) |
|
||||||
|
(_codeBuffer[_position + 3] << 24));
|
||||||
_position += 4;
|
_position += 4;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
170
X86Disassembler/X86/PrefixDecoder.cs
Normal file
170
X86Disassembler/X86/PrefixDecoder.cs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
namespace X86Disassembler.X86;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles decoding of instruction prefixes
|
||||||
|
/// </summary>
|
||||||
|
public class PrefixDecoder
|
||||||
|
{
|
||||||
|
// Prefix flags
|
||||||
|
private bool _operandSizePrefix;
|
||||||
|
private bool _addressSizePrefix;
|
||||||
|
private bool _segmentOverridePrefix;
|
||||||
|
private bool _lockPrefix;
|
||||||
|
private bool _repPrefix;
|
||||||
|
private string _segmentOverride = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PrefixDecoder class
|
||||||
|
/// </summary>
|
||||||
|
public PrefixDecoder()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets all prefix flags
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_operandSizePrefix = false;
|
||||||
|
_addressSizePrefix = false;
|
||||||
|
_segmentOverridePrefix = false;
|
||||||
|
_lockPrefix = false;
|
||||||
|
_repPrefix = false;
|
||||||
|
_segmentOverride = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a prefix byte
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prefix">The prefix byte</param>
|
||||||
|
/// <returns>True if the byte was a prefix, false otherwise</returns>
|
||||||
|
public bool DecodePrefix(byte prefix)
|
||||||
|
{
|
||||||
|
if (prefix == 0x66) // Operand size prefix
|
||||||
|
{
|
||||||
|
_operandSizePrefix = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (prefix == 0x67) // Address size prefix
|
||||||
|
{
|
||||||
|
_addressSizePrefix = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((prefix >= 0x26 && prefix <= 0x3E && (prefix & 0x7) == 0x6) || prefix == 0x64 || prefix == 0x65) // Segment override prefix
|
||||||
|
{
|
||||||
|
_segmentOverridePrefix = true;
|
||||||
|
switch (prefix)
|
||||||
|
{
|
||||||
|
case 0x26: _segmentOverride = "es"; break;
|
||||||
|
case 0x2E: _segmentOverride = "cs"; break;
|
||||||
|
case 0x36: _segmentOverride = "ss"; break;
|
||||||
|
case 0x3E: _segmentOverride = "ds"; break;
|
||||||
|
case 0x64: _segmentOverride = "fs"; break;
|
||||||
|
case 0x65: _segmentOverride = "gs"; break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (prefix == 0xF0) // LOCK prefix
|
||||||
|
{
|
||||||
|
_lockPrefix = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (prefix == 0xF2 || prefix == 0xF3) // REP/REPNE prefix
|
||||||
|
{
|
||||||
|
_repPrefix = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the operand size prefix is present
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the operand size prefix is present</returns>
|
||||||
|
public bool HasOperandSizePrefix()
|
||||||
|
{
|
||||||
|
return _operandSizePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the address size prefix is present
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the address size prefix is present</returns>
|
||||||
|
public bool HasAddressSizePrefix()
|
||||||
|
{
|
||||||
|
return _addressSizePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a segment override prefix is present
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if a segment override prefix is present</returns>
|
||||||
|
public bool HasSegmentOverridePrefix()
|
||||||
|
{
|
||||||
|
return _segmentOverridePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the segment override prefix
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The segment override prefix, or an empty string if none is present</returns>
|
||||||
|
public string GetSegmentOverride()
|
||||||
|
{
|
||||||
|
return _segmentOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the LOCK prefix is present
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the LOCK prefix is present</returns>
|
||||||
|
public bool HasLockPrefix()
|
||||||
|
{
|
||||||
|
return _lockPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the REP/REPNE prefix is present
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the REP/REPNE prefix is present</returns>
|
||||||
|
public bool HasRepPrefix()
|
||||||
|
{
|
||||||
|
return _repPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the segment override prefix to the operands string if applicable
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="operands">The operands string</param>
|
||||||
|
/// <returns>The operands string with segment override applied</returns>
|
||||||
|
public string ApplySegmentOverride(string operands)
|
||||||
|
{
|
||||||
|
if (_segmentOverridePrefix && !string.IsNullOrEmpty(operands))
|
||||||
|
{
|
||||||
|
// If the instruction has memory operands, add the segment override
|
||||||
|
if (operands.Contains("["))
|
||||||
|
{
|
||||||
|
// Replace the first '[' with the segment override
|
||||||
|
return operands.Replace("[", $"{_segmentOverride}:[" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return operands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the REP prefix to the mnemonic if applicable
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mnemonic">The mnemonic</param>
|
||||||
|
/// <returns>The mnemonic with REP prefix applied</returns>
|
||||||
|
public string ApplyRepPrefix(string mnemonic)
|
||||||
|
{
|
||||||
|
if (_repPrefix && !mnemonic.StartsWith("rep"))
|
||||||
|
{
|
||||||
|
return $"rep {mnemonic}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return mnemonic;
|
||||||
|
}
|
||||||
|
}
|
98
X86Disassembler/X86/StringInstructionDecoder.cs
Normal file
98
X86Disassembler/X86/StringInstructionDecoder.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
namespace X86Disassembler.X86;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles decoding of string instructions
|
||||||
|
/// </summary>
|
||||||
|
public class StringInstructionDecoder
|
||||||
|
{
|
||||||
|
// The buffer containing the code to decode
|
||||||
|
private readonly byte[] _codeBuffer;
|
||||||
|
|
||||||
|
// The length of the buffer
|
||||||
|
private readonly int _length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the StringInstructionDecoder class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||||
|
/// <param name="length">The length of the buffer</param>
|
||||||
|
public StringInstructionDecoder(byte[] codeBuffer, int length)
|
||||||
|
{
|
||||||
|
_codeBuffer = codeBuffer;
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the opcode is a string instruction
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode to check</param>
|
||||||
|
/// <returns>True if the opcode is a string instruction</returns>
|
||||||
|
public bool IsStringInstruction(byte opcode)
|
||||||
|
{
|
||||||
|
return opcode == 0xA4 || opcode == 0xA5 || // MOVS
|
||||||
|
opcode == 0xAA || opcode == 0xAB || // STOS
|
||||||
|
opcode == 0xAC || opcode == 0xAD || // LODS
|
||||||
|
opcode == 0xAE || opcode == 0xAF; // SCAS
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// <param name="currentPosition">The current position after reading the string opcode</param>
|
||||||
|
/// <returns>The created instruction</returns>
|
||||||
|
public Instruction CreateStringInstruction(byte prefix, byte stringOp, int startPosition, int currentPosition)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
instruction.Operands = GetStringOperands(stringOp);
|
||||||
|
|
||||||
|
// Set the raw bytes
|
||||||
|
int length = currentPosition - startPosition;
|
||||||
|
instruction.RawBytes = new byte[length];
|
||||||
|
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length);
|
||||||
|
|
||||||
|
return instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the operands for a string instruction
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stringOp">The string operation opcode</param>
|
||||||
|
/// <returns>The operands string</returns>
|
||||||
|
private string GetStringOperands(byte stringOp)
|
||||||
|
{
|
||||||
|
switch (stringOp)
|
||||||
|
{
|
||||||
|
case 0xA4: // MOVSB
|
||||||
|
return "byte ptr [edi], byte ptr [esi]";
|
||||||
|
case 0xA5: // MOVSD
|
||||||
|
return "dword ptr [edi], dword ptr [esi]";
|
||||||
|
case 0xAA: // STOSB
|
||||||
|
return "byte ptr [edi], al";
|
||||||
|
case 0xAB: // STOSD
|
||||||
|
return "dword ptr [edi], eax";
|
||||||
|
case 0xAC: // LODSB
|
||||||
|
return "al, byte ptr [esi]";
|
||||||
|
case 0xAD: // LODSD
|
||||||
|
return "eax, dword ptr [esi]";
|
||||||
|
case 0xAE: // SCASB
|
||||||
|
return "al, byte ptr [edi]";
|
||||||
|
case 0xAF: // SCASD
|
||||||
|
return "eax, dword ptr [edi]";
|
||||||
|
default:
|
||||||
|
return "??";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user