mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-19 11:51:17 +03:00
Added support for far call instructions and PUSH imm16. Fixed invalid test cases in call_tests.csv and or_tests.csv
This commit is contained in:
parent
089fe4dfd4
commit
fa1a7f582c
@ -137,8 +137,9 @@ public class InstructionHandlerFactory
|
|||||||
private void RegisterCallHandlers()
|
private void RegisterCallHandlers()
|
||||||
{
|
{
|
||||||
// Add Call handlers
|
// Add Call handlers
|
||||||
_handlers.Add(new CallRel32Handler(_decoder));
|
_handlers.Add(new CallRel32Handler(_decoder)); // CALL rel32 (opcode E8)
|
||||||
_handlers.Add(new CallRm32Handler(_decoder));
|
_handlers.Add(new CallRm32Handler(_decoder)); // CALL r/m32 (opcode FF /2)
|
||||||
|
_handlers.Add(new CallFarPtrHandler(_decoder)); // CALL m16:32 (opcode FF /3) - Far call
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -378,6 +379,7 @@ public class InstructionHandlerFactory
|
|||||||
|
|
||||||
// Add PUSH immediate handlers
|
// Add PUSH immediate handlers
|
||||||
_handlers.Add(new PushImm32Handler(_decoder)); // PUSH imm32 (opcode 68)
|
_handlers.Add(new PushImm32Handler(_decoder)); // PUSH imm32 (opcode 68)
|
||||||
|
_handlers.Add(new PushImm16Handler(_decoder)); // PUSH imm16 with operand size prefix (0x66 0x68)
|
||||||
_handlers.Add(new PushImm8Handler(_decoder)); // PUSH imm8 (opcode 6A)
|
_handlers.Add(new PushImm8Handler(_decoder)); // PUSH imm8 (opcode 6A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
67
X86Disassembler/X86/Handlers/Push/PushImm16Handler.cs
Normal file
67
X86Disassembler/X86/Handlers/Push/PushImm16Handler.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
namespace X86Disassembler.X86.Handlers.Push;
|
||||||
|
|
||||||
|
using Operands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for PUSH imm16 instruction with operand size prefix (0x66 0x68)
|
||||||
|
/// </summary>
|
||||||
|
public class PushImm16Handler : InstructionHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PushImm16Handler class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||||
|
public PushImm16Handler(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)
|
||||||
|
{
|
||||||
|
// Check for operand size prefix (66h) followed by PUSH imm (68h)
|
||||||
|
if (opcode != 0x68)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have an operand size prefix
|
||||||
|
return Decoder.HasOperandSizePrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes a PUSH 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.Push;
|
||||||
|
|
||||||
|
// Check if we have enough bytes for the 16-bit immediate
|
||||||
|
if(!Decoder.CanReadUShort())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the 16-bit immediate value
|
||||||
|
ushort imm16 = Decoder.ReadUInt16();
|
||||||
|
|
||||||
|
// Create an immediate operand with 16-bit size
|
||||||
|
var immOperand = new ImmediateOperand(imm16, 16);
|
||||||
|
|
||||||
|
// Set the structured operands
|
||||||
|
instruction.StructuredOperands =
|
||||||
|
[
|
||||||
|
immOperand
|
||||||
|
];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
206
X86Disassembler/X86/Operands/FarPointerOperand.cs
Normal file
206
X86Disassembler/X86/Operands/FarPointerOperand.cs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
namespace X86Disassembler.X86.Operands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a far pointer memory operand (m16:32) in an x86 instruction
|
||||||
|
/// </summary>
|
||||||
|
public class FarPointerOperand : MemoryOperand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the base register (if any)
|
||||||
|
/// </summary>
|
||||||
|
public RegisterIndex? BaseRegister { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index register (if any)
|
||||||
|
/// </summary>
|
||||||
|
public RegisterIndex? IndexRegister { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scale factor (if using an index register)
|
||||||
|
/// </summary>
|
||||||
|
public int Scale { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the displacement value (if any)
|
||||||
|
/// </summary>
|
||||||
|
public long Displacement { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the direct memory address (if any)
|
||||||
|
/// </summary>
|
||||||
|
public long? Address { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the FarPointerOperand class for base register memory operands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseRegister">The base register</param>
|
||||||
|
/// <param name="segmentOverride">Optional segment override</param>
|
||||||
|
public FarPointerOperand(RegisterIndex baseRegister, string? segmentOverride = null)
|
||||||
|
: base(48, segmentOverride)
|
||||||
|
{
|
||||||
|
Type = OperandType.MemoryBaseReg;
|
||||||
|
BaseRegister = baseRegister;
|
||||||
|
IndexRegister = null;
|
||||||
|
Scale = 1;
|
||||||
|
Displacement = 0;
|
||||||
|
Address = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the FarPointerOperand class for displacement memory operands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseRegister">The base register</param>
|
||||||
|
/// <param name="displacement">The displacement value</param>
|
||||||
|
/// <param name="segmentOverride">Optional segment override</param>
|
||||||
|
public FarPointerOperand(RegisterIndex baseRegister, long displacement, string? segmentOverride = null)
|
||||||
|
: base(48, segmentOverride)
|
||||||
|
{
|
||||||
|
Type = OperandType.MemoryBaseRegPlusOffset;
|
||||||
|
BaseRegister = baseRegister;
|
||||||
|
IndexRegister = null;
|
||||||
|
Scale = 1;
|
||||||
|
Displacement = displacement;
|
||||||
|
Address = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the FarPointerOperand class for scaled index memory operands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indexRegister">The index register</param>
|
||||||
|
/// <param name="scale">The scale factor</param>
|
||||||
|
/// <param name="baseRegister">The optional base register</param>
|
||||||
|
/// <param name="displacement">The displacement value</param>
|
||||||
|
/// <param name="segmentOverride">Optional segment override</param>
|
||||||
|
public FarPointerOperand(RegisterIndex indexRegister, int scale, RegisterIndex? baseRegister = null, long displacement = 0, string? segmentOverride = null)
|
||||||
|
: base(48, segmentOverride)
|
||||||
|
{
|
||||||
|
Type = OperandType.MemoryIndexed;
|
||||||
|
BaseRegister = baseRegister;
|
||||||
|
IndexRegister = indexRegister;
|
||||||
|
Scale = scale;
|
||||||
|
Displacement = displacement;
|
||||||
|
Address = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the FarPointerOperand class for direct memory operands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The memory address</param>
|
||||||
|
/// <param name="segmentOverride">Optional segment override</param>
|
||||||
|
public FarPointerOperand(long address, string? segmentOverride = null)
|
||||||
|
: base(48, segmentOverride)
|
||||||
|
{
|
||||||
|
Type = OperandType.MemoryDirect;
|
||||||
|
BaseRegister = null;
|
||||||
|
IndexRegister = null;
|
||||||
|
Scale = 1;
|
||||||
|
Displacement = 0;
|
||||||
|
Address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a FarPointerOperand from an existing memory operand
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryOperand">The memory operand to convert</param>
|
||||||
|
/// <returns>A new FarPointerOperand with the same properties</returns>
|
||||||
|
public static FarPointerOperand FromMemoryOperand(MemoryOperand memoryOperand)
|
||||||
|
{
|
||||||
|
// Create the appropriate type of FarPointerOperand based on the source operand type
|
||||||
|
if (memoryOperand is BaseRegisterMemoryOperand baseRegMemOperand)
|
||||||
|
{
|
||||||
|
return new FarPointerOperand(baseRegMemOperand.BaseRegister, memoryOperand.SegmentOverride);
|
||||||
|
}
|
||||||
|
else if (memoryOperand is DisplacementMemoryOperand dispMemOperand)
|
||||||
|
{
|
||||||
|
return new FarPointerOperand(dispMemOperand.BaseRegister, dispMemOperand.Displacement, memoryOperand.SegmentOverride);
|
||||||
|
}
|
||||||
|
else if (memoryOperand is DirectMemoryOperand directMemOperand)
|
||||||
|
{
|
||||||
|
return new FarPointerOperand(directMemOperand.Address, memoryOperand.SegmentOverride);
|
||||||
|
}
|
||||||
|
else if (memoryOperand is ScaledIndexMemoryOperand sibMemOperand)
|
||||||
|
{
|
||||||
|
return new FarPointerOperand(sibMemOperand.IndexRegister, sibMemOperand.Scale, sibMemOperand.BaseRegister, sibMemOperand.Displacement, memoryOperand.SegmentOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default case - shouldn't happen if all memory operand types are handled above
|
||||||
|
throw new System.ArgumentException("Unsupported memory operand type", nameof(memoryOperand));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this operand
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string prefix = "fword ptr ";
|
||||||
|
|
||||||
|
// Add segment override if present
|
||||||
|
if (SegmentOverride != null)
|
||||||
|
{
|
||||||
|
prefix = $"{prefix}{SegmentOverride}:";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format based on operand type
|
||||||
|
return Type switch
|
||||||
|
{
|
||||||
|
OperandType.MemoryBaseReg => $"{prefix}[{RegisterMapper.GetRegisterName(BaseRegister!.Value, 32)}]",
|
||||||
|
|
||||||
|
OperandType.MemoryBaseRegPlusOffset => $"{prefix}[{RegisterMapper.GetRegisterName(BaseRegister!.Value, 32)}+0x{Displacement:X}]",
|
||||||
|
|
||||||
|
OperandType.MemoryDirect => $"{prefix}[0x{Address!.Value:X}]",
|
||||||
|
|
||||||
|
OperandType.MemoryIndexed => FormatSIBString(prefix),
|
||||||
|
|
||||||
|
_ => $"{prefix}[unknown]"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats the string representation for SIB addressing mode
|
||||||
|
/// </summary>
|
||||||
|
private string FormatSIBString(string prefix)
|
||||||
|
{
|
||||||
|
string result = prefix + "[";
|
||||||
|
|
||||||
|
// Add base register if present
|
||||||
|
if (BaseRegister.HasValue)
|
||||||
|
{
|
||||||
|
result += RegisterMapper.GetRegisterName(BaseRegister.Value, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add index register with scale if present
|
||||||
|
if (IndexRegister.HasValue)
|
||||||
|
{
|
||||||
|
// Add + if we already have a base register
|
||||||
|
if (BaseRegister.HasValue)
|
||||||
|
{
|
||||||
|
result += "+";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += RegisterMapper.GetRegisterName(IndexRegister.Value, 32);
|
||||||
|
|
||||||
|
// Add scale if not 1
|
||||||
|
if (Scale > 1)
|
||||||
|
{
|
||||||
|
result += $"*{Scale}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add displacement if non-zero
|
||||||
|
if (Displacement != 0)
|
||||||
|
{
|
||||||
|
// Format as signed value
|
||||||
|
if (Displacement > 0)
|
||||||
|
{
|
||||||
|
result += $"+0x{Displacement:X}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += $"-0x{-Displacement:X}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += "]";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -27,11 +27,13 @@ public abstract class MemoryOperand : Operand
|
|||||||
/// <returns>The size prefix string</returns>
|
/// <returns>The size prefix string</returns>
|
||||||
protected string GetSizePrefix()
|
protected string GetSizePrefix()
|
||||||
{
|
{
|
||||||
|
// Use size-based prefix
|
||||||
string sizePrefix = Size switch
|
string sizePrefix = Size switch
|
||||||
{
|
{
|
||||||
8 => "byte ptr ",
|
8 => "byte ptr ",
|
||||||
16 => "word ptr ",
|
16 => "word ptr ",
|
||||||
32 => "dword ptr ",
|
32 => "dword ptr ",
|
||||||
|
48 => "fword ptr ",
|
||||||
64 => "qword ptr ",
|
64 => "qword ptr ",
|
||||||
_ => ""
|
_ => ""
|
||||||
};
|
};
|
||||||
|
@ -209,4 +209,15 @@ public static class OperandFactory
|
|||||||
{
|
{
|
||||||
return new FPURegisterOperand(registerIndex);
|
return new FPURegisterOperand(registerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a far pointer operand from an existing memory operand
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryOperand">The memory operand to convert to a far pointer</param>
|
||||||
|
/// <returns>A far pointer operand with the same addressing mode as the given memory operand</returns>
|
||||||
|
public static FarPointerOperand CreateFarPointerOperand(MemoryOperand memoryOperand)
|
||||||
|
{
|
||||||
|
// Create a new FarPointerOperand with the same properties as the given memory operand
|
||||||
|
return FarPointerOperand.FromMemoryOperand(memoryOperand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,14 @@ FF549DFF;[{ "Type": "Call", "Operands": ["dword ptr [ebp+ebx*4-0x01]"] }]
|
|||||||
|
|
||||||
# CALL m16:32 (opcode FF /3) - Far call with memory operand
|
# CALL m16:32 (opcode FF /3) - Far call with memory operand
|
||||||
FF1C;[{ "Type": "Call", "Operands": ["fword ptr [esp]"] }]
|
FF1C;[{ "Type": "Call", "Operands": ["fword ptr [esp]"] }]
|
||||||
FF1D;[{ "Type": "Call", "Operands": ["fword ptr [ebp]"] }]
|
# SPECIAL CASE in x86 encoding:
|
||||||
|
# When Mod=00 and R/M=101 (EBP), this doesn't actually refer to [EBP] but instead indicates
|
||||||
|
# a 32-bit displacement-only addressing mode. The correct encoding for "Call fword ptr [ebp]"
|
||||||
|
# would be FF5D00 which is "Call fword ptr [ebp+0x0]"
|
||||||
|
# FF1D;[{ "Type": "Call", "Operands": ["fword ptr [ebp]"] }]
|
||||||
|
|
||||||
|
# Correct encoding for "Call fword ptr [ebp]" with displacement 0
|
||||||
|
FF5D00;[{ "Type": "Call", "Operands": ["fword ptr [ebp+0x0]"] }]
|
||||||
FF1E;[{ "Type": "Call", "Operands": ["fword ptr [esi]"] }]
|
FF1E;[{ "Type": "Call", "Operands": ["fword ptr [esi]"] }]
|
||||||
FF1F;[{ "Type": "Call", "Operands": ["fword ptr [edi]"] }]
|
FF1F;[{ "Type": "Call", "Operands": ["fword ptr [edi]"] }]
|
||||||
FF18;[{ "Type": "Call", "Operands": ["fword ptr [eax]"] }]
|
FF18;[{ "Type": "Call", "Operands": ["fword ptr [eax]"] }]
|
||||||
|
Can't render this file because it contains an unexpected character in line 6 and column 15.
|
@ -12,7 +12,12 @@ RawBytes;Instructions
|
|||||||
83C842;[{ "Type": "Or", "Operands": ["eax", "0x42"] }]
|
83C842;[{ "Type": "Or", "Operands": ["eax", "0x42"] }]
|
||||||
|
|
||||||
# OR with memory operands
|
# OR with memory operands
|
||||||
810C2578563412;[{ "Type": "Or", "Operands": ["dword ptr [eax]", "0x12345678"] }]
|
# INVALID TEST: The following test has an invalid encoding.
|
||||||
|
# When ModR/M byte has R/M=100 (ESP), a SIB byte is required.
|
||||||
|
# 810C2578563412;[{ "Type": "Or", "Operands": ["dword ptr [eax]", "0x12345678"] }]
|
||||||
|
|
||||||
|
# Correct encoding for "Or dword ptr [eax], 0x12345678"
|
||||||
|
810878563412;[{ "Type": "Or", "Operands": ["dword ptr [eax]", "0x12345678"] }]
|
||||||
|
|
||||||
# OR r/m32, r32 (opcode 09)
|
# OR r/m32, r32 (opcode 09)
|
||||||
09D8;[{ "Type": "Or", "Operands": ["eax", "ebx"] }]
|
09D8;[{ "Type": "Or", "Operands": ["eax", "ebx"] }]
|
||||||
|
Can't render this file because it contains an unexpected character in line 6 and column 11.
|
Loading…
x
Reference in New Issue
Block a user