mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-19 11:51:17 +03:00
fixes
This commit is contained in:
parent
4d2db05a07
commit
df453b930f
47
X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs
Normal file
47
X86Disassembler/X86/Handlers/Ret/Retf16Handler.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using X86Disassembler.X86.Operands;
|
||||||
|
|
||||||
|
namespace X86Disassembler.X86.Handlers.Ret;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for RETF instruction with operand size prefix (0xCB with 0x66 prefix)
|
||||||
|
/// </summary>
|
||||||
|
public class Retf16Handler : InstructionHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the Retf16Handler class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||||
|
public Retf16Handler(InstructionDecoder decoder)
|
||||||
|
: base(decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if this handler can decode the given opcode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode to check</param>
|
||||||
|
/// <returns>True if this handler can decode the opcode</returns>
|
||||||
|
public override bool CanHandle(byte opcode)
|
||||||
|
{
|
||||||
|
// RETF with operand size prefix is encoded as 0xCB with 0x66 prefix
|
||||||
|
// Only handle when the operand size prefix IS present
|
||||||
|
return opcode == 0xCB && Decoder.HasOperandSizePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a RETF instruction with operand size prefix
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode of the instruction</param>
|
||||||
|
/// <param name="instruction">The instruction object to populate</param>
|
||||||
|
/// <returns>True if the instruction was successfully decoded</returns>
|
||||||
|
public override bool Decode(byte opcode, Instruction instruction)
|
||||||
|
{
|
||||||
|
// Set the instruction type
|
||||||
|
instruction.Type = InstructionType.Retf;
|
||||||
|
|
||||||
|
// RETF has no operands
|
||||||
|
instruction.StructuredOperands = [];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
48
X86Disassembler/X86/Handlers/Ret/RetfHandler.cs
Normal file
48
X86Disassembler/X86/Handlers/Ret/RetfHandler.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using X86Disassembler.X86.Operands;
|
||||||
|
|
||||||
|
namespace X86Disassembler.X86.Handlers.Ret;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for RETF instruction (0xCB)
|
||||||
|
/// </summary>
|
||||||
|
public class RetfHandler : InstructionHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the RetfHandler class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||||
|
public RetfHandler(InstructionDecoder decoder)
|
||||||
|
: base(decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if this handler can decode the given opcode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode to check</param>
|
||||||
|
/// <returns>True if this handler can decode the opcode</returns>
|
||||||
|
public override bool CanHandle(byte opcode)
|
||||||
|
{
|
||||||
|
// RETF is encoded as 0xCB
|
||||||
|
// Only handle when the operand size prefix is NOT present
|
||||||
|
// This ensures 16-bit handlers get priority when the prefix is present
|
||||||
|
return opcode == 0xCB && !Decoder.HasOperandSizePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a RETF instruction
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode of the instruction</param>
|
||||||
|
/// <param name="instruction">The instruction object to populate</param>
|
||||||
|
/// <returns>True if the instruction was successfully decoded</returns>
|
||||||
|
public override bool Decode(byte opcode, Instruction instruction)
|
||||||
|
{
|
||||||
|
// Set the instruction type
|
||||||
|
instruction.Type = InstructionType.Retf;
|
||||||
|
|
||||||
|
// RETF has no operands
|
||||||
|
instruction.StructuredOperands = [];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
60
X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs
Normal file
60
X86Disassembler/X86/Handlers/Ret/RetfImm16Handler.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using X86Disassembler.X86.Operands;
|
||||||
|
|
||||||
|
namespace X86Disassembler.X86.Handlers.Ret;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for RETF imm16 instruction with operand size prefix (0xCA with 0x66 prefix)
|
||||||
|
/// </summary>
|
||||||
|
public class RetfImm16Handler : InstructionHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the RetfImm16Handler class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||||
|
public RetfImm16Handler(InstructionDecoder decoder)
|
||||||
|
: base(decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if this handler can decode the given opcode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode to check</param>
|
||||||
|
/// <returns>True if this handler can decode the opcode</returns>
|
||||||
|
public override bool CanHandle(byte opcode)
|
||||||
|
{
|
||||||
|
// RETF imm16 with operand size prefix is encoded as 0xCA with 0x66 prefix
|
||||||
|
// Only handle when the operand size prefix IS present
|
||||||
|
return opcode == 0xCA && Decoder.HasOperandSizePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a RETF imm16 instruction with operand size prefix
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode of the instruction</param>
|
||||||
|
/// <param name="instruction">The instruction object to populate</param>
|
||||||
|
/// <returns>True if the instruction was successfully decoded</returns>
|
||||||
|
public override bool Decode(byte opcode, Instruction instruction)
|
||||||
|
{
|
||||||
|
// Set the instruction type
|
||||||
|
instruction.Type = InstructionType.Retf;
|
||||||
|
|
||||||
|
// Check if we can read the immediate word
|
||||||
|
if (!Decoder.CanReadUShort())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read the immediate word (number of bytes to pop from stack)
|
||||||
|
ushort imm16 = Decoder.ReadUInt16();
|
||||||
|
|
||||||
|
// Create an immediate operand for the pop count
|
||||||
|
var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
|
||||||
|
|
||||||
|
// Set the structured operands
|
||||||
|
instruction.StructuredOperands =
|
||||||
|
[
|
||||||
|
immOperand
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
61
X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs
Normal file
61
X86Disassembler/X86/Handlers/Ret/RetfImmHandler.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using X86Disassembler.X86.Operands;
|
||||||
|
|
||||||
|
namespace X86Disassembler.X86.Handlers.Ret;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for RETF imm16 instruction (0xCA)
|
||||||
|
/// </summary>
|
||||||
|
public class RetfImmHandler : InstructionHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the RetfImmHandler class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||||
|
public RetfImmHandler(InstructionDecoder decoder)
|
||||||
|
: base(decoder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if this handler can decode the given opcode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode to check</param>
|
||||||
|
/// <returns>True if this handler can decode the opcode</returns>
|
||||||
|
public override bool CanHandle(byte opcode)
|
||||||
|
{
|
||||||
|
// RETF imm16 is encoded as 0xCA
|
||||||
|
// Only handle when the operand size prefix is NOT present
|
||||||
|
// This ensures 16-bit handlers get priority when the prefix is present
|
||||||
|
return opcode == 0xCA && !Decoder.HasOperandSizePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a RETF imm16 instruction
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode of the instruction</param>
|
||||||
|
/// <param name="instruction">The instruction object to populate</param>
|
||||||
|
/// <returns>True if the instruction was successfully decoded</returns>
|
||||||
|
public override bool Decode(byte opcode, Instruction instruction)
|
||||||
|
{
|
||||||
|
// Set the instruction type
|
||||||
|
instruction.Type = InstructionType.Retf;
|
||||||
|
|
||||||
|
// Check if we can read the immediate word
|
||||||
|
if (!Decoder.CanReadUShort())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read the immediate word (number of bytes to pop from stack)
|
||||||
|
ushort imm16 = Decoder.ReadUInt16();
|
||||||
|
|
||||||
|
// Create an immediate operand for the pop count
|
||||||
|
var immOperand = OperandFactory.CreateImmediateOperand(imm16, 16);
|
||||||
|
|
||||||
|
// Set the structured operands
|
||||||
|
instruction.StructuredOperands =
|
||||||
|
[
|
||||||
|
immOperand
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -3,47 +3,67 @@ namespace X86Disassembler.X86.Handlers.String;
|
|||||||
using Operands;
|
using Operands;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for string instructions (MOVS, STOS, LODS, SCAS) with and without REP/REPNE prefixes
|
/// Handler for string instructions (MOVS, CMPS, STOS, LODS, SCAS)
|
||||||
|
/// The REP/REPNE prefixes are handled by the InstructionDecoder class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StringInstructionHandler : InstructionHandler
|
public class StringInstructionHandler : InstructionHandler
|
||||||
{
|
{
|
||||||
// Dictionary mapping opcodes to their instruction types and operand factories
|
// Dictionary mapping opcodes to their instruction types and operand factories for 32-bit mode (default)
|
||||||
private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions = new()
|
private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions32 = new()
|
||||||
{
|
{
|
||||||
|
// MOVS instructions
|
||||||
{ 0xA4, (InstructionType.MovsB, () =>
|
{ 0xA4, (InstructionType.MovsB, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"),
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds")
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
|
||||||
]) }, // MOVSB
|
]) }, // MOVSB
|
||||||
{ 0xA5, (InstructionType.MovsD, () =>
|
{ 0xA5, (InstructionType.MovsD, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
|
||||||
]) }, // MOVSD
|
]) }, // MOVSD
|
||||||
|
|
||||||
|
// CMPS instructions
|
||||||
|
{ 0xA6, (InstructionType.CmpsB, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
|
||||||
|
]) }, // CMPSB
|
||||||
|
{ 0xA7, (InstructionType.CmpsD, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds"),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es")
|
||||||
|
]) }, // CMPSD
|
||||||
|
|
||||||
|
// STOS instructions
|
||||||
{ 0xAA, (InstructionType.StosB, () =>
|
{ 0xAA, (InstructionType.StosB, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es"),
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
|
||||||
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8)
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL)
|
||||||
]) }, // STOSB
|
]) }, // STOSB
|
||||||
{ 0xAB, (InstructionType.StosD, () =>
|
{ 0xAB, (InstructionType.StosD, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 32, "es"),
|
||||||
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32)
|
||||||
]) }, // STOSD
|
]) }, // STOSD
|
||||||
|
|
||||||
|
// LODS instructions
|
||||||
{ 0xAC, (InstructionType.LodsB, () =>
|
{ 0xAC, (InstructionType.LodsB, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 8, "ds")
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
|
||||||
]) }, // LODSB
|
]) }, // LODSB
|
||||||
{ 0xAD, (InstructionType.LodsD, () =>
|
{ 0xAD, (InstructionType.LodsD, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 32),
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 32, "ds")
|
||||||
]) }, // LODSD
|
]) }, // LODSD
|
||||||
|
|
||||||
|
// SCAS instructions
|
||||||
{ 0xAE, (InstructionType.ScasB, () =>
|
{ 0xAE, (InstructionType.ScasB, () =>
|
||||||
[
|
[
|
||||||
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 8),
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
|
||||||
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 8, "es")
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
|
||||||
]) }, // SCASB
|
]) }, // SCASB
|
||||||
{ 0xAF, (InstructionType.ScasD, () =>
|
{ 0xAF, (InstructionType.ScasD, () =>
|
||||||
[
|
[
|
||||||
@ -52,28 +72,68 @@ public class StringInstructionHandler : InstructionHandler
|
|||||||
]) } // SCASD
|
]) } // SCASD
|
||||||
};
|
};
|
||||||
|
|
||||||
// REP/REPNE prefix opcodes
|
// Dictionary mapping opcodes to their instruction types and operand factories for 16-bit mode (with operand size prefix)
|
||||||
private const byte REP_PREFIX = 0xF3;
|
private static readonly Dictionary<byte, (InstructionType Type, Func<Operand[]> CreateOperands)> StringInstructions16 = new()
|
||||||
private const byte REPNE_PREFIX = 0xF2;
|
|
||||||
|
|
||||||
// Dictionary mapping base instruction types to their REP-prefixed versions
|
|
||||||
private static readonly Dictionary<InstructionType, InstructionType> RepPrefixMap = new()
|
|
||||||
{
|
{
|
||||||
{ InstructionType.MovsB, InstructionType.RepMovsB },
|
// MOVS instructions
|
||||||
{ InstructionType.MovsD, InstructionType.RepMovsD },
|
{ 0xA4, (InstructionType.MovsB, () =>
|
||||||
{ InstructionType.StosB, InstructionType.RepStosB },
|
[
|
||||||
{ InstructionType.StosD, InstructionType.RepStosD },
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
|
||||||
{ InstructionType.LodsB, InstructionType.RepLodsB },
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
|
||||||
{ InstructionType.LodsD, InstructionType.RepLodsD },
|
]) }, // MOVSB (same for 16-bit)
|
||||||
{ InstructionType.ScasB, InstructionType.RepScasB },
|
{ 0xA5, (InstructionType.MovsW, () =>
|
||||||
{ InstructionType.ScasD, InstructionType.RepScasD }
|
[
|
||||||
};
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds")
|
||||||
|
]) }, // MOVSW
|
||||||
|
|
||||||
// Dictionary mapping base instruction types to their REPNE-prefixed versions
|
// CMPS instructions
|
||||||
private static readonly Dictionary<InstructionType, InstructionType> RepnePrefixMap = new()
|
{ 0xA6, (InstructionType.CmpsB, () =>
|
||||||
{
|
[
|
||||||
{ InstructionType.ScasB, InstructionType.RepneScasB },
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds"),
|
||||||
{ InstructionType.ScasD, InstructionType.RepneScasD }
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
|
||||||
|
]) }, // CMPSB (same for 16-bit)
|
||||||
|
{ 0xA7, (InstructionType.CmpsW, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds"),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es")
|
||||||
|
]) }, // CMPSW
|
||||||
|
|
||||||
|
// STOS instructions
|
||||||
|
{ 0xAA, (InstructionType.StosB, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es"),
|
||||||
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL)
|
||||||
|
]) }, // STOSB (same for 16-bit)
|
||||||
|
{ 0xAB, (InstructionType.StosW, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es"),
|
||||||
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16)
|
||||||
|
]) }, // STOSW
|
||||||
|
|
||||||
|
// LODS instructions
|
||||||
|
{ 0xAC, (InstructionType.LodsB, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Si, "ds")
|
||||||
|
]) }, // LODSB (same for 16-bit)
|
||||||
|
{ 0xAD, (InstructionType.LodsW, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Si, 16, "ds")
|
||||||
|
]) }, // LODSW
|
||||||
|
|
||||||
|
// SCAS instructions
|
||||||
|
{ 0xAE, (InstructionType.ScasB, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateRegisterOperand8(RegisterIndex8.AL),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand8(RegisterIndex.Di, "es")
|
||||||
|
]) }, // SCASB (same for 16-bit)
|
||||||
|
{ 0xAF, (InstructionType.ScasW, () =>
|
||||||
|
[
|
||||||
|
OperandFactory.CreateRegisterOperand(RegisterIndex.A, 16),
|
||||||
|
OperandFactory.CreateBaseRegisterMemoryOperand(RegisterIndex.Di, 16, "es")
|
||||||
|
]) } // SCASW
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -92,27 +152,8 @@ public class StringInstructionHandler : InstructionHandler
|
|||||||
/// <returns>True if this handler can handle the opcode</returns>
|
/// <returns>True if this handler can handle the opcode</returns>
|
||||||
public override bool CanHandle(byte opcode)
|
public override bool CanHandle(byte opcode)
|
||||||
{
|
{
|
||||||
// Check if the opcode is a string instruction
|
// Check if the opcode is a string instruction in either 16-bit or 32-bit mode
|
||||||
if (StringInstructions.ContainsKey(opcode))
|
return StringInstructions32.ContainsKey(opcode);
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the opcode is a REP/REPNE prefix followed by a string instruction
|
|
||||||
if (opcode != REP_PREFIX && opcode != REPNE_PREFIX)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we can read the next byte
|
|
||||||
if (!Decoder.CanReadByte())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the next byte is a string instruction
|
|
||||||
byte nextByte = Decoder.PeakByte();
|
|
||||||
return StringInstructions.ContainsKey(nextByte);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -123,59 +164,19 @@ public class StringInstructionHandler : InstructionHandler
|
|||||||
/// <returns>True if the instruction was successfully decoded</returns>
|
/// <returns>True if the instruction was successfully decoded</returns>
|
||||||
public override bool Decode(byte opcode, Instruction instruction)
|
public override bool Decode(byte opcode, Instruction instruction)
|
||||||
{
|
{
|
||||||
// Check if this is a REP/REPNE prefix
|
// Select the appropriate dictionary based on operand size prefix
|
||||||
bool hasRepPrefix = opcode == REP_PREFIX || opcode == REPNE_PREFIX;
|
var instructionsDict = Decoder.HasOperandSizePrefix()
|
||||||
|
? StringInstructions16
|
||||||
// If this is a REP/REPNE prefix, get the actual string instruction opcode
|
: StringInstructions32;
|
||||||
byte stringOpcode = opcode;
|
|
||||||
|
|
||||||
if (hasRepPrefix)
|
|
||||||
{
|
|
||||||
// Read the next byte (the actual string instruction opcode)
|
|
||||||
if (!Decoder.CanReadByte())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringOpcode = Decoder.ReadByte();
|
|
||||||
|
|
||||||
if (!StringInstructions.ContainsKey(stringOpcode))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the instruction type and operands for the string instruction
|
// Get the instruction type and operands for the string instruction
|
||||||
if (StringInstructions.TryGetValue(stringOpcode, out var instructionInfo))
|
if (instructionsDict.TryGetValue(opcode, out var instructionInfo))
|
||||||
{
|
{
|
||||||
// Set the instruction type based on whether there's a REP/REPNE prefix
|
// Set the instruction type
|
||||||
if (hasRepPrefix)
|
instruction.Type = instructionInfo.Type;
|
||||||
{
|
|
||||||
// Determine the appropriate prefixed instruction type based on the prefix
|
|
||||||
if (opcode == REP_PREFIX)
|
|
||||||
{
|
|
||||||
// Use the REP prefix map to get the prefixed instruction type
|
|
||||||
instruction.Type = RepPrefixMap.TryGetValue(instructionInfo.Type, out var repType)
|
|
||||||
? repType
|
|
||||||
: instructionInfo.Type;
|
|
||||||
}
|
|
||||||
else // REPNE prefix
|
|
||||||
{
|
|
||||||
// Use the REPNE prefix map to get the prefixed instruction type
|
|
||||||
instruction.Type = RepnePrefixMap.TryGetValue(instructionInfo.Type, out var repneType)
|
|
||||||
? repneType
|
|
||||||
: instructionInfo.Type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No prefix, use the original instruction type
|
|
||||||
instruction.Type = instructionInfo.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and set the structured operands
|
// Create and set the structured operands
|
||||||
instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
|
instruction.StructuredOperands = instructionInfo.CreateOperands().ToList();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +101,6 @@ public enum InstructionType
|
|||||||
// Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues
|
// Lods = LodsD, // Alias for LodsD - removed alias to avoid switch expression issues
|
||||||
|
|
||||||
// REP prefixed instructions
|
// REP prefixed instructions
|
||||||
Rep, // REP prefix
|
|
||||||
RepE, // REPE/REPZ prefix
|
|
||||||
RepNE, // REPNE/REPNZ prefix
|
|
||||||
// RepneScas = RepNE, // Alias for RepNE - removed alias to avoid switch expression issues
|
// RepneScas = RepNE, // Alias for RepNE - removed alias to avoid switch expression issues
|
||||||
RepMovsB, // REP MOVSB
|
RepMovsB, // REP MOVSB
|
||||||
RepMovsW, // REP MOVSW
|
RepMovsW, // REP MOVSW
|
||||||
|
@ -271,8 +271,8 @@ public class ModRMDecoder
|
|||||||
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
|
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
|
||||||
|
|
||||||
// Map the ModR/M register indices to RegisterIndex enum values
|
// Map the ModR/M register indices to RegisterIndex enum values
|
||||||
RegisterIndex reg = RegisterMapper.MapModRMToRegisterIndex(regIndex);
|
RegisterIndex reg = (RegisterIndex)regIndex;
|
||||||
RegisterIndex rm = RegisterMapper.MapModRMToRegisterIndex(rmIndex);
|
RegisterIndex rm = (RegisterIndex)rmIndex;
|
||||||
|
|
||||||
// Create the operand based on the mod and rm fields
|
// Create the operand based on the mod and rm fields
|
||||||
Operand operand = DecodeModRM(mod, rm, is64Bit);
|
Operand operand = DecodeModRM(mod, rm, is64Bit);
|
||||||
@ -299,8 +299,8 @@ public class ModRMDecoder
|
|||||||
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
|
byte rmIndex = (byte)(modRM & Constants.RM_MASK);
|
||||||
|
|
||||||
// Map the ModR/M register indices to RegisterIndex8 enum values
|
// Map the ModR/M register indices to RegisterIndex8 enum values
|
||||||
RegisterIndex8 reg = RegisterMapper.MapModRMToRegisterIndex8(regIndex);
|
RegisterIndex8 reg = (RegisterIndex8)regIndex;
|
||||||
RegisterIndex8 rm = RegisterMapper.MapModRMToRegisterIndex8(rmIndex);
|
RegisterIndex8 rm = (RegisterIndex8)rmIndex;
|
||||||
|
|
||||||
// Create the operand based on the mod and rm fields
|
// Create the operand based on the mod and rm fields
|
||||||
Operand operand;
|
Operand operand;
|
||||||
@ -315,7 +315,7 @@ public class ModRMDecoder
|
|||||||
// For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers
|
// For memory operands, we need to map the RegisterIndex8 to RegisterIndex for base registers
|
||||||
// The rmIndex is the raw value from the ModR/M byte, not the mapped RegisterIndex8
|
// The rmIndex is the raw value from the ModR/M byte, not the mapped RegisterIndex8
|
||||||
// This is important because we need to check if it's 4 (ESP) for SIB byte
|
// This is important because we need to check if it's 4 (ESP) for SIB byte
|
||||||
RegisterIndex rmRegIndex = RegisterMapper.MapModRMToRegisterIndex(rmIndex);
|
RegisterIndex rmRegIndex = (RegisterIndex)rmIndex;
|
||||||
|
|
||||||
// Use the DecodeModRM8 method to get an 8-bit memory operand
|
// Use the DecodeModRM8 method to get an 8-bit memory operand
|
||||||
operand = DecodeModRM8(mod, rmRegIndex);
|
operand = DecodeModRM8(mod, rmRegIndex);
|
||||||
|
@ -1,76 +1,10 @@
|
|||||||
namespace X86Disassembler.X86;
|
namespace X86Disassembler.X86;
|
||||||
|
|
||||||
using Operands;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles mapping between register indices and register enums
|
/// Handles mapping between register indices and register enums
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RegisterMapper
|
public static class RegisterMapper
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Maps the register index from the ModR/M byte to the RegisterIndex enum value
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="modRMRegIndex">The register index from the ModR/M byte (0-7)</param>
|
|
||||||
/// <returns>The corresponding RegisterIndex enum value</returns>
|
|
||||||
public static RegisterIndex MapModRMToRegisterIndex(int modRMRegIndex)
|
|
||||||
{
|
|
||||||
// The mapping from ModR/M register index to RegisterIndex enum is:
|
|
||||||
// 0 -> A (EAX)
|
|
||||||
// 1 -> C (ECX)
|
|
||||||
// 2 -> D (EDX)
|
|
||||||
// 3 -> B (EBX)
|
|
||||||
// 4 -> Sp (ESP)
|
|
||||||
// 5 -> Bp (EBP)
|
|
||||||
// 6 -> Si (ESI)
|
|
||||||
// 7 -> Di (EDI)
|
|
||||||
return modRMRegIndex switch
|
|
||||||
{
|
|
||||||
0 => RegisterIndex.A, // EAX
|
|
||||||
1 => RegisterIndex.C, // ECX
|
|
||||||
2 => RegisterIndex.D, // EDX
|
|
||||||
3 => RegisterIndex.B, // EBX
|
|
||||||
4 => RegisterIndex.Sp, // ESP
|
|
||||||
5 => RegisterIndex.Bp, // EBP
|
|
||||||
6 => RegisterIndex.Si, // ESI
|
|
||||||
7 => RegisterIndex.Di, // EDI
|
|
||||||
_ => RegisterIndex.A // Default to EAX
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maps the register index from the ModR/M byte to the RegisterIndex8 enum value
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="modRMRegIndex">The register index from the ModR/M byte (0-7)</param>
|
|
||||||
/// <returns>The corresponding RegisterIndex8 enum value</returns>
|
|
||||||
public static RegisterIndex8 MapModRMToRegisterIndex8(int modRMRegIndex)
|
|
||||||
{
|
|
||||||
// The mapping from ModR/M register index to RegisterIndex8 enum is direct:
|
|
||||||
// 0 -> AL, 1 -> CL, 2 -> DL, 3 -> BL, 4 -> AH, 5 -> CH, 6 -> DH, 7 -> BH
|
|
||||||
return (RegisterIndex8)modRMRegIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maps a RegisterIndex8 enum value to the corresponding RegisterIndex enum value for base registers
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="regIndex8">The RegisterIndex8 enum value</param>
|
|
||||||
/// <returns>The corresponding RegisterIndex enum value</returns>
|
|
||||||
public static RegisterIndex MapRegister8ToBaseRegister(RegisterIndex8 regIndex8)
|
|
||||||
{
|
|
||||||
// Map 8-bit register indices to their corresponding 32-bit register indices
|
|
||||||
return regIndex8 switch
|
|
||||||
{
|
|
||||||
RegisterIndex8.AL => RegisterIndex.A,
|
|
||||||
RegisterIndex8.CL => RegisterIndex.C,
|
|
||||||
RegisterIndex8.DL => RegisterIndex.D,
|
|
||||||
RegisterIndex8.BL => RegisterIndex.B,
|
|
||||||
RegisterIndex8.AH => RegisterIndex.A,
|
|
||||||
RegisterIndex8.CH => RegisterIndex.C,
|
|
||||||
RegisterIndex8.DH => RegisterIndex.D,
|
|
||||||
RegisterIndex8.BH => RegisterIndex.B,
|
|
||||||
_ => RegisterIndex.A // Default to EAX
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the register name based on the register index and size
|
/// Gets the register name based on the register index and size
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -34,8 +34,8 @@ public class SIBDecoder
|
|||||||
int baseIndex = sib & Constants.SIB_BASE_MASK;
|
int baseIndex = sib & Constants.SIB_BASE_MASK;
|
||||||
|
|
||||||
// Map the SIB register indices to RegisterIndex enum values
|
// Map the SIB register indices to RegisterIndex enum values
|
||||||
RegisterIndex index = RegisterMapper.MapModRMToRegisterIndex(indexIndex);
|
RegisterIndex index = (RegisterIndex)indexIndex;
|
||||||
RegisterIndex @base = RegisterMapper.MapModRMToRegisterIndex(baseIndex);
|
RegisterIndex @base = (RegisterIndex)baseIndex;
|
||||||
|
|
||||||
// Special case: ESP/SP (4) in index field means no index register
|
// Special case: ESP/SP (4) in index field means no index register
|
||||||
if (index == RegisterIndex.Sp)
|
if (index == RegisterIndex.Sp)
|
||||||
|
@ -24,7 +24,7 @@ public class Int3InstructionTests
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(instruction);
|
Assert.NotNull(instruction);
|
||||||
Assert.Equal(InstructionType.Int, instruction.Type);
|
Assert.Equal(InstructionType.Int3, instruction.Type);
|
||||||
|
|
||||||
// Check that we have no operands
|
// Check that we have no operands
|
||||||
Assert.Empty(instruction.StructuredOperands);
|
Assert.Empty(instruction.StructuredOperands);
|
||||||
|
@ -154,9 +154,9 @@ public class StringInstructionHandlerTests
|
|||||||
|
|
||||||
// Check the second operand (AL)
|
// Check the second operand (AL)
|
||||||
var alOperand = instruction.StructuredOperands[1];
|
var alOperand = instruction.StructuredOperands[1];
|
||||||
Assert.IsType<RegisterOperand>(alOperand);
|
Assert.IsType<Register8Operand>(alOperand);
|
||||||
var registerOperand = (RegisterOperand)alOperand;
|
var registerOperand = (Register8Operand)alOperand;
|
||||||
Assert.Equal(RegisterIndex.A, registerOperand.Register);
|
Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
|
||||||
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
|
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,9 +223,9 @@ public class StringInstructionHandlerTests
|
|||||||
|
|
||||||
// Check the first operand (AL)
|
// Check the first operand (AL)
|
||||||
var alOperand = instruction.StructuredOperands[0];
|
var alOperand = instruction.StructuredOperands[0];
|
||||||
Assert.IsType<RegisterOperand>(alOperand);
|
Assert.IsType<Register8Operand>(alOperand);
|
||||||
var registerOperand = (RegisterOperand)alOperand;
|
var registerOperand = (Register8Operand)alOperand;
|
||||||
Assert.Equal(RegisterIndex.A, registerOperand.Register);
|
Assert.Equal(RegisterIndex8.AL, registerOperand.Register);
|
||||||
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
|
Assert.Equal(8, registerOperand.Size); // Validate that it's an 8-bit register (AL)
|
||||||
|
|
||||||
// Check the second operand (memory operand)
|
// Check the second operand (memory operand)
|
||||||
|
@ -16,8 +16,8 @@ C2FFFF;[{ "Type": "Ret", "Operands": ["0xFFFF"] }]
|
|||||||
CB;[{ "Type": "Retf", "Operands": [] }]
|
CB;[{ "Type": "Retf", "Operands": [] }]
|
||||||
|
|
||||||
# RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack
|
# RETF imm16 (opcode CA) - Far return to calling procedure and pop imm16 bytes from stack
|
||||||
CA0000;[{ "Type": "Retf", "Operands": ["0x0000"] }]
|
CA0000;[{ "Type": "Retf", "Operands": ["0x00"] }]
|
||||||
CA0400;[{ "Type": "Retf", "Operands": ["0x0004"] }]
|
CA0400;[{ "Type": "Retf", "Operands": ["0x04"] }]
|
||||||
CA0800;[{ "Type": "Retf", "Operands": ["0x0008"] }]
|
CA0800;[{ "Type": "Retf", "Operands": ["0x08"] }]
|
||||||
CA1000;[{ "Type": "Retf", "Operands": ["0x0010"] }]
|
CA1000;[{ "Type": "Retf", "Operands": ["0x10"] }]
|
||||||
CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }]
|
CAFFFF;[{ "Type": "Retf", "Operands": ["0xFFFF"] }]
|
||||||
|
Can't render this file because it contains an unexpected character in line 6 and column 7.
|
@ -12,7 +12,7 @@ RawBytes;Instructions
|
|||||||
83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }]
|
83D842;[{ "Type": "Sbb", "Operands": ["eax", "0x42"] }]
|
||||||
|
|
||||||
# SBB with memory operands
|
# SBB with memory operands
|
||||||
811C2578563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }]
|
811878563412;[{ "Type": "Sbb", "Operands": ["dword ptr [eax]", "0x12345678"] }]
|
||||||
|
|
||||||
# SBB r/m32, r32 (opcode 19)
|
# SBB r/m32, r32 (opcode 19)
|
||||||
19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }]
|
19D8;[{ "Type": "Sbb", "Operands": ["eax", "ebx"] }]
|
||||||
|
Can't render this file because it contains an unexpected character in line 6 and column 11.
|
@ -18,9 +18,9 @@ AF;[{ "Type": "ScasD", "Operands": ["eax", "dword ptr es:[edi]"] }]
|
|||||||
66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }]
|
66AF;[{ "Type": "ScasW", "Operands": ["ax", "word ptr es:[edi]"] }]
|
||||||
|
|
||||||
# LODS - Load string
|
# LODS - Load string
|
||||||
AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr es:[esi]"] }]
|
AC;[{ "Type": "LodsB", "Operands": ["al", "byte ptr ds:[esi]"] }]
|
||||||
AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr es:[esi]"] }]
|
AD;[{ "Type": "LodsD", "Operands": ["eax", "dword ptr ds:[esi]"] }]
|
||||||
66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr es:[esi]"] }]
|
66AD;[{ "Type": "LodsW", "Operands": ["ax", "byte ptr ds:[esi]"] }]
|
||||||
|
|
||||||
# STOS - Store string
|
# STOS - Store string
|
||||||
AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }]
|
AA;[{ "Type": "StosB", "Operands": ["byte ptr es:[edi]", "al"] }]
|
||||||
|
Can't render this file because it contains an unexpected character in line 6 and column 7.
|
Loading…
x
Reference in New Issue
Block a user