private void WriteOperandValue(X86OperandType method, X86OperandSize size, X86Operand operand) { switch (method) { case X86OperandType.MemoryAddress: case X86OperandType.DirectAddress: case X86OperandType.ImmediateData: { WriteNumber(operand.Value, size); break; } case X86OperandType.RegisterOrMemoryAddress: { if ((operand.ScaledIndex != null) || (operand.OperandUsage != X86OperandUsage.Normal && operand.Value is X86Register && (X86Register)operand.Value == X86Register.Esp)) { _writer.WriteByte(ComputeRegOrMemSibToken(operand)); } else if (!(operand.Value is X86Register)) { WriteNumber(operand.Value, X86OperandSize.Dword); } break; } case X86OperandType.RelativeOffset: { WriteNumber(Convert.ToUInt32(operand.Value) - (_writer.Position + sizeof(sbyte)), size); break; } } }
private X86Operand GetRegOrMemOperand32(byte registerToken, X86OperandSize size) { // Mechanism: // http://ref.x86asm.net/coder32.html#modrm_byte_32 // ModR/M byte: // mod | reg/mem | (reg2) // -----+---------+------- // 7 6 | 5 4 3 | (2 1 0) var modifier = (X86RegOrMemModifier)(registerToken >> 6); var operand = new X86Operand(); // Register-only operands: if (modifier == X86RegOrMemModifier.RegisterOnly) { operand.Value = GetRegisterFromToken((byte)(registerToken & 0x7), GetRegisterSize(size)); operand.OperandUsage = X86OperandUsage.Normal; return(operand); } // Register-pointer operands are always 32-bit registers. var register = GetRegisterFromToken((byte)(registerToken & 0x7), X86RegisterSize.Dword); operand.OperandUsage = GetOperandType(size); operand.Value = register; // EBP register is replaced by a direct address. if (modifier == X86RegOrMemModifier.RegisterPointer && register == X86Register.Ebp) { operand.Value = _reader.ReadUInt32(); return(operand); } // ESP register are replaced by a scaled index operand. if (register == X86Register.Esp) { MakeScaledIndexOperandFromToken(operand, _reader.ReadByte()); } // Read correction based on modifier. switch (modifier) { case X86RegOrMemModifier.RegisterDispShortPointer: operand.Offset = _reader.ReadSByte(); operand.OffsetType = X86OffsetType.Short; break; case X86RegOrMemModifier.RegisterDispLongPointer: operand.Offset = _reader.ReadInt32(); operand.OffsetType = X86OffsetType.Long; break; } return(operand); }
private static X86OperandUsage GetOperandType(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return X86OperandUsage.BytePointer; case X86OperandSize.Dword: return X86OperandUsage.DwordPointer; case X86OperandSize.WordOrDword: return X86OperandUsage.DwordPointer; // TODO: use operand-size override opcode case X86OperandSize.Fword: return X86OperandUsage.FwordPointer; } throw new ArgumentException(); }
private static byte ComputeRegisterTokenPart(X86OperandType method, X86OperandSize size, X86Operand operand) { switch (method) { case X86OperandType.Register: { return (byte)(ComputeRegisterToken((X86Register)operand.Value) << 3); } case X86OperandType.RegisterOrMemoryAddress: { return ComputeRegOrMemToken(operand); } } return 0; }
private static byte ComputeRegisterTokenPart(X86OperandType method, X86OperandSize size, X86Operand operand) { switch (method) { case X86OperandType.Register: { return((byte)(ComputeRegisterToken((X86Register)operand.Value) << 3)); } case X86OperandType.RegisterOrMemoryAddress: { return(ComputeRegOrMemToken(operand)); } } return(0); }
private static int GetTotalOperandSize(X86OperandType operandType, X86OperandSize operandSize, X86Operand operand) { int size = (int)operand.OffsetType; switch (operandType) { case X86OperandType.None: case X86OperandType.ControlRegister: case X86OperandType.DebugRegister: case X86OperandType.StackRegister: case X86OperandType.Register: case X86OperandType.RegisterCl: case X86OperandType.RegisterDx: case X86OperandType.RegisterEax: case X86OperandType.RegisterAl: case X86OperandType.ImmediateOne: case X86OperandType.SegmentRegister: case X86OperandType.OpCodeRegister: break; case X86OperandType.DirectAddress: case X86OperandType.MemoryAddress: size += 4; break; case X86OperandType.RelativeOffset: case X86OperandType.ImmediateData: size += GetSize(operandSize); break; case X86OperandType.RegisterOrMemoryAddress: case X86OperandType.StackRegisterOrMemoryAddress: if ((operand.ScaledIndex != null) || (operand.OperandUsage != X86OperandUsage.Normal && operand.Value is X86Register && (X86Register)operand.Value == X86Register.Esp)) { size += 1; } if (!(operand.Value is X86Register)) { size += 4; } break; } return(size); }
private static X86RegisterSize GetRegisterSize(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(X86RegisterSize.Byte); case X86OperandSize.Word: return(X86RegisterSize.Word); case X86OperandSize.Dword: return(X86RegisterSize.Dword); case X86OperandSize.WordOrDword: return(X86RegisterSize.Dword); // TODO: use operand-size override opcode } throw new ArgumentException(); }
private static X86OperandUsage GetOperandType(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(X86OperandUsage.BytePointer); case X86OperandSize.Dword: return(X86OperandUsage.DwordPointer); case X86OperandSize.WordOrDword: return(X86OperandUsage.DwordPointer); // TODO: use operand-size override opcode case X86OperandSize.Fword: return(X86OperandUsage.FwordPointer); } throw new ArgumentException(); }
private object ReadImmediateData(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(_reader.ReadByte()); case X86OperandSize.Word: return(_reader.ReadUInt16()); case X86OperandSize.Dword: return(_reader.ReadUInt32()); case X86OperandSize.WordOrDword: return(_reader.ReadUInt32()); // TODO: use operand-size override opcode // TODO: fword } throw new NotSupportedException(); }
private static int GetSize(X86OperandSize operandSize) { switch (operandSize) { case X86OperandSize.Byte: return(1); case X86OperandSize.Word: return(2); case X86OperandSize.WordOrDword: case X86OperandSize.Dword: return(4); case X86OperandSize.Fword: return(6); } throw new NotSupportedException(); }
private X86Operand ReadOperand(X86OperandType method, X86OperandSize size, byte opcode, byte registerToken) { switch (method) { case X86OperandType.OpCodeRegister: return(new X86Operand(GetRegisterFromToken((byte)(opcode & 7), GetRegisterSize(size)))); case X86OperandType.Register: return(new X86Operand(GetRegisterFromToken((byte)((registerToken >> 3) & 7), GetRegisterSize(size)))); case X86OperandType.RegisterOrMemoryAddress: return(GetRegOrMemOperand32(registerToken, size)); case X86OperandType.ImmediateData: return(new X86Operand(ReadImmediateData(size))); case X86OperandType.MemoryAddress: return(new X86Operand(GetOperandType(size), _reader.ReadUInt32())); case X86OperandType.RegisterAl: return(new X86Operand(X86Register.Al)); case X86OperandType.RegisterCl: return(new X86Operand(X86Register.Cl)); case X86OperandType.RegisterDx: return(new X86Operand(X86Register.Dx)); case X86OperandType.RegisterEax: return(new X86Operand(X86Register.Eax)); case X86OperandType.ImmediateOne: return(new X86Operand(1)); case X86OperandType.RelativeOffset: return(new X86Operand((ulong)(Convert.ToInt64(ReadSignedImmediateData(size)) + BaseAddress + _reader.Position))); case X86OperandType.None: return(null); } throw new NotSupportedException("Unrecognized or unsupported addressing method."); }
private void WriteNumber(object value, X86OperandSize size) { switch (size) { case X86OperandSize.Byte: if (value is sbyte || value is short || value is int || value is long) { _writer.WriteSByte(Convert.ToSByte(value)); } else { _writer.WriteByte(Convert.ToByte(value)); } break; case X86OperandSize.Word: if (value is sbyte || value is short || value is int || value is long) { _writer.WriteInt16(Convert.ToInt16(value)); } else { _writer.WriteUInt16(Convert.ToUInt16(value)); } break; case X86OperandSize.WordOrDword: case X86OperandSize.Dword: if (value is sbyte || value is short || value is int || value is long) { _writer.WriteInt32(Convert.ToInt32(value)); } else { _writer.WriteUInt32(Convert.ToUInt32(value)); } break; default: throw new NotSupportedException(); } }
private object ReadImmediateData(ICollection <X86Prefix> prefixes, X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(_reader.ReadByte()); case X86OperandSize.Word: return(_reader.ReadUInt16()); case X86OperandSize.Dword: return(_reader.ReadUInt32()); case X86OperandSize.WordOrDword: return(prefixes.Contains(X86Prefixes.OperandSizeOverride) ? _reader.ReadUInt16() : _reader.ReadUInt32()); // TODO: fword } throw new NotSupportedException(); }
private static int GetSize(ICollection <X86Prefix> prefixes, X86OperandSize operandSize) { switch (operandSize) { case X86OperandSize.Byte: return(1); case X86OperandSize.Word: return(2); case X86OperandSize.WordOrDword: return(prefixes.Contains(X86Prefixes.OperandSizeOverride) ? 2 : 4); case X86OperandSize.Dword: return(4); case X86OperandSize.Fword: return(6); } throw new NotSupportedException(); }
private static X86RegisterSize GetRegisterSize(ICollection <X86Prefix> prefixes, X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(X86RegisterSize.Byte); case X86OperandSize.Word: return(X86RegisterSize.Word); case X86OperandSize.Dword: return(X86RegisterSize.Dword); case X86OperandSize.WordOrDword: return(prefixes.Contains(X86Prefixes.OperandSizeOverride) ? X86RegisterSize.Word : X86RegisterSize.Dword); } throw new ArgumentException(); }
private X86Operand GetRegOrMemOperand32(byte registerToken, X86OperandSize size) { // Mechanism: // http://ref.x86asm.net/coder32.html#modrm_byte_32 // ModR/M byte: // mod | reg/mem | (reg2) // -----+---------+------- // 7 6 | 5 4 3 | (2 1 0) var modifier = (X86RegOrMemModifier)(registerToken >> 6); var operand = new X86Operand(); // Register-only operands: if (modifier == X86RegOrMemModifier.RegisterOnly) { operand.Value = GetRegisterFromToken((byte)(registerToken & 0x7), GetRegisterSize(size)); operand.OperandUsage = X86OperandUsage.Normal; return operand; } // Register-pointer operands are always 32-bit registers. var register = GetRegisterFromToken((byte)(registerToken & 0x7), X86RegisterSize.Dword); operand.OperandUsage = GetOperandType(size); operand.Value = register; // EBP register is replaced by a direct address. if (modifier == X86RegOrMemModifier.RegisterPointer && register == X86Register.Ebp) { operand.Value = _reader.ReadUInt32(); return operand; } // ESP register are replaced by a scaled index operand. if (register == X86Register.Esp) MakeScaledIndexOperandFromToken(operand, _reader.ReadByte()); // Read correction based on modifier. switch (modifier) { case X86RegOrMemModifier.RegisterDispShortPointer: operand.Offset = _reader.ReadSByte(); operand.OffsetType = X86OffsetType.Short; break; case X86RegOrMemModifier.RegisterDispLongPointer: operand.Offset = _reader.ReadInt32(); operand.OffsetType = X86OffsetType.Long; break; } return operand; }
private static int GetSize(X86OperandSize operandSize) { switch (operandSize) { case X86OperandSize.Byte: return 1; case X86OperandSize.Word: return 2; case X86OperandSize.WordOrDword: case X86OperandSize.Dword: return 4; case X86OperandSize.Fword: return 6; } throw new NotSupportedException(); }
private static X86OperandUsage GetOperandType(ICollection <X86Prefix> prefixes, X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return(X86OperandUsage.BytePointer); case X86OperandSize.Word: return(X86OperandUsage.WordPointer); case X86OperandSize.Dword: return(X86OperandUsage.DwordPointer); case X86OperandSize.WordOrDword: return(prefixes.Contains(X86Prefixes.OperandSizeOverride) ? X86OperandUsage.WordPointer : X86OperandUsage.DwordPointer); case X86OperandSize.Fword: return(X86OperandUsage.FwordPointer); } throw new ArgumentException(); }
private void WriteNumber(object value, X86OperandSize size) { switch (size) { case X86OperandSize.Byte: if (value is sbyte || value is short || value is int || value is long) _writer.WriteSByte(Convert.ToSByte(value)); else _writer.WriteByte(Convert.ToByte(value)); break; case X86OperandSize.Word: if (value is sbyte || value is short || value is int || value is long) _writer.WriteInt16(Convert.ToInt16(value)); else _writer.WriteUInt16(Convert.ToUInt16(value)); break; case X86OperandSize.WordOrDword: case X86OperandSize.Dword: if (value is sbyte || value is short || value is int || value is long) _writer.WriteInt32(Convert.ToInt32(value)); else _writer.WriteUInt32(Convert.ToUInt32(value)); break; default: throw new NotSupportedException(); } }
private static int GetTotalOperandSize(X86OperandType operandType, X86OperandSize operandSize, X86Operand operand) { int size = (int)operand.OffsetType; switch (operandType) { case X86OperandType.None: case X86OperandType.ControlRegister: case X86OperandType.DebugRegister: case X86OperandType.StackRegister: case X86OperandType.Register: case X86OperandType.RegisterCl: case X86OperandType.RegisterDx: case X86OperandType.RegisterEax: case X86OperandType.RegisterAl: case X86OperandType.ImmediateOne: case X86OperandType.SegmentRegister: case X86OperandType.OpCodeRegister: break; case X86OperandType.DirectAddress: case X86OperandType.MemoryAddress: size += 4; break; case X86OperandType.RelativeOffset: case X86OperandType.ImmediateData: size += GetSize(operandSize); break; case X86OperandType.RegisterOrMemoryAddress: case X86OperandType.StackRegisterOrMemoryAddress: if ((operand.ScaledIndex != null) || (operand.OperandUsage != X86OperandUsage.Normal && operand.Value is X86Register && (X86Register)operand.Value == X86Register.Esp)) size += 1; if (!(operand.Value is X86Register)) size += 4; break; } return size; }
private void WriteOperand(X86OperandType method, X86OperandSize size, X86Operand operand) { WriteOperandValue(method, size, operand); WriteOperandOffset(operand.OffsetType, operand.Offset); }
private void WriteOperandValue(X86OperandType method, X86OperandSize size, X86Operand operand) { switch (method) { case X86OperandType.MemoryAddress: case X86OperandType.DirectAddress: case X86OperandType.ImmediateData: { WriteNumber(operand.Value, size); break; } case X86OperandType.RegisterOrMemoryAddress: { if ((operand.ScaledIndex != null) || (operand.OperandUsage != X86OperandUsage.Normal && operand.Value is X86Register && (X86Register)operand.Value == X86Register.Esp)) _writer.WriteByte(ComputeRegOrMemSibToken(operand)); else if (!(operand.Value is X86Register)) WriteNumber(operand.Value, X86OperandSize.Dword); break; } case X86OperandType.RelativeOffset: { WriteNumber(Convert.ToUInt32(operand.Value) - (_writer.Position + sizeof (sbyte)), size); break; } } }
private void DumpMemory(IDebuggeeProcess process, ulong address, int rows, X86OperandSize size, Logger logger) { const int rowSize = 0x10; var buffer = new byte[rows * rowSize]; process.ReadMemory((IntPtr)address, buffer, 0, buffer.Length); int stepSize = 0; switch (size) { case X86OperandSize.Byte: stepSize = 1; break; case X86OperandSize.Word: stepSize = 2; break; case X86OperandSize.Dword: stepSize = 4; break; default: throw new ArgumentOutOfRangeException(nameof(size)); } for (int row = 0; row < rows; row++) { logger.Write("{0:X8}: ", address + (ulong)(row * rowSize)); var builder = new StringBuilder(); for (int col = 0; col < rowSize; col += stepSize) { if (col % 4 == 0) { logger.Write(" "); } ulong currentValue = 0; switch (size) { case X86OperandSize.Byte: currentValue = buffer[row * rowSize + col]; break; case X86OperandSize.Word: currentValue = BitConverter.ToUInt16(buffer, row * rowSize + col); break; case X86OperandSize.Dword: currentValue = BitConverter.ToUInt32(buffer, row * rowSize + col); break; } logger.Write("{0} ", currentValue.ToString("X" + (stepSize * 2))); if (stepSize == 1) { char currentChar = (char)currentValue; builder.Append(char.IsControl(currentChar) ? '.' : currentChar); } } logger.WriteLine(" " + builder.ToString()); } }
private static X86RegisterSize GetRegisterSize(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return X86RegisterSize.Byte; case X86OperandSize.Word: return X86RegisterSize.Word; case X86OperandSize.Dword: return X86RegisterSize.Dword; case X86OperandSize.WordOrDword: return X86RegisterSize.Dword ; // TODO: use operand-size override opcode } throw new ArgumentException(); }
private object ReadSignedImmediateData(X86OperandSize size) { switch (size) { case X86OperandSize.Byte: return _reader.ReadSByte(); case X86OperandSize.Word: return _reader.ReadInt16(); case X86OperandSize.Dword: return _reader.ReadInt32(); case X86OperandSize.WordOrDword: return _reader.ReadInt32(); // TODO: use operand-size override opcode // TODO: fword } throw new NotSupportedException(); }
private X86Operand ReadOperand(X86OperandType method, X86OperandSize size, byte opcode, byte registerToken) { switch (method) { case X86OperandType.OpCodeRegister: return new X86Operand(GetRegisterFromToken((byte)(opcode & 7), GetRegisterSize(size))); case X86OperandType.Register: return new X86Operand(GetRegisterFromToken((byte)((registerToken >> 3) & 7), GetRegisterSize(size))); case X86OperandType.RegisterOrMemoryAddress: return GetRegOrMemOperand32(registerToken, size); case X86OperandType.ImmediateData: return new X86Operand(ReadImmediateData(size)); case X86OperandType.MemoryAddress: return new X86Operand(GetOperandType(size), _reader.ReadUInt32()); case X86OperandType.RegisterAl: return new X86Operand(X86Register.Al); case X86OperandType.RegisterCl: return new X86Operand(X86Register.Cl); case X86OperandType.RegisterDx: return new X86Operand(X86Register.Dx); case X86OperandType.RegisterEax: return new X86Operand(X86Register.Eax); case X86OperandType.ImmediateOne: return new X86Operand(1); case X86OperandType.RelativeOffset: return new X86Operand((ulong)(Convert.ToInt64(ReadSignedImmediateData(size)) + BaseAddress + _reader.Position)); case X86OperandType.None: return null; } throw new NotSupportedException("Unrecognized or unsupported addressing method."); }