Example #1
0
        private void RewritePush()
        {
            if (instrCur.Operands[0] is RegisterOperand reg && reg.Register == Registers.cs)
            {
                if (dasm.Peek(1).Mnemonic == Mnemonic.call &&
                    dasm.Peek(1).Operands[0].Width == PrimitiveType.Word16)
                {
                    dasm.MoveNext();
                    MachineOperand targetOperand = dasm.Current.Operands[0];

                    if (targetOperand is ImmediateOperand immOperand)
                    {
                        targetOperand = new X86AddressOperand(orw.ImmediateAsAddress(instrCur.Address, immOperand));
                    }
                    else
                    {
                        m.Assign(StackPointer(), m.ISubS(StackPointer(), reg.Register.DataType.Size));
                    }

                    RewriteCall(targetOperand, targetOperand.Width);
                    this.len = (byte)(this.len + dasm.Current.Length);
                    return;
                }

                if (
                    dasm.Peek(1).Mnemonic == Mnemonic.push && (dasm.Peek(1).Operands[0] is ImmediateOperand) &&
                    dasm.Peek(2).Mnemonic == Mnemonic.push && (dasm.Peek(2).Operands[0] is ImmediateOperand) &&
                    dasm.Peek(3).Mnemonic == Mnemonic.jmp && (dasm.Peek(3).Operands[0] is X86AddressOperand))
                {
                    // That's actually a far call, but the callee thinks its a near call.
                    RewriteCall(dasm.Peek(3).Operands[0], instrCur.Operands[0].Width);
                    dasm.MoveNext();
                    dasm.MoveNext();
                    dasm.MoveNext();
                    return;
                }
            }
            var imm   = instrCur.Operands[0] as ImmediateOperand;
            var value = SrcOp(dasm.Current.Operands[0], arch.StackRegister.DataType);

            Debug.Assert(
                value.DataType.BitSize == 16 ||
                value.DataType.BitSize == 32 ||
                value.DataType.BitSize == 64,
                string.Format("Unexpected size {0}", dasm.Current.dataWidth));
            RewritePush(PrimitiveType.CreateWord(value.DataType.BitSize), value);
        }
Example #2
0
        private X86Instruction DecodeOperands(Opcode opcode, byte op, string strFormat, InstrClass iclass)
        {
            if (strFormat == null)
            {
                return(null);
            }
            MachineOperand        pOperand;
            PrimitiveType         width  = null;
            PrimitiveType         iWidth = dataWidth;
            byte                  modRm;
            List <MachineOperand> ops = new List <MachineOperand>();
            int i = 0;

            while (i != strFormat.Length)
            {
                if (strFormat[i] == ',')
                {
                    ++i;
                }

                pOperand = null;
                MemoryOperand memOp;
                char          chFmt = strFormat[i++];
                switch (chFmt)
                {
                case '1':
                    pOperand = new ImmediateOperand(Constant.Byte(1));
                    break;

                case '3':
                    pOperand = new ImmediateOperand(Constant.Byte(3));
                    break;

                case 'A':               // Absolute memory address.
                    ++i;
                    if (!rdr.TryReadLeUInt16(out ushort off))
                    {
                        return(null);
                    }
                    if (!rdr.TryReadLeUInt16(out ushort seg))
                    {
                        return(null);
                    }
                    var addr = mode.CreateSegmentedAddress(seg, off);
                    if (addr == null)
                    {
                        return(null);
                    }
                    pOperand = new X86AddressOperand(addr);
                    break;

                case 'C':       // control register encoded in the reg field.
                    ++i;
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    var creg = mode.GetControlRegister((modRm >> 3) & 7);
                    if (creg == null)
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(creg);
                    break;

                case 'D':       // debug register encoded in the reg field.
                    ++i;
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    var dreg = mode.GetDebugRegister((modRm >> 3) & 7);
                    if (dreg == null)
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(dreg);
                    break;

                case 'E':               // memory or register operand specified by mod & r/m fields.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    pOperand = DecodeModRM(width, this.currentDecodingContext.SegmentOverride, GpRegFromBits);
                    if (pOperand == null)
                    {
                        return(null);
                    }
                    break;

                case 'Q':               // memory or register MMX operand specified by mod & r/m fields.
                    width    = SseOperandWidth(strFormat, ref i);
                    pOperand = DecodeModRM(width, this.currentDecodingContext.SegmentOverride, MmxRegFromBits);
                    if (pOperand == null)
                    {
                        return(null);
                    }
                    break;

                case 'G':               // register operand specified by the reg field of the modRM byte.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, GpRegFromBits));
                    break;

                case 'H':       // If VEX encoding, use vvvv register.
                    if (currentDecodingContext.IsVex)
                    {
                        width    = SseOperandWidth(strFormat, ref i);
                        pOperand = new RegisterOperand(XmmRegFromBits(currentDecodingContext.VexRegister, width));
                    }
                    else
                    {
                        i = strFormat.IndexOf(',', i);
                    }
                    break;

                case 'N':       // MMX register operand specified by the r/m field of the modRM byte.
                    width = SseOperandWidth(strFormat, ref i);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm, width, MmxRegFromBits));
                    break;

                case 'P':               // MMX register operand specified by the reg field of the modRM byte.
                    width = SseOperandWidth(strFormat, ref i);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, MmxRegFromBits));
                    break;

                case 'I':               // Immediate operand.
                    if (strFormat[i] == 'x')
                    {
                        iWidth = width; // Use width of the previous operand.
                    }
                    else
                    {
                        width = OperandWidth(strFormat, ref i); //  Don't use the width of the previous operand.
                    }
                    ++i;
                    pOperand = CreateImmediateOperand(width, dataWidth);
                    if (pOperand == null)
                    {
                        return(null);
                    }
                    break;

                case 'L': // The upper 4 bits of the 8-bit immediate selects a 128-bit XMM register or a 256-bit YMM register, determined
                          // by operand type.
                    if (!rdr.TryReadByte(out var lReg))
                    {
                        return(null);
                    }
                    if (strFormat[i] == 'x')
                    {
                        iWidth = width; // Use width of the previous operand.
                    }
                    else
                    {
                        width = OperandWidth(strFormat, ref i); //  Don't use the width of the previous operand.
                    }
                    ++i;
                    pOperand = new RegisterOperand(XmmRegFromBits((lReg >> 4) & 0xF, width));
                    break;

                case 'J':               // Relative ("near") jump.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    Constant cOffset;
                    if (!rdr.TryRead(width, out cOffset))
                    {
                        return(null);
                    }
                    long  jOffset = cOffset.ToInt64();
                    ulong uAddr   = (ulong)((long)rdr.Address.Offset + jOffset);
                    if (defaultAddressWidth.BitSize == 64)      //$REVIEW: not too keen on the switch statement here.
                    {
                        pOperand = AddressOperand.Ptr64(uAddr);
                    }
                    else if (defaultAddressWidth.BitSize == 32)
                    {
                        pOperand = AddressOperand.Ptr32((uint)uAddr);
                    }
                    else
                    {
                        pOperand = new ImmediateOperand(Constant.Create(defaultDataWidth, uAddr));
                    }
                    break;

                case 'M':               // modRM may only refer to memory.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    if ((modRm & 0xC0) == 0xC0)
                    {
                        return(null);
                    }
                    pOperand = DecodeModRM(dataWidth, this.currentDecodingContext.SegmentOverride, GpRegFromBits) as MemoryOperand;
                    if (pOperand == null)
                    {
                        return(null);
                    }
                    break;

                case 'O':               // Offset of the operand is encoded directly after the opcode.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    if (!rdr.TryReadLe(addressWidth, out var offset))
                    {
                        return(null);
                    }
                    pOperand          = memOp = new MemoryOperand(width, offset);
                    memOp.SegOverride = this.currentDecodingContext.SegmentOverride;
                    break;

                case 'R':       // register operand specified by the mod field of the modRM byte.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm, width, GpRegFromBits));
                    break;

                case 'S':       // Segment register encoded by reg field of modRM byte.
                    ++i;        // Skip over the 'w'.
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(SegFromBits(modRm >> 3));
                    break;

                case 'U':               // XMM operand specified by the modRm field of the modRM byte.
                    width = SseOperandWidth(strFormat, ref i);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm, width, XmmRegFromBits));
                    break;

                case 'V':               // XMM operand specified by the reg field of the modRM byte.
                    width = SseOperandWidth(strFormat, ref i);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, XmmRegFromBits));
                    break;

                case 'W':               // memory or XMM operand specified by mod & r/m fields.
                    width    = SseOperandWidth(strFormat, ref i);
                    pOperand = DecodeModRM(width, this.currentDecodingContext.SegmentOverride, XmmRegFromBits);
                    break;

                case 'a':               // Implicit use of accumulator.
                    pOperand = new RegisterOperand(RegFromBitsRexW(0, OperandWidth(strFormat, ref i)));
                    ++i;
                    break;

                case 'b':
                    iWidth   = PrimitiveType.Byte;
                    pOperand = null;
                    break;

                case 'c':               // Implicit use of CL.
                    pOperand = new RegisterOperand(Registers.cl);
                    break;

                case 'd':               // Implicit use of DX or EDX.
                    width = OperandWidth(strFormat, ref i);
                    ++i;
                    pOperand = new RegisterOperand(RegFromBitsRexW(2, width));
                    break;

                case 'r':               // Register encoded as last 3 bits of instruction.
                    iWidth = width = OperandWidth(strFormat, ref i);
                    ++i;
                    pOperand = new RegisterOperand(RegFromBitsRexB(op, width));
                    break;

                case 's':               // Segment encoded as next byte of the format string.
                    pOperand = new RegisterOperand(SegFromBits(strFormat[i++] - '0'));
                    break;

                case 'F':               // Floating-point ST(x)
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new FpuOperand(modRm & 0x07);
                    break;

                case 'f':               // ST(0)
                    pOperand = new FpuOperand(0);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(string.Format("Unknown format specifier '{0}' at position {1} of format string '{2}'.", chFmt, i, strFormat));
                }
                if (pOperand != null)
                {
                    ops.Add(pOperand);
                }
            }
            return(new X86Instruction(opcode, iclass, iWidth, addressWidth, ops.ToArray())
            {
                repPrefix = this.currentDecodingContext.F2Prefix ? 2 :
                            this.currentDecodingContext.F3Prefix ? 3 : 0
            });
        }
Example #3
0
        private IntelInstruction DecodeOperands(Opcode opcode, byte op, string strFormat)
        {
            MachineOperand        pOperand;
            PrimitiveType         width  = null;
            PrimitiveType         iWidth = dataWidth;
            byte                  modRm;
            List <MachineOperand> ops = new List <MachineOperand>();
            int i = 0;

            while (i != strFormat.Length)
            {
                if (strFormat[i] == ',')
                {
                    ++i;
                }

                pOperand = null;
                ImmediateOperand  immOp;
                MemoryOperand     memOp;
                X86AddressOperand addrOp;
                int offset;

                char chFmt = strFormat[i++];
                switch (chFmt)
                {
                case '1':
                    pOperand = immOp = new ImmediateOperand(Constant.Byte(1));
                    break;

                case '3':
                    pOperand = immOp = new ImmediateOperand(Constant.Byte(3));
                    break;

                case 'A':               // Absolute memory address.
                    ++i;
                    ushort off = rdr.ReadLeUInt16();
                    ushort seg = rdr.ReadLeUInt16();
                    pOperand = addrOp = new X86AddressOperand(Address.SegPtr(seg, off));
                    break;

                case 'E':               // memory or register operand specified by mod & r/m fields.
                    width    = OperandWidth(strFormat[i++]);
                    pOperand = DecodeModRM(width, segmentOverride, GpRegFromBits);
                    break;

                case 'Q':               // memory or register MMX operand specified by mod & r/m fields.
                    width    = OperandWidth(strFormat[i++]);
                    pOperand = DecodeModRM(width, segmentOverride, MmxRegFromBits);
                    break;

                case 'G':               // register operand specified by the reg field of the modRM byte.
                    width = OperandWidth(strFormat[i++]);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, GpRegFromBits));
                    break;

                case 'P':               // MMX register operand specified by the reg field of the modRM byte.
                    width = OperandWidth(strFormat[i++]);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, MmxRegFromBits));
                    break;

                case 'I':               // Immediate operand.
                    if (strFormat[i] == 'x')
                    {
                        iWidth = width; // Use width of the previous operand.
                    }
                    else
                    {
                        width = OperandWidth(strFormat[i]); //  Don't use the width of the previous operand.
                    }
                    ++i;
                    pOperand = CreateImmediateOperand(width, dataWidth);
                    break;

                case 'J':               // Relative ("near") jump.
                    width  = OperandWidth(strFormat[i++]);
                    offset = rdr.ReadLeSigned(width);
                    ulong uAddr = (ulong)((long)rdr.Address.Offset + (long)offset);
                    if (defaultAddressWidth.BitSize == 64)      //$REVIEW: not too keen on the switch statement here.
                    {
                        pOperand = AddressOperand.Ptr64(uAddr);
                    }
                    else if (defaultAddressWidth.BitSize == 32)
                    {
                        pOperand = AddressOperand.Ptr32((uint)uAddr);
                    }
                    else
                    {
                        pOperand = new ImmediateOperand(Constant.Create(defaultDataWidth, uAddr));
                    }
                    break;

                case 'M':               // modRM may only refer to memory.
                    width    = OperandWidth(strFormat[i++]);
                    pOperand = DecodeModRM(dataWidth, segmentOverride, GpRegFromBits);
                    break;

                case 'O':               // Offset of the operand is encoded directly after the opcode.
                    width             = OperandWidth(strFormat[i++]);
                    pOperand          = memOp = new MemoryOperand(width, rdr.ReadLe(addressWidth));
                    memOp.SegOverride = segmentOverride;
                    break;

                case 'S':       // Segment register encoded by reg field of modRM byte.
                    ++i;        // Skip over the 'w'.
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(SegFromBits(modRm >> 3));
                    break;

                case 'V':               // XMM operand specified by the reg field of the modRM byte.
                    width = SseOperandWidth(strFormat, ref i);
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new RegisterOperand(RegFromBitsRexR(modRm >> 3, width, XmmRegFromBits));
                    break;

                case 'W':               // memory or XMM operand specified by mod & r/m fields.
                    width    = SseOperandWidth(strFormat, ref i);
                    pOperand = DecodeModRM(width, segmentOverride, XmmRegFromBits);
                    break;

                case 'a':               // Implicit use of accumulator.
                    pOperand = new RegisterOperand(RegFromBitsRexW(0, OperandWidth(strFormat[i++])));
                    break;

                case 'b':
                    iWidth   = PrimitiveType.Byte;
                    pOperand = null;
                    break;

                case 'c':               // Implicit use of CL.
                    pOperand = new RegisterOperand(Registers.cl);
                    break;

                case 'd':               // Implicit use of DX or EDX.
                    width    = OperandWidth(strFormat[i++]);
                    pOperand = new RegisterOperand(RegFromBitsRexW(2, width));
                    break;

                case 'r':               // Register encoded as last 3 bits of instruction.
                    width    = OperandWidth(strFormat[i++]);
                    pOperand = new RegisterOperand(RegFromBitsRexW(op, width));
                    break;

                case 's':               // Segment encoded as next byte of the format string.
                    pOperand = new RegisterOperand(SegFromBits(strFormat[i++] - '0'));
                    break;

                case 'F':               // Floating-point ST(x)
                    if (!TryEnsureModRM(out modRm))
                    {
                        return(null);
                    }
                    pOperand = new FpuOperand(modRm & 0x07);
                    break;

                case 'f':               // ST(0)
                    pOperand = new FpuOperand(0);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(string.Format("Unknown format specifier '{0}' at position {1} of format string '{2}'.", chFmt, i, strFormat));
                }
                if (pOperand != null)
                {
                    ops.Add(pOperand);
                }
            }
            return(new IntelInstruction(opcode, iWidth, addressWidth, ops.ToArray()));
        }