public virtual string FormatInstruction(Instruction instruction)
        {
            if (instruction == null)
                throw new ArgumentNullException("instruction");

            StringBuilder sb = new StringBuilder();

            // Format group 1 (LOCK/REPZ/REPNZ) prefix.
            if ((instruction.Prefix & Prefixes.Group1) != 0)
            {
                sb.Append((instruction.Prefix & Prefixes.Group1).ToString().ToLowerInvariant());
                sb.Append(' ');
            }

            // Format mnemonic.
            sb.Append(FormatMnemonic(instruction.Operation));

            // Format operands.
            for (int i = 0; i < instruction.Operands.Length; i++)
            {
                if (i > 0)
                {
                    sb.Append(',');
                }
                sb.Append(' ');
                sb.Append(FormatOperand(instruction.Operands[i]));
            }
            return sb.ToString();
        }
Exemple #2
0
        /// <summary>
        /// Decodes an instruction.
        /// </summary>
        /// <param name="code">X86 binary code.</param>
        /// <param name="startIndex">Index of the first byte to start
        /// decoding.</param>
        /// <param name="context">Decoding context.</param>
        /// <returns>The decoded instruction.</returns>
        /// <exception cref="InvalidInstructionException">If decoding failed.
        /// </exception>
        public Instruction Decode(
            byte[] code, 
            int startIndex,
            int count,
            DecoderContext context)
        {
            Instruction instruction = new Instruction();

            // Create an instruction reader.
            InstructionReader reader = new InstructionReader(code, startIndex, count);

            // Reset the context.
            context.AddressSize = CpuSize.Use16Bit;
            context.OperandSize = CpuSize.Use16Bit;
            context.SegmentOverride = Register.None;

            // Decode prefixes.
            Prefixes prefix = DecodeLegacyPrefixes(reader);
            if ((prefix & Prefixes.OperandSizeOverride) != 0)
            {
                context.OperandSize = CpuSize.Use32Bit;
            }
            if ((prefix & Prefixes.AddressSizeOverride) != 0)
            {
                context.AddressSize = CpuSize.Use32Bit;
            }
            if ((prefix & Prefixes.Group2) != 0)
            {
                Register seg = Register.None;
                switch (prefix & Prefixes.Group2)
                {
                    case Prefixes.ES: seg = Register.ES; break;
                    case Prefixes.CS: seg = Register.CS; break;
                    case Prefixes.SS: seg = Register.SS; break;
                    case Prefixes.DS: seg = Register.DS; break;
                    case Prefixes.FS: seg = Register.FS; break;
                    case Prefixes.GS: seg = Register.GS; break;
                }
                context.SegmentOverride = seg;
            }
            instruction.Prefix = prefix;

            // Decode the opcode to retrieve opcode specification.
            Op spec = DecodeOpcode(reader);
            instruction.Operation = spec.Operation;

            // Decode operands.
            instruction.Operands = new Operand[spec.Operands.Length];
            for (int i = 0; i < spec.Operands.Length; i++)
            {
                instruction.Operands[i] =
                    DecodeOperand(spec.Operands[i], reader, context);
            }

            // Update the encoded length of the instruction.
            instruction.EncodedLength = reader.Position;
            //instruction.Location = location;
            return instruction;
        }
        public void Add(Address address, Instruction instruction)
        {
            if (!image.IsAddressValid(address))
                throw new ArgumentOutOfRangeException("address");
            if (instruction == null)
                throw new ArgumentNullException("instruction");

            this.instructions.Add(address, instruction);
        }
Exemple #4
0
        public override string FormatInstruction(Instruction instruction)
        {
            string s = base.FormatInstruction(instruction);

            // Make "interesting" instructions bold.
            switch (instruction.Operation)
            {
                //case Operation.CALL:
                //case Operation.CALLF:
                //    return string.Format("<b>{0}</b>", s);
                default:
                    return s;
            }
        }
Exemple #5
0
        private static string FormatSymbolicOperand(
            X86Codec.Instruction instruction,
            X86Codec.Operand operand,
            FixupDefinition fixup,
            ObjectModule module)
        {
            if (fixup.Target.Method == FixupTargetMethod.ExternalPlusDisplacement ||
                fixup.Target.Method == FixupTargetMethod.ExternalWithoutDisplacement)
            {
                var extIndex = fixup.Target.IndexOrFrame;
                var extName  = module.ExternalNames[extIndex - 1];
                var disp     = fixup.Target.Displacement;

                //System.Diagnostics.Debug.WriteLine(string.Format(
                //    "{0} : operand {4} refers to {1}+{2} : {3}",
                //    instruction, extName, disp, fixup.Location, operand));
                return(extName.Name);
            }
            return(null);
        }
 public static CodeFeatures GetFeatures(Instruction instruction)
 {
     CodeFeatures features = CodeFeatures.None;
     switch (instruction.Operation)
     {
         case Operation.INT:
         case Operation.INTO:
             features |= CodeFeatures.HasInterrupt;
             break;
         case Operation.RET:
             features |= CodeFeatures.HasRETN;
             break;
         case Operation.RETF:
             features |= CodeFeatures.HasRETF;
             break;
         case Operation.IRET:
             features |= CodeFeatures.HasIRET;
             break;
         case Operation.FCLEX:
             features |= CodeFeatures.HasFpu;
             break;
     }
     return features;
 }
        private static void ComputeMore(
            HashAlgorithm hasher, byte[] code, int startIndex, Instruction instruction)
        {
            if (instruction == null)
                throw new ArgumentNullException("instruction");

            // Find the opcode part.
            // TODO: in X86Codec, since a fixable location always comes after
            // prefix+opcode+modrm+sib, we should put the fixable location as
            // a property of the instruction instead of the operand.
            int opcodeLength = instruction.EncodedLength;
            foreach (Operand operand in instruction.Operands)
            {
                if (operand.FixableLocation.Length > 0)
                    opcodeLength = Math.Min(opcodeLength, operand.FixableLocation.StartOffset);
            }

            // Since the opcode uniquely determines the displacement and
            // immediate format, we only need to hash the opcode part and
            // don't need to hash dummy zeros for the remaining part of the
            // instruction.
            hasher.TransformBlock(code, startIndex, opcodeLength, code, startIndex);
        }
        protected virtual XRef CreateFlowXRef(
            XRefType xrefType, Address source, Instruction instruction)
        {
            switch (xrefType)
            {
                case XRefType.ConditionalJump:
                case XRefType.FarJump:
                case XRefType.NearJump:
                case XRefType.FarCall:
                case XRefType.NearCall:
                    return CreateBranchJumpCallXRef(xrefType, source, instruction);

                case XRefType.NearIndexedJump:
                    throw new NotImplementedException();

                default:
                    return null;
            }
        }
        protected virtual XRef CreateBranchJumpCallXRef(
            XRefType type, Address source, Instruction instruction)
        {
            Address target = ResolveFlowInstructionTarget(instruction.Operands[0]);

            if (target == Address.Invalid)
            {
                AddError(source, ErrorCode.DynamicTarget,
                    "Cannot determine the target of {0} instruction.", instruction.Operation);
            }
            return new XRef(
                type: type,
                source: source,
                target: target
            );
        }
 /// <summary>
 /// Replaces any RelativeOperand with SourceAwareRelativeOperand.
 /// </summary>
 /// <param name="instruction"></param>
 // TODO: make SourceAwareRelativeOperand.Target a dummy
 // SymbolicTarget, so that we can handle them consistently.
 protected static void MakeRelativeOperandSourceAware(
     Instruction instruction, Address instructionStart)
 {
     for (int i = 0; i < instruction.Operands.Length; i++)
     {
         if (instruction.Operands[i] is RelativeOperand &&
             instruction.Operands[i].Tag == null)
         {
             instruction.Operands[i] = new SourceAwareRelativeOperand(
                 (RelativeOperand)instruction.Operands[i],
                 instructionStart + instruction.EncodedLength);
         }
     }
 }
        /// <summary>
        /// Analyzes an instruction and returns a xref if the instruction is
        /// one of the branch/call/jump instructions. Note that the 'no-jump'
        /// branch of a conditional jump instruction is not returned. The
        /// caller must manually create such a xref if needed.
        /// </summary>
        /// <param name="instruction">The instruction to analyze.</param>
        /// <returns>XRef if the instruction is a b/c/j instruction; 
        /// null otherwise.</returns>
        /// TBD: address wrapping if IP is above 0xFFFF is not handled. It should be.
        private XRef AnalyzeFlowInstruction(Pointer start, Instruction instruction)
        {
            Operation op = instruction.Operation;

            // Find the type of branch/call/jump instruction being processed.
            //
            // Note: If the instruction is a conditional jump, we assume that
            // the condition may be true or false, so that both "jump" and 
            // "no jump" is a reachable branch. If the code is malformed such
            // that either branch will never be executed, the analysis may not
            // work correctly.
            //
            // Note: If the instruction is a function call, we assume that the
            // subroutine being called will return. If the subroutine never
            // returns the analysis may not work correctly.
            XRefType bcjType;
            switch (op)
            {
                case Operation.JO:
                case Operation.JNO:
                case Operation.JB:
                case Operation.JAE:
                case Operation.JE:
                case Operation.JNE:
                case Operation.JBE:
                case Operation.JA:
                case Operation.JS:
                case Operation.JNS:
                case Operation.JP:
                case Operation.JNP:
                case Operation.JL:
                case Operation.JGE:
                case Operation.JLE:
                case Operation.JG:
                case Operation.JCXZ:
                case Operation.LOOP:
                case Operation.LOOPZ:
                case Operation.LOOPNZ:
                    bcjType = XRefType.ConditionalJump;
                    break;

                case Operation.JMP:
                    bcjType = XRefType.NearJump;
                    break;

                case Operation.JMPF:
                    bcjType = XRefType.FarJump;
                    break;

                case Operation.CALL:
                    bcjType = XRefType.NearCall;
                    break;

                case Operation.CALLF:
                    bcjType = XRefType.FarCall;
                    break;

                default:
                    // Not a b/c/j instruction; do nothing.
                    return null;
            }

            // Create a cross-reference depending on the type of operand.
            if (instruction.Operands[0] is RelativeOperand) // near jump/call to relative address
            {
                RelativeOperand opr = (RelativeOperand)instruction.Operands[0];
                return new XRef(
                    type: bcjType,
                    source: start,
                    target: start.IncrementWithWrapping(instruction.EncodedLength + opr.Offset.Value)
                );
            }

            if (instruction.Operands[0] is PointerOperand) // far jump/call to absolute address
            {
                PointerOperand opr = (PointerOperand)instruction.Operands[0];
                return new XRef(
                    type: bcjType,
                    source: start,
                    target: new Pointer(opr.Segment.Value, (UInt16)opr.Offset.Value)
                );
            }

            if (instruction.Operands[0] is MemoryOperand) // indirect jump/call
            {
                MemoryOperand opr = (MemoryOperand)instruction.Operands[0];

                // Handle static near jump table. We recognize a jump table 
                // heuristically if the instruction looks like the following:
                //
                //   jmpn word ptr cs:[bx+3782h] 
                //
                // That is, it meets the requirements that
                //   - the instruction is JMPN
                //   - the jump target is a word-ptr memory location
                //   - the memory location has CS prefix
                //   - a base register (e.g. bx) specifies the entry index
                //
                // Note that a malformed executable may create a jump table
                // not conforming to the above rules, or create a non-jump 
                // table that conforms to the above rules. We do not deal with
                // these cases for the moment.
                if (op == Operation.JMP &&
                    opr.Size == CpuSize.Use16Bit &&
                    opr.Segment == Register.CS &&
                    opr.Base != Register.None &&
                    opr.Index == Register.None)
                {
                    return new XRef(
                        type: XRefType.NearIndexedJump,
                        source: start,
                        target: Pointer.Invalid,
                        dataLocation: new Pointer(start.Segment, (UInt16)opr.Displacement.Value)
                    );
                }
            }

            // Other jump/call targets that we cannot recognize.
            AddError(start, ErrorCategory.Message,
                "Cannot determine target of {0} instruction.", op);

            return new XRef(
                type: bcjType,
                source: start,
                target: Pointer.Invalid
            );
        }