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