private static byte ComputeRegOrMemToken(X86Operand operand) { // 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 = DetermineRegOrMemModifier(operand); var token = (byte)((byte)modifier << 6); if (operand.ScaledIndex != null) { token |= ComputeRegisterToken(X86Register.Esp); } else if (operand.Value is X86Register) { token |= ComputeRegisterToken((X86Register)operand.Value); } else { return(ComputeRegisterToken(X86Register.Ebp)); } return(token); }
private static X86RegOrMemModifier DetermineRegOrMemModifier(X86Operand operand) { if (operand.Value is X86Register) { switch (operand.OffsetType) { case X86OffsetType.None: return(operand.OperandUsage == X86OperandUsage.Normal ? X86RegOrMemModifier.RegisterOnly : X86RegOrMemModifier.RegisterPointer); case X86OffsetType.Short: return(X86RegOrMemModifier.RegisterDispShortPointer); case X86OffsetType.Long: return(X86RegOrMemModifier.RegisterDispLongPointer); } throw new NotSupportedException("Unsupported or unrecognized operand offset type."); } if (operand.Value is uint) { return(X86RegOrMemModifier.RegisterPointer); } throw new ArgumentException("Operand is not a valid RegOrMem operand.", "operand"); }
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 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; }
public virtual string FormatOperand(X86Operand operand) { if (operand == null) { return(string.Empty); } string prefix = FormatOperandUsagePrefix(operand.OperandUsage); var formattedValue = FormatValue(operand.Value); var formattedOffset = FormatOffset(operand.Offset); var formattedScaledIndex = operand.ScaledIndex != null ? '+' + operand.ScaledIndex.ToString() : string.Empty; return(prefix == null ? formattedValue : string.Format("{0} [{1}{2}{3}]", prefix, formattedValue, formattedScaledIndex, formattedOffset)); }
private static byte ComputeRegOrMemSibToken(X86Operand operand) { // Mechanism: // http://ref.x86asm.net/coder32.html#sib_byte_32 // SIB-byte: // mul | scaled_reg | reg // -----+------------+------- // 7 6 | 5 4 3 | 2 1 0 var token = ComputeRegisterToken((X86Register)operand.Value); if (operand.ScaledIndex == null) { token |= 0x20; } else { token |= (byte)(ComputeRegisterToken(operand.ScaledIndex.Register) << 3); switch (operand.ScaledIndex.Multiplier) { case 1: break; case 2: token |= 0x40; break; case 4: token |= 0x80; break; case 8: token |= 0xC0; break; default: throw new ArgumentException("Operand has an invalid scaled index multiplier.", "operand"); } } return(token); }
private static IEnumerable<X86Instruction> CreateRegOrMemSibTestInstructions(X86OpCode opcode, X86Mnemonic mnemonic) { for (int operandType = 0; operandType < 3; operandType++) { for (int multiplier = 1; multiplier < 16; multiplier*=2) { for (int scaledRegIndex = 0; scaledRegIndex < 8; scaledRegIndex++) { if (scaledRegIndex == 4) continue; var operand1 = new X86Operand(X86OperandUsage.BytePointer, X86Register.Eax, new X86ScaledIndex((X86Register)scaledRegIndex | X86Register.Eax, multiplier)); var operand2 = new X86Operand(X86OperandUsage.Normal, X86Register.Al); var instruction = new X86Instruction() { OpCode = opcode, Mnemonic = mnemonic, Operand1 = operand1, Operand2 = operand2, }; switch (operandType) { case 1: operand1.Offset = 1; operand1.OffsetType = X86OffsetType.Short; break; case 2: operand1.Offset = 0x1337; operand1.OffsetType = X86OffsetType.Long; break; } yield return instruction; } } } }
private static void MakeScaledIndexOperandFromToken(X86Operand operand, byte token) { // Mechanism: // http://ref.x86asm.net/coder32.html#sib_byte_32 // SIB-byte: // mul | scaled_reg | reg // -----+------------+------- // 7 6 | 5 4 3 | 2 1 0 var scaledIndex = new X86ScaledIndex { Register = GetRegisterFromToken((byte)((token >> 3) & 7), X86RegisterSize.Dword), Multiplier = 1 << ((token >> 6) & 3), }; // ESP scales are ignored. if (scaledIndex.Register != X86Register.Esp) { operand.ScaledIndex = scaledIndex; } operand.Value = GetRegisterFromToken((byte)(token & 0x7), X86RegisterSize.Dword); }
private void WriteOperand(X86OperandType method, X86OperandSize size, X86Operand operand) { WriteOperandValue(method, size, operand); WriteOperandOffset(operand.OffsetType, operand.Offset); }
private static byte ComputeRegOrMemSibToken(X86Operand operand) { // Mechanism: // http://ref.x86asm.net/coder32.html#sib_byte_32 // SIB-byte: // mul | scaled_reg | reg // -----+------------+------- // 7 6 | 5 4 3 | 2 1 0 var token = ComputeRegisterToken((X86Register)operand.Value); if (operand.ScaledIndex == null) token |= 0x20; else { token |= (byte)(ComputeRegisterToken(operand.ScaledIndex.Register) << 3); switch (operand.ScaledIndex.Multiplier) { case 1: break; case 2: token |= 0x40; break; case 4: token |= 0x80; break; case 8: token |= 0xC0; break; default: throw new ArgumentException("Operand has an invalid scaled index multiplier.", "operand"); } } return token; }
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 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 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 ComputeRegOrMemToken(X86Operand operand) { // 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 = DetermineRegOrMemModifier(operand); var token = (byte)((byte)modifier << 6); if (operand.ScaledIndex != null) token |= ComputeRegisterToken(X86Register.Esp); else if (operand.Value is X86Register) token |= ComputeRegisterToken((X86Register)operand.Value); else return ComputeRegisterToken(X86Register.Ebp); return token; }
private static X86RegOrMemModifier DetermineRegOrMemModifier(X86Operand operand) { if (operand.Value is X86Register) { switch (operand.OffsetType) { case X86OffsetType.None: return operand.OperandUsage == X86OperandUsage.Normal ? X86RegOrMemModifier.RegisterOnly : X86RegOrMemModifier.RegisterPointer; case X86OffsetType.Short: return X86RegOrMemModifier.RegisterDispShortPointer; case X86OffsetType.Long: return X86RegOrMemModifier.RegisterDispLongPointer; } throw new NotSupportedException("Unsupported or unrecognized operand offset type."); } if (operand.Value is uint) return X86RegOrMemModifier.RegisterPointer; throw new ArgumentException("Operand is not a valid RegOrMem operand.", "operand"); }
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 IEnumerable<X86Instruction> CreateRegOrMemTestInstructions(X86OpCode opcode, X86Mnemonic mnemonic, bool flippedOperands) { for (int operandType = 0; operandType < 3; operandType++) { for (int register2Index = 0; register2Index < 8; register2Index++) { for (int register1Index = 0; register1Index < 8; register1Index++) { var operand1 = new X86Operand(X86OperandUsage.BytePointer, (X86Register)register1Index | X86Register.Eax); var operand2 = new X86Operand(X86OperandUsage.Normal, (X86Register)register2Index); var instruction = new X86Instruction() { OpCode = opcode, Mnemonic = mnemonic, }; if (flippedOperands) { instruction.Operand2 = operand1; instruction.Operand1 = operand2; } else { instruction.Operand1 = operand1; instruction.Operand2 = operand2; } switch (register1Index) { case 4: // esp continue; case 5: // ebp if (operandType != 0) continue; operand1.Value = 0x1337u; break; } switch (operandType) { case 1: operand1.Offset = 1; operand1.OffsetType = X86OffsetType.Short; break; case 2: operand1.Offset = 0x1337; operand1.OffsetType = X86OffsetType.Long; break; } yield return instruction; } } } }
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 static void MakeScaledIndexOperandFromToken(X86Operand operand, byte token) { // Mechanism: // http://ref.x86asm.net/coder32.html#sib_byte_32 // SIB-byte: // mul | scaled_reg | reg // -----+------------+------- // 7 6 | 5 4 3 | 2 1 0 var scaledIndex = new X86ScaledIndex { Register = GetRegisterFromToken((byte)((token >> 3) & 7), X86RegisterSize.Dword), Multiplier = 1 << ((token >> 6) & 3), }; // ESP scales are ignored. if (scaledIndex.Register != X86Register.Esp) operand.ScaledIndex = scaledIndex; operand.Value = GetRegisterFromToken((byte)(token & 0x7), X86RegisterSize.Dword); }
public virtual string FormatOperand(X86Operand operand) { if (operand == null) return string.Empty; string prefix = FormatOperandUsagePrefix(operand.OperandUsage); var formattedValue = FormatValue(operand.Value); var formattedOffset = FormatOffset(operand.Offset); var formattedScaledIndex = operand.ScaledIndex != null ? '+' + operand.ScaledIndex.ToString() : string.Empty; return prefix == null ? formattedValue : string.Format("{0} [{1}{2}{3}]", prefix, formattedValue, formattedScaledIndex, formattedOffset); }