Represents an operand in an x86 instruction.
Пример #1
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);
        }
Пример #2
0
        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");
        }
Пример #3
0
        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;
            }
            }
        }
Пример #4
0
        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);
        }
Пример #5
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;
 }
Пример #6
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));
        }
Пример #7
0
        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);
        }
Пример #8
0
        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;
                    }
                }
            }
        }
Пример #9
0
        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);
        }
Пример #10
0
 private void WriteOperand(X86OperandType method, X86OperandSize size, X86Operand operand)
 {
     WriteOperandValue(method, size, operand);
     WriteOperandOffset(operand.OffsetType, operand.Offset);
 }
Пример #11
0
        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;
        }
Пример #12
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 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);
        }
Пример #14
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);
        }
Пример #15
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;
        }
Пример #16
0
        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");
        }
Пример #17
0
        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;
        }
Пример #18
0
        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;
                    }
                }
            }
        }
Пример #19
0
 private void WriteOperand(X86OperandType method, X86OperandSize size, X86Operand operand)
 {
     WriteOperandValue(method, size, operand);
     WriteOperandOffset(operand.OffsetType, operand.Offset);
 }
Пример #20
0
 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;
         }
     }
 }
Пример #21
0
        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);
        }
Пример #22
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);
        }