mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2025-05-21 04:41:18 +03:00
Refactor instruction handlers to use single instruction per handler pattern
This commit is contained in:
parent
82ffd51a3e
commit
58a148ebd8
@ -1,5 +1,3 @@
|
||||
namespace X86Disassembler;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@ -7,203 +5,138 @@ using System.Collections.Generic;
|
||||
using X86Disassembler.PE;
|
||||
using X86Disassembler.X86;
|
||||
|
||||
internal class Program
|
||||
namespace X86Disassembler;
|
||||
|
||||
/// <summary>
|
||||
/// Main program class
|
||||
/// </summary>
|
||||
public class Program
|
||||
{
|
||||
// Path to the DLL file to disassemble
|
||||
private const string DllPath = @"C:\Program Files (x86)\Nikita\Iron Strategy\Terrain.dll"; // Example path, replace with your target DLL
|
||||
// Hardcoded file path for testing
|
||||
private const string FilePath = @"C:\Program Files (x86)\Nikita\Iron Strategy\Terrain.dll";
|
||||
|
||||
// Maximum number of instructions to display per section
|
||||
private const int MaxInstructionsToDisplay = 50;
|
||||
|
||||
static void Main(string[] args)
|
||||
/// <summary>
|
||||
/// Main entry point
|
||||
/// </summary>
|
||||
/// <param name="args">Command line arguments</param>
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("X86 Disassembler and Decompiler");
|
||||
Console.WriteLine("--------------------------------");
|
||||
|
||||
string filePath = DllPath;
|
||||
// Load the file
|
||||
Console.WriteLine($"Loading file: {FilePath}");
|
||||
byte[] fileBytes = File.ReadAllBytes(FilePath);
|
||||
Console.WriteLine($"Successfully loaded {FilePath}");
|
||||
Console.WriteLine($"File size: {fileBytes.Length} bytes\n");
|
||||
|
||||
Console.WriteLine($"Loading file: {filePath}");
|
||||
// Parse the PE format
|
||||
Console.WriteLine("Parsing PE format...\n");
|
||||
PEFormat peFormat = new PEFormat(fileBytes);
|
||||
peFormat.Parse();
|
||||
|
||||
try
|
||||
{
|
||||
// Load the file into memory
|
||||
byte[] fileBytes = File.ReadAllBytes(filePath);
|
||||
Console.WriteLine($"Successfully loaded {filePath}");
|
||||
Console.WriteLine($"File size: {fileBytes.Length} bytes");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Parsing PE format...");
|
||||
Console.WriteLine();
|
||||
|
||||
// Parse the PE format
|
||||
PEFormat peFormat = new PEFormat(fileBytes);
|
||||
if (!peFormat.Parse())
|
||||
{
|
||||
Console.WriteLine("Failed to parse PE file.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Display PE information
|
||||
DisplayPEInfo(peFormat);
|
||||
|
||||
// Disassemble code sections
|
||||
DisassembleCodeSections(peFormat);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Press Enter to exit...");
|
||||
Console.Read(); // Use Read instead of ReadKey to avoid errors in redirected console
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
Console.WriteLine(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays information about the PE file
|
||||
/// </summary>
|
||||
/// <param name="peFormat">The PE format object</param>
|
||||
private static void DisplayPEInfo(PEFormat peFormat)
|
||||
{
|
||||
// Print PE file information
|
||||
Console.WriteLine("PE File Information:");
|
||||
Console.WriteLine($"Architecture: {(peFormat.OptionalHeader.Is64Bit() ? "64-bit" : "32-bit")}");
|
||||
Console.WriteLine($"Entry Point: 0x{peFormat.OptionalHeader.AddressOfEntryPoint:X8}");
|
||||
Console.WriteLine($"Image Base: 0x{peFormat.OptionalHeader.ImageBase:X8}");
|
||||
Console.WriteLine($"Number of Sections: {peFormat.FileHeader.NumberOfSections}");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("\nSections:");
|
||||
for (int i = 0; i < peFormat.SectionHeaders.Count; i++)
|
||||
// Print section information
|
||||
Console.WriteLine("Sections:");
|
||||
foreach (var section in peFormat.SectionHeaders)
|
||||
{
|
||||
var section = peFormat.SectionHeaders[i];
|
||||
string flags = "";
|
||||
|
||||
// Use the section's methods to determine characteristics
|
||||
if (section.ContainsCode()) flags += "Code ";
|
||||
if (section.IsExecutable()) flags += "Exec ";
|
||||
if (section.IsReadable()) flags += "Read ";
|
||||
if (section.IsWritable()) flags += "Write";
|
||||
|
||||
Console.WriteLine($" {i}: {section.Name,-8} VA=0x{section.VirtualAddress:X8} Size={section.VirtualSize,-8} [{flags}]");
|
||||
Console.WriteLine($" {peFormat.SectionHeaders.IndexOf(section)}: {section.Name,-8} VA=0x{section.VirtualAddress:X8} Size={section.VirtualSize,-8} [{flags}]");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
// Display exported functions
|
||||
// Print export information
|
||||
if (peFormat.ExportDirectory != null)
|
||||
{
|
||||
Console.WriteLine("\nExported Functions:");
|
||||
Console.WriteLine("Exported Functions:");
|
||||
Console.WriteLine($"DLL Name: {peFormat.ExportDirectory.DllName}");
|
||||
Console.WriteLine($"Number of Functions: {peFormat.ExportDirectory.NumberOfFunctions}");
|
||||
Console.WriteLine($"Number of Names: {peFormat.ExportDirectory.NumberOfNames}");
|
||||
|
||||
for (int i = 0; i < peFormat.ExportedFunctions.Count; i++)
|
||||
{
|
||||
var function = peFormat.ExportedFunctions[i];
|
||||
Console.WriteLine($" {i}: {function.Name} (Ordinal={function.Ordinal}, RVA=0x{function.AddressRva:X8})");
|
||||
var export = peFormat.ExportedFunctions[i];
|
||||
Console.WriteLine($" {i}: {export.Name} (Ordinal={export.Ordinal}, RVA=0x{export.AddressRva:X8})");
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
// Display imported functions
|
||||
// Print import information
|
||||
if (peFormat.ImportDescriptors.Count > 0)
|
||||
{
|
||||
Console.WriteLine("\nImported Functions:");
|
||||
Console.WriteLine("Imported Functions:");
|
||||
Console.WriteLine($"Number of Imported DLLs: {peFormat.ImportDescriptors.Count}");
|
||||
|
||||
for (int i = 0; i < peFormat.ImportDescriptors.Count; i++)
|
||||
foreach (var import in peFormat.ImportDescriptors)
|
||||
{
|
||||
var descriptor = peFormat.ImportDescriptors[i];
|
||||
Console.WriteLine($" DLL: {descriptor.DllName}");
|
||||
Console.WriteLine($" DLL: {import.DllName}");
|
||||
|
||||
for (int j = 0; j < descriptor.Functions.Count; j++)
|
||||
for (int i = 0; i < import.Functions.Count; i++)
|
||||
{
|
||||
var function = descriptor.Functions[j];
|
||||
var function = import.Functions[i];
|
||||
if (function.IsOrdinal)
|
||||
{
|
||||
Console.WriteLine($" {j}: Ordinal {function.Ordinal}");
|
||||
Console.WriteLine($" {i}: Ordinal {function.Ordinal}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($" {j}: {function.Name} (Hint={function.Hint})");
|
||||
Console.WriteLine($" {i}: {function.Name} (Hint={function.Hint})");
|
||||
}
|
||||
}
|
||||
|
||||
if (i < peFormat.ImportDescriptors.Count - 1)
|
||||
{
|
||||
Console.WriteLine(); // Add a blank line between DLLs for better readability
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disassembles the code sections of the PE file
|
||||
/// </summary>
|
||||
/// <param name="peFormat">The PE format object</param>
|
||||
private static void DisassembleCodeSections(PEFormat peFormat)
|
||||
{
|
||||
|
||||
// Find code sections
|
||||
var codeSections = peFormat.SectionHeaders.FindAll(s => s.ContainsCode());
|
||||
|
||||
Console.WriteLine($"\nFound {codeSections.Count} code section(s):");
|
||||
Console.WriteLine($"Found {codeSections.Count} code section(s):");
|
||||
foreach (var section in codeSections)
|
||||
{
|
||||
Console.WriteLine($" - {section.Name}: Size={section.VirtualSize} bytes, RVA=0x{section.VirtualAddress:X8}");
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
// Disassemble each code section
|
||||
for (int i = 0; i < peFormat.SectionHeaders.Count; i++)
|
||||
// Disassemble the first code section
|
||||
if (codeSections.Count > 0)
|
||||
{
|
||||
var section = peFormat.SectionHeaders[i];
|
||||
var section = codeSections[0];
|
||||
byte[] codeBytes = peFormat.GetSectionData(peFormat.SectionHeaders.IndexOf(section));
|
||||
|
||||
// Skip non-code sections
|
||||
if (!section.ContainsCode())
|
||||
continue;
|
||||
|
||||
Console.WriteLine($"Disassembling section {section.Name} at RVA 0x{section.VirtualAddress:X8}:");
|
||||
|
||||
// Get section data using the section index
|
||||
byte[] sectionData = peFormat.GetSectionData(i);
|
||||
// Create a disassembler for the code section
|
||||
Disassembler disassembler = new Disassembler(codeBytes, section.VirtualAddress);
|
||||
|
||||
// Create a disassembler for this section
|
||||
ulong baseAddress = peFormat.OptionalHeader.ImageBase + section.VirtualAddress;
|
||||
Disassembler disassembler = new Disassembler(sectionData, baseAddress);
|
||||
// Disassemble all instructions
|
||||
var instructions = disassembler.Disassemble();
|
||||
|
||||
// Disassemble and display instructions
|
||||
int count = 0;
|
||||
int maxInstructions = MaxInstructionsToDisplay; // Use the constant
|
||||
|
||||
while (count < maxInstructions)
|
||||
// Print the first 100 instructions
|
||||
int count = Math.Min(100, instructions.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Instruction? instruction = disassembler.DisassembleNext();
|
||||
if (instruction == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Format the instruction bytes
|
||||
StringBuilder bytesStr = new StringBuilder();
|
||||
foreach (byte b in instruction.Bytes)
|
||||
{
|
||||
bytesStr.Append($"{b:X2} ");
|
||||
}
|
||||
|
||||
// Format the instruction
|
||||
// Calculate the RVA by subtracting the image base
|
||||
ulong rva = instruction.Address - peFormat.OptionalHeader.ImageBase;
|
||||
string addressStr = $"{rva:X8}";
|
||||
string bytesDisplay = bytesStr.ToString().PadRight(20); // Pad to 20 characters
|
||||
string operandsStr = string.IsNullOrEmpty(instruction.Operands) ? "" : $" {instruction.Operands}";
|
||||
|
||||
Console.WriteLine($" {addressStr} {bytesDisplay} {instruction.Mnemonic}{operandsStr}");
|
||||
|
||||
count++;
|
||||
Console.WriteLine(instructions[i]);
|
||||
}
|
||||
|
||||
if (sectionData.Length > count * 10) // If we've only shown a small portion
|
||||
// Print a summary of how many more instructions there are
|
||||
if (instructions.Count > count)
|
||||
{
|
||||
Console.WriteLine($" ... ({sectionData.Length - (count * 10)} more bytes not shown)");
|
||||
Console.WriteLine($"... ({instructions.Count - count} more bytes not shown)");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("\nPress Enter to exit...");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace X86Disassembler.X86;
|
||||
|
||||
@ -7,77 +8,62 @@ namespace X86Disassembler.X86;
|
||||
/// </summary>
|
||||
public class Disassembler
|
||||
{
|
||||
// Buffer containing the code to disassemble
|
||||
// The buffer containing the code to disassemble
|
||||
private readonly byte[] _codeBuffer;
|
||||
|
||||
// Base address for the code (RVA)
|
||||
private readonly ulong _baseAddress;
|
||||
// The length of the buffer
|
||||
private readonly int _length;
|
||||
|
||||
// Current position in the code buffer
|
||||
private int _position;
|
||||
|
||||
// Instruction decoder
|
||||
private readonly InstructionDecoder _decoder;
|
||||
// The base address of the code
|
||||
private readonly uint _baseAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Disassembler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to disassemble</param>
|
||||
/// <param name="baseAddress">The base address (RVA) of the code</param>
|
||||
public Disassembler(byte[] codeBuffer, ulong baseAddress)
|
||||
/// <param name="baseAddress">The base address of the code</param>
|
||||
public Disassembler(byte[] codeBuffer, uint baseAddress)
|
||||
{
|
||||
_codeBuffer = codeBuffer;
|
||||
_length = codeBuffer.Length;
|
||||
_baseAddress = baseAddress;
|
||||
_position = 0;
|
||||
_decoder = new InstructionDecoder(codeBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disassembles the next instruction in the code buffer
|
||||
/// </summary>
|
||||
/// <returns>The disassembled instruction, or null if the end of the buffer is reached</returns>
|
||||
public Instruction? DisassembleNext()
|
||||
{
|
||||
if (_position >= _codeBuffer.Length)
|
||||
{
|
||||
return null; // End of buffer reached
|
||||
}
|
||||
|
||||
// Create a new instruction
|
||||
Instruction instruction = new Instruction
|
||||
{
|
||||
Address = _baseAddress + (uint)_position
|
||||
};
|
||||
|
||||
// Decode the instruction
|
||||
int bytesRead = _decoder.DecodeAt(_position, instruction);
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
return null; // Failed to decode instruction
|
||||
}
|
||||
|
||||
// Update position
|
||||
_position += bytesRead;
|
||||
|
||||
return instruction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disassembles all instructions in the code buffer
|
||||
/// Disassembles the code buffer and returns the disassembled instructions
|
||||
/// </summary>
|
||||
/// <returns>A list of disassembled instructions</returns>
|
||||
public List<Instruction> DisassembleAll()
|
||||
public List<Instruction> Disassemble()
|
||||
{
|
||||
List<Instruction> instructions = new List<Instruction>();
|
||||
|
||||
// Reset position
|
||||
_position = 0;
|
||||
// Create an instruction decoder
|
||||
InstructionDecoder decoder = new InstructionDecoder(_codeBuffer, _length);
|
||||
|
||||
// Disassemble all instructions
|
||||
Instruction? instruction;
|
||||
while ((instruction = DisassembleNext()) != null)
|
||||
// Decode instructions until the end of the buffer is reached
|
||||
while (true)
|
||||
{
|
||||
int position = decoder.GetPosition();
|
||||
|
||||
// Check if we've reached the end of the buffer
|
||||
if (position >= _length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Decode the next instruction
|
||||
Instruction? instruction = decoder.DecodeInstruction();
|
||||
|
||||
// Check if decoding failed
|
||||
if (instruction == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Adjust the instruction address to include the base address
|
||||
instruction.Address += _baseAddress;
|
||||
|
||||
// Add the instruction to the list
|
||||
instructions.Add(instruction);
|
||||
}
|
||||
|
||||
|
59
X86Disassembler/X86/Handlers/CallRel32Handler.cs
Normal file
59
X86Disassembler/X86/Handlers/CallRel32Handler.cs
Normal file
@ -0,0 +1,59 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CALL rel32 instruction (0xE8)
|
||||
/// </summary>
|
||||
public class CallRel32Handler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CallRel32Handler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public CallRel32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xE8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a CALL rel32 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 mnemonic
|
||||
instruction.Mnemonic = "call";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position + 4 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the relative offset
|
||||
int offset = BitConverter.ToInt32(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 4);
|
||||
|
||||
// Calculate the target address
|
||||
uint targetAddress = (uint)(position + offset + 4);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{targetAddress:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
68
X86Disassembler/X86/Handlers/ConditionalJumpHandler.cs
Normal file
68
X86Disassembler/X86/Handlers/ConditionalJumpHandler.cs
Normal file
@ -0,0 +1,68 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for conditional jump instructions (0x70-0x7F)
|
||||
/// </summary>
|
||||
public class ConditionalJumpHandler : InstructionHandler
|
||||
{
|
||||
// Mnemonics for conditional jumps
|
||||
private static readonly string[] ConditionalJumpMnemonics = new string[]
|
||||
{
|
||||
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "jnbe",
|
||||
"js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConditionalJumpHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public ConditionalJumpHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Conditional jumps are in the range 0x70-0x7F
|
||||
return opcode >= 0x70 && opcode <= 0x7F;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a conditional jump 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)
|
||||
{
|
||||
// Get the mnemonic from the table
|
||||
int index = opcode - 0x70;
|
||||
instruction.Mnemonic = ConditionalJumpMnemonics[index];
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the relative offset
|
||||
sbyte offset = (sbyte)CodeBuffer[position];
|
||||
Decoder.SetPosition(position + 1);
|
||||
|
||||
// Calculate the target address
|
||||
uint targetAddress = (uint)(position + offset + 1);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{targetAddress:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
63
X86Disassembler/X86/Handlers/FnstswHandler.cs
Normal file
63
X86Disassembler/X86/Handlers/FnstswHandler.cs
Normal file
@ -0,0 +1,63 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for FNSTSW instruction (0xDFE0)
|
||||
/// </summary>
|
||||
public class FnstswHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FnstswHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public FnstswHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// FNSTSW is a two-byte opcode (0xDF 0xE0)
|
||||
if (opcode == 0xDF)
|
||||
{
|
||||
int position = Decoder.GetPosition();
|
||||
if (position < Length && CodeBuffer[position] == 0xE0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an FNSTSW 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)
|
||||
{
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length || CodeBuffer[position] != 0xE0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the second byte of the opcode
|
||||
Decoder.SetPosition(position + 1);
|
||||
|
||||
// Set the mnemonic and operands
|
||||
instruction.Mnemonic = "fnstsw";
|
||||
instruction.Operands = "ax";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
22
X86Disassembler/X86/Handlers/IInstructionHandler.cs
Normal file
22
X86Disassembler/X86/Handlers/IInstructionHandler.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for instruction handlers
|
||||
/// </summary>
|
||||
public interface IInstructionHandler
|
||||
{
|
||||
/// <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>
|
||||
bool CanHandle(byte opcode);
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an 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>
|
||||
bool Decode(byte opcode, Instruction instruction);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all instruction handlers
|
||||
/// Abstract base class for instruction handlers
|
||||
/// </summary>
|
||||
public abstract class InstructionHandler
|
||||
public abstract class InstructionHandler : IInstructionHandler
|
||||
{
|
||||
// Buffer containing the code to decode
|
||||
protected readonly byte[] CodeBuffer;
|
||||
|
72
X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
Normal file
72
X86Disassembler/X86/Handlers/InstructionHandlerFactory.cs
Normal file
@ -0,0 +1,72 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating instruction handlers
|
||||
/// </summary>
|
||||
public class InstructionHandlerFactory
|
||||
{
|
||||
private readonly byte[] _codeBuffer;
|
||||
private readonly InstructionDecoder _decoder;
|
||||
private readonly int _length;
|
||||
private readonly List<IInstructionHandler> _handlers = new List<IInstructionHandler>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the InstructionHandlerFactory class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this factory</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public InstructionHandlerFactory(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
{
|
||||
_codeBuffer = codeBuffer;
|
||||
_decoder = decoder;
|
||||
_length = length;
|
||||
|
||||
// Register all instruction handlers
|
||||
RegisterHandlers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers all instruction handlers
|
||||
/// </summary>
|
||||
private void RegisterHandlers()
|
||||
{
|
||||
// Register specific instruction handlers
|
||||
_handlers.Add(new RetHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new RetImmHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new JmpRel32Handler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new JmpRel8Handler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new CallRel32Handler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new XorRegMemHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new TestRegMemHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new TestAlImmHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new TestEaxImmHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new FnstswHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new ConditionalJumpHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new TwoByteConditionalJumpHandler(_codeBuffer, _decoder, _length));
|
||||
|
||||
// Register group handlers for instructions that share similar decoding logic
|
||||
_handlers.Add(new Group1Handler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new Group3Handler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new FloatingPointHandler(_codeBuffer, _decoder, _length));
|
||||
_handlers.Add(new DataTransferHandler(_codeBuffer, _decoder, _length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a handler that can decode the given opcode
|
||||
/// </summary>
|
||||
/// <param name="opcode">The opcode to decode</param>
|
||||
/// <returns>A handler that can decode the opcode, or null if no handler is found</returns>
|
||||
public IInstructionHandler? GetHandler(byte opcode)
|
||||
{
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
if (handler.CanHandle(opcode))
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
59
X86Disassembler/X86/Handlers/JmpRel32Handler.cs
Normal file
59
X86Disassembler/X86/Handlers/JmpRel32Handler.cs
Normal file
@ -0,0 +1,59 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for JMP rel32 instruction (0xE9)
|
||||
/// </summary>
|
||||
public class JmpRel32Handler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JmpRel32Handler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public JmpRel32Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xE9;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a JMP rel32 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 mnemonic
|
||||
instruction.Mnemonic = "jmp";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position + 4 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the relative offset
|
||||
int offset = BitConverter.ToInt32(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 4);
|
||||
|
||||
// Calculate the target address
|
||||
uint targetAddress = (uint)(position + offset + 4);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{targetAddress:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
59
X86Disassembler/X86/Handlers/JmpRel8Handler.cs
Normal file
59
X86Disassembler/X86/Handlers/JmpRel8Handler.cs
Normal file
@ -0,0 +1,59 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for JMP rel8 instruction (0xEB)
|
||||
/// </summary>
|
||||
public class JmpRel8Handler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the JmpRel8Handler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public JmpRel8Handler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xEB;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a JMP rel8 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 mnemonic
|
||||
instruction.Mnemonic = "jmp";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the relative offset
|
||||
sbyte offset = (sbyte)CodeBuffer[position];
|
||||
Decoder.SetPosition(position + 1);
|
||||
|
||||
// Calculate the target address
|
||||
uint targetAddress = (uint)(position + offset + 1);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{targetAddress:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
45
X86Disassembler/X86/Handlers/RetHandler.cs
Normal file
45
X86Disassembler/X86/Handlers/RetHandler.cs
Normal file
@ -0,0 +1,45 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for RET instruction (0xC3)
|
||||
/// </summary>
|
||||
public class RetHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RetHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public RetHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xC3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a RET 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 mnemonic
|
||||
instruction.Mnemonic = "ret";
|
||||
|
||||
// No operands for RET
|
||||
instruction.Operands = string.Empty;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
56
X86Disassembler/X86/Handlers/RetImmHandler.cs
Normal file
56
X86Disassembler/X86/Handlers/RetImmHandler.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for RET instruction with immediate operand (0xC2)
|
||||
/// </summary>
|
||||
public class RetImmHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the RetImmHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public RetImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xC2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a RET instruction with immediate operand
|
||||
/// </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 mnemonic
|
||||
instruction.Mnemonic = "ret";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position + 2 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the immediate value
|
||||
ushort imm16 = BitConverter.ToUInt16(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 2);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{imm16:X4}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
56
X86Disassembler/X86/Handlers/TestAlImmHandler.cs
Normal file
56
X86Disassembler/X86/Handlers/TestAlImmHandler.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for TEST AL, imm8 instruction (0xA8)
|
||||
/// </summary>
|
||||
public class TestAlImmHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TestAlImmHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public TestAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xA8;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a TEST AL, imm8 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 mnemonic
|
||||
instruction.Mnemonic = "test";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the immediate value
|
||||
byte imm8 = CodeBuffer[position];
|
||||
Decoder.SetPosition(position + 1);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"al, 0x{imm8:X2}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
56
X86Disassembler/X86/Handlers/TestEaxImmHandler.cs
Normal file
56
X86Disassembler/X86/Handlers/TestEaxImmHandler.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for TEST EAX, imm32 instruction (0xA9)
|
||||
/// </summary>
|
||||
public class TestEaxImmHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TestEaxImmHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public TestEaxImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0xA9;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a TEST EAX, imm32 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 mnemonic
|
||||
instruction.Mnemonic = "test";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position + 4 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the immediate value
|
||||
uint imm32 = BitConverter.ToUInt32(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 4);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"eax, 0x{imm32:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
82
X86Disassembler/X86/Handlers/TestRegMemHandler.cs
Normal file
82
X86Disassembler/X86/Handlers/TestRegMemHandler.cs
Normal file
@ -0,0 +1,82 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for TEST r/m32, r32 instruction (0x85)
|
||||
/// </summary>
|
||||
public class TestRegMemHandler : InstructionHandler
|
||||
{
|
||||
// ModR/M decoder
|
||||
private readonly ModRMDecoder _modRMDecoder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TestRegMemHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public TestRegMemHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
_modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0x85;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a TEST r/m32, r32 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 mnemonic
|
||||
instruction.Mnemonic = "test";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the ModR/M byte
|
||||
byte modRM = CodeBuffer[position++];
|
||||
Decoder.SetPosition(position);
|
||||
|
||||
// Extract the fields from the ModR/M byte
|
||||
byte mod = (byte)((modRM & 0xC0) >> 6);
|
||||
byte reg = (byte)((modRM & 0x38) >> 3);
|
||||
byte rm = (byte)(modRM & 0x07);
|
||||
|
||||
// Decode the destination operand
|
||||
string destOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
|
||||
|
||||
// Get the source register
|
||||
string srcReg = GetRegister32(reg);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"{destOperand}, {srcReg}";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the 32-bit register name for the given register index
|
||||
/// </summary>
|
||||
/// <param name="reg">The register index</param>
|
||||
/// <returns>The register name</returns>
|
||||
private static string GetRegister32(byte reg)
|
||||
{
|
||||
string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
|
||||
return registerNames[reg & 0x07];
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for two-byte conditional jump instructions (0x0F 0x80-0x8F)
|
||||
/// </summary>
|
||||
public class TwoByteConditionalJumpHandler : InstructionHandler
|
||||
{
|
||||
// Mnemonics for conditional jumps
|
||||
private static readonly string[] ConditionalJumpMnemonics = new string[]
|
||||
{
|
||||
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "jnbe",
|
||||
"js", "jns", "jp", "jnp", "jl", "jnl", "jle", "jnle"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TwoByteConditionalJumpHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public TwoByteConditionalJumpHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Two-byte conditional jumps start with 0x0F
|
||||
if (opcode == 0x0F)
|
||||
{
|
||||
int position = Decoder.GetPosition();
|
||||
if (position < Length)
|
||||
{
|
||||
byte secondByte = CodeBuffer[position];
|
||||
// Second byte must be in the range 0x80-0x8F
|
||||
return secondByte >= 0x80 && secondByte <= 0x8F;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a two-byte conditional jump 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)
|
||||
{
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the second byte of the opcode
|
||||
byte secondByte = CodeBuffer[position++];
|
||||
Decoder.SetPosition(position);
|
||||
|
||||
// Get the mnemonic from the table
|
||||
int index = secondByte - 0x80;
|
||||
instruction.Mnemonic = ConditionalJumpMnemonics[index];
|
||||
|
||||
if (position + 4 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the relative offset (32-bit)
|
||||
int offset = BitConverter.ToInt32(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 4);
|
||||
|
||||
// Calculate the target address
|
||||
uint targetAddress = (uint)(position + offset + 4);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"0x{targetAddress:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
56
X86Disassembler/X86/Handlers/XorAlImmHandler.cs
Normal file
56
X86Disassembler/X86/Handlers/XorAlImmHandler.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for XOR AL, imm8 instruction (0x34)
|
||||
/// </summary>
|
||||
public class XorAlImmHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the XorAlImmHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public XorAlImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0x34;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a XOR AL, imm8 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 mnemonic
|
||||
instruction.Mnemonic = "xor";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the immediate value
|
||||
byte imm8 = CodeBuffer[position];
|
||||
Decoder.SetPosition(position + 1);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"al, 0x{imm8:X2}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
56
X86Disassembler/X86/Handlers/XorEaxImmHandler.cs
Normal file
56
X86Disassembler/X86/Handlers/XorEaxImmHandler.cs
Normal file
@ -0,0 +1,56 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for XOR EAX, imm32 instruction (0x35)
|
||||
/// </summary>
|
||||
public class XorEaxImmHandler : InstructionHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the XorEaxImmHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public XorEaxImmHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0x35;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a XOR EAX, imm32 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 mnemonic
|
||||
instruction.Mnemonic = "xor";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position + 4 > Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the immediate value
|
||||
uint imm32 = BitConverter.ToUInt32(CodeBuffer, position);
|
||||
Decoder.SetPosition(position + 4);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"eax, 0x{imm32:X8}";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
82
X86Disassembler/X86/Handlers/XorMemRegHandler.cs
Normal file
82
X86Disassembler/X86/Handlers/XorMemRegHandler.cs
Normal file
@ -0,0 +1,82 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for XOR r/m32, r32 instruction (0x31)
|
||||
/// </summary>
|
||||
public class XorMemRegHandler : InstructionHandler
|
||||
{
|
||||
// ModR/M decoder
|
||||
private readonly ModRMDecoder _modRMDecoder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the XorMemRegHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public XorMemRegHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
_modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0x31;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an XOR r/m32, r32 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 mnemonic
|
||||
instruction.Mnemonic = "xor";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the ModR/M byte
|
||||
byte modRM = CodeBuffer[position++];
|
||||
Decoder.SetPosition(position);
|
||||
|
||||
// Extract the fields from the ModR/M byte
|
||||
byte mod = (byte)((modRM & 0xC0) >> 6);
|
||||
byte reg = (byte)((modRM & 0x38) >> 3);
|
||||
byte rm = (byte)(modRM & 0x07);
|
||||
|
||||
// Decode the destination operand
|
||||
string destOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
|
||||
|
||||
// Get the source register
|
||||
string srcReg = GetRegister32(reg);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"{destOperand}, {srcReg}";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the 32-bit register name for the given register index
|
||||
/// </summary>
|
||||
/// <param name="reg">The register index</param>
|
||||
/// <returns>The register name</returns>
|
||||
private static string GetRegister32(byte reg)
|
||||
{
|
||||
string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
|
||||
return registerNames[reg & 0x07];
|
||||
}
|
||||
}
|
82
X86Disassembler/X86/Handlers/XorRegMemHandler.cs
Normal file
82
X86Disassembler/X86/Handlers/XorRegMemHandler.cs
Normal file
@ -0,0 +1,82 @@
|
||||
namespace X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for XOR r32, r/m32 instruction (0x33)
|
||||
/// </summary>
|
||||
public class XorRegMemHandler : InstructionHandler
|
||||
{
|
||||
// ModR/M decoder
|
||||
private readonly ModRMDecoder _modRMDecoder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the XorRegMemHandler class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
/// <param name="decoder">The instruction decoder that owns this handler</param>
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public XorRegMemHandler(byte[] codeBuffer, InstructionDecoder decoder, int length)
|
||||
: base(codeBuffer, decoder, length)
|
||||
{
|
||||
_modRMDecoder = new ModRMDecoder(codeBuffer, decoder, length);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
return opcode == 0x33;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an XOR r32, r/m32 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 mnemonic
|
||||
instruction.Mnemonic = "xor";
|
||||
|
||||
int position = Decoder.GetPosition();
|
||||
|
||||
if (position >= Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the ModR/M byte
|
||||
byte modRM = CodeBuffer[position++];
|
||||
Decoder.SetPosition(position);
|
||||
|
||||
// Extract the fields from the ModR/M byte
|
||||
byte mod = (byte)((modRM & 0xC0) >> 6);
|
||||
byte reg = (byte)((modRM & 0x38) >> 3);
|
||||
byte rm = (byte)(modRM & 0x07);
|
||||
|
||||
// Decode the source operand
|
||||
string srcOperand = _modRMDecoder.DecodeModRM(mod, rm, false);
|
||||
|
||||
// Get the destination register
|
||||
string destReg = GetRegister32(reg);
|
||||
|
||||
// Set the operands
|
||||
instruction.Operands = $"{destReg}, {srcOperand}";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the 32-bit register name for the given register index
|
||||
/// </summary>
|
||||
/// <param name="reg">The register index</param>
|
||||
/// <returns>The register name</returns>
|
||||
private static string GetRegister32(byte reg)
|
||||
{
|
||||
string[] registerNames = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
|
||||
return registerNames[reg & 0x07];
|
||||
}
|
||||
}
|
@ -1,50 +1,56 @@
|
||||
namespace X86Disassembler.X86;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a decoded x86 instruction
|
||||
/// Represents an x86 instruction
|
||||
/// </summary>
|
||||
public class Instruction
|
||||
{
|
||||
/// <summary>
|
||||
/// The address of the instruction in memory
|
||||
/// Gets or sets the address of the instruction
|
||||
/// </summary>
|
||||
public ulong Address { get; set; }
|
||||
public uint Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw bytes of the instruction
|
||||
/// </summary>
|
||||
public byte[] Bytes { get; set; } = Array.Empty<byte>();
|
||||
|
||||
/// <summary>
|
||||
/// The mnemonic of the instruction (e.g., "mov", "add", "jmp")
|
||||
/// Gets or sets the mnemonic of the instruction
|
||||
/// </summary>
|
||||
public string Mnemonic { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The operands of the instruction as a formatted string
|
||||
/// Gets or sets the operands of the instruction
|
||||
/// </summary>
|
||||
public string Operands { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The length of the instruction in bytes
|
||||
/// Gets or sets the raw bytes of the instruction
|
||||
/// </summary>
|
||||
public int Length => Bytes.Length;
|
||||
public byte[] RawBytes { get; set; } = Array.Empty<byte>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the instruction
|
||||
/// </summary>
|
||||
/// <returns>A formatted string representing the instruction</returns>
|
||||
/// <returns>A string representation of the instruction</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Address:X8} {BytesToString()} {Mnemonic} {Operands}".Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the instruction bytes to a formatted hex string
|
||||
/// </summary>
|
||||
/// <returns>A formatted hex string of the instruction bytes</returns>
|
||||
private string BytesToString()
|
||||
{
|
||||
return string.Join(" ", Bytes.Select(b => b.ToString("X2")));
|
||||
// Format the address
|
||||
string addressStr = $"{Address:X8}";
|
||||
|
||||
// Format the raw bytes
|
||||
string bytesStr = string.Empty;
|
||||
foreach (byte b in RawBytes)
|
||||
{
|
||||
bytesStr += $"{b:X2} ";
|
||||
}
|
||||
|
||||
// Pad the bytes string to a fixed width
|
||||
bytesStr = bytesStr.PadRight(30);
|
||||
|
||||
// Format the instruction
|
||||
string instructionStr = Mnemonic;
|
||||
if (!string.IsNullOrEmpty(Operands))
|
||||
{
|
||||
instructionStr += " " + Operands;
|
||||
}
|
||||
|
||||
return $" {addressStr} {bytesStr}{instructionStr}";
|
||||
}
|
||||
}
|
||||
|
@ -3,188 +3,147 @@ namespace X86Disassembler.X86;
|
||||
using X86Disassembler.X86.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// Decodes x86 instructions
|
||||
/// Decodes x86 instructions from a byte buffer
|
||||
/// </summary>
|
||||
public class InstructionDecoder
|
||||
{
|
||||
// Instruction prefix bytes
|
||||
private const byte PREFIX_LOCK = 0xF0;
|
||||
private const byte PREFIX_REPNE = 0xF2;
|
||||
private const byte PREFIX_REP = 0xF3;
|
||||
private const byte PREFIX_CS = 0x2E;
|
||||
private const byte PREFIX_SS = 0x36;
|
||||
private const byte PREFIX_DS = 0x3E;
|
||||
private const byte PREFIX_ES = 0x26;
|
||||
private const byte PREFIX_FS = 0x64;
|
||||
private const byte PREFIX_GS = 0x65;
|
||||
private const byte PREFIX_OPERAND_SIZE = 0x66;
|
||||
private const byte PREFIX_ADDRESS_SIZE = 0x67;
|
||||
|
||||
// Buffer containing the code to decode
|
||||
// The buffer containing the code to decode
|
||||
private readonly byte[] _codeBuffer;
|
||||
|
||||
// Current position in the code buffer
|
||||
private int _position;
|
||||
|
||||
// Length of the buffer
|
||||
// The length of the buffer
|
||||
private readonly int _length;
|
||||
|
||||
// List of instruction handlers
|
||||
private readonly List<InstructionHandler> _handlers;
|
||||
// The current position in the buffer
|
||||
private int _position;
|
||||
|
||||
// The instruction handler factory
|
||||
private readonly InstructionHandlerFactory _handlerFactory;
|
||||
|
||||
// Instruction prefixes
|
||||
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 InstructionDecoder class
|
||||
/// </summary>
|
||||
/// <param name="codeBuffer">The buffer containing the code to decode</param>
|
||||
public InstructionDecoder(byte[] codeBuffer)
|
||||
/// <param name="length">The length of the buffer</param>
|
||||
public InstructionDecoder(byte[] codeBuffer, int length)
|
||||
{
|
||||
_codeBuffer = codeBuffer;
|
||||
_length = length;
|
||||
_position = 0;
|
||||
_length = codeBuffer.Length;
|
||||
_segmentOverride = string.Empty;
|
||||
|
||||
// Initialize the instruction handlers
|
||||
_handlers = new List<InstructionHandler>
|
||||
{
|
||||
new Group1Handler(_codeBuffer, this, _length),
|
||||
new FloatingPointHandler(_codeBuffer, this, _length),
|
||||
new DataTransferHandler(_codeBuffer, this, _length),
|
||||
new ControlFlowHandler(_codeBuffer, this, _length),
|
||||
new Group3Handler(_codeBuffer, this, _length),
|
||||
new TestHandler(_codeBuffer, this, _length),
|
||||
new ArithmeticHandler(_codeBuffer, this, _length)
|
||||
};
|
||||
// Create the instruction handler factory
|
||||
_handlerFactory = new InstructionHandlerFactory(_codeBuffer, this, _length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an instruction at the current position in the code buffer
|
||||
/// Decodes an instruction at the current position
|
||||
/// </summary>
|
||||
/// <param name="instruction">The instruction object to populate</param>
|
||||
/// <returns>The number of bytes read</returns>
|
||||
public int Decode(Instruction instruction)
|
||||
/// <returns>The decoded instruction, or null if the decoding failed</returns>
|
||||
public Instruction? DecodeInstruction()
|
||||
{
|
||||
// Store the starting position
|
||||
int startPosition = _position;
|
||||
|
||||
// Check if we've reached the end of the buffer
|
||||
if (_position >= _length)
|
||||
{
|
||||
return 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle instruction prefixes
|
||||
bool hasPrefix = true;
|
||||
bool operandSizePrefix = false;
|
||||
bool addressSizePrefix = false;
|
||||
string segmentOverride = string.Empty;
|
||||
// Reset prefix flags
|
||||
_operandSizePrefix = false;
|
||||
_addressSizePrefix = false;
|
||||
_segmentOverridePrefix = false;
|
||||
_lockPrefix = false;
|
||||
_repPrefix = false;
|
||||
_segmentOverride = string.Empty;
|
||||
|
||||
while (hasPrefix && _position < _length)
|
||||
// Save the start position of the instruction
|
||||
int startPosition = _position;
|
||||
|
||||
// Create a new instruction
|
||||
Instruction instruction = new Instruction
|
||||
{
|
||||
Address = (uint)startPosition,
|
||||
};
|
||||
|
||||
// Handle prefixes
|
||||
while (_position < _length)
|
||||
{
|
||||
byte prefix = _codeBuffer[_position];
|
||||
|
||||
switch (prefix)
|
||||
if (prefix == 0x66) // Operand size prefix
|
||||
{
|
||||
case PREFIX_LOCK:
|
||||
case PREFIX_REPNE:
|
||||
case PREFIX_REP:
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_CS:
|
||||
segmentOverride = "cs";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_SS:
|
||||
segmentOverride = "ss";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_DS:
|
||||
segmentOverride = "ds";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_ES:
|
||||
segmentOverride = "es";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_FS:
|
||||
segmentOverride = "fs";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_GS:
|
||||
segmentOverride = "gs";
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_OPERAND_SIZE:
|
||||
operandSizePrefix = true;
|
||||
_position++;
|
||||
break;
|
||||
|
||||
case PREFIX_ADDRESS_SIZE:
|
||||
addressSizePrefix = true;
|
||||
_position++;
|
||||
break;
|
||||
|
||||
default:
|
||||
hasPrefix = false;
|
||||
break;
|
||||
_operandSizePrefix = true;
|
||||
_position++;
|
||||
}
|
||||
else if (prefix == 0x67) // Address size prefix
|
||||
{
|
||||
_addressSizePrefix = true;
|
||||
_position++;
|
||||
}
|
||||
else if (prefix >= 0x26 && prefix <= 0x3E && (prefix & 0x7) == 0x6) // 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++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We've reached the end of the buffer after processing prefixes
|
||||
if (_position >= _length)
|
||||
{
|
||||
return _position - startPosition;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Read the opcode
|
||||
byte opcode = _codeBuffer[_position++];
|
||||
|
||||
// Try to find a handler for this opcode
|
||||
bool handled = false;
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
if (handler.CanHandle(opcode))
|
||||
{
|
||||
handled = handler.Decode(opcode, instruction);
|
||||
if (handled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get a handler for the opcode
|
||||
var handler = _handlerFactory.GetHandler(opcode);
|
||||
|
||||
// If no handler was found or the instruction couldn't be decoded,
|
||||
// use a default mnemonic from the opcode map
|
||||
if (!handled)
|
||||
if (handler == null || !handler.Decode(opcode, instruction))
|
||||
{
|
||||
// If no handler is found or decoding fails, create a default instruction
|
||||
instruction.Mnemonic = OpcodeMap.GetMnemonic(opcode);
|
||||
instruction.Operands = string.Empty;
|
||||
instruction.Operands = "??";
|
||||
}
|
||||
|
||||
// Copy the instruction bytes
|
||||
int bytesRead = _position - startPosition;
|
||||
instruction.Bytes = new byte[bytesRead];
|
||||
Array.Copy(_codeBuffer, startPosition, instruction.Bytes, 0, bytesRead);
|
||||
// Set the raw bytes
|
||||
int length = _position - startPosition;
|
||||
instruction.RawBytes = new byte[length];
|
||||
Array.Copy(_codeBuffer, startPosition, instruction.RawBytes, 0, length);
|
||||
|
||||
return bytesRead;
|
||||
return instruction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current position in the code buffer
|
||||
/// </summary>
|
||||
/// <param name="position">The new position</param>
|
||||
public void SetPosition(int position)
|
||||
{
|
||||
_position = position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current position in the code buffer
|
||||
/// Gets the current position in the buffer
|
||||
/// </summary>
|
||||
/// <returns>The current position</returns>
|
||||
public int GetPosition()
|
||||
@ -193,14 +152,111 @@ public class InstructionDecoder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an instruction at the specified position in the code buffer
|
||||
/// Sets the current position in the buffer
|
||||
/// </summary>
|
||||
/// <param name="position">The position in the code buffer</param>
|
||||
/// <param name="instruction">The instruction object to populate</param>
|
||||
/// <returns>The number of bytes read</returns>
|
||||
public int DecodeAt(int position, Instruction instruction)
|
||||
/// <param name="position">The new position</param>
|
||||
public void SetPosition(int position)
|
||||
{
|
||||
_position = position;
|
||||
return Decode(instruction);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Reads a byte from the buffer and advances the position
|
||||
/// </summary>
|
||||
/// <returns>The byte read</returns>
|
||||
public byte ReadByte()
|
||||
{
|
||||
if (_position >= _length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _codeBuffer[_position++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 16-bit value from the buffer and advances the position
|
||||
/// </summary>
|
||||
/// <returns>The 16-bit value read</returns>
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
if (_position + 1 >= _length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ushort value = BitConverter.ToUInt16(_codeBuffer, _position);
|
||||
_position += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 32-bit value from the buffer and advances the position
|
||||
/// </summary>
|
||||
/// <returns>The 32-bit value read</returns>
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
if (_position + 3 >= _length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint value = BitConverter.ToUInt32(_codeBuffer, _position);
|
||||
_position += 4;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user