/// <summary>
 /// Analyzes code starting from the given location. That location
 /// should be the entry point of a procedure, or otherwise the
 /// analysis may not work correctly.
 /// </summary>
 /// <param name="entryPoint">Specifies the location to start analysis.
 /// This location is relative to the beginning of the image.</param>
 /// <param name="entryType">Type of entry, should usually be JMP or
 /// CALL.</param>
 public virtual void Analyze(Address entryPoint, XRefType entryType)
 {
     GenerateBasicBlocks(entryPoint, entryType);
     GenerateControlFlowGraph();
     GenerateProcedures();
     AddBasicBlocksToProcedures();
 }
Exemple #2
0
 public SourceAwareRelativeOperand(RelativeOperand opr, Address source)
     : base(opr.Offset)
 {
     this.source = source;
 }
        /// <summary>
        /// Analyzes code starting from the given location, and create basic
        /// blocks iteratively.
        /// </summary>
        public void GenerateBasicBlocks(Address entryPoint, XRefType entryType)
        {
            Address address = entryPoint;

            // Maintain a queue of basic block entry points to analyze. At
            // the beginning, only the user-specified entry point is in the
            // queue. As we encounter b/c/j instructions during the course
            // of analysis, we push the target addresses to the queue of
            // entry points to be analyzed later.
            PriorityQueue<XRef> xrefQueue =
                new PriorityQueue<XRef>(XRef.CompareByPriority);

            // Maintain a list of all procedure calls (with known target)
            // encountered during the analysis. After we finish analyzing
            // all the basic blocks, we update the list of procedures.
            // List<XRef> xrefCalls = new List<XRef>();

            // Create a a dummy xref entry using the user-supplied starting
            // address.
            xrefQueue.Enqueue(new XRef(
                type: entryType,
                source: Address.Invalid,
                target: entryPoint
            ));

            // Analyze each cross reference in order of their priority.
            // In particular, if the xref is an indexed jump, we delay its
            // processing until we have processed all other types of xrefs.
            // This reduces the chance that we process past the end of a
            // jump table.
            while (!xrefQueue.IsEmpty)
            {
                XRef entry = xrefQueue.Dequeue();

                // Handle jump table entry, whose Target == Invalid.
                if (entry.Type == XRefType.NearIndexedJump)
                {
                    System.Diagnostics.Debug.Assert(entry.Target == Address.Invalid);

                    // Fill the Target field to make it a static xref.
                    entry = ProcessJumpTableEntry(entry, xrefQueue);
                    if (entry == null) // end of jump table
                        continue;
                }

                // Skip other dynamic xrefs.
                if (entry.Target == Address.Invalid)
                {
                    CrossReferences.Add(entry);
                    continue;
                }

                // Process the basic block starting at the target address.
                BasicBlock block = AnalyzeBasicBlock(entry, xrefQueue);
                if (block != null)
                {
                    //int count = block.Length;
                    //int baseOffset = PointerToOffset(entry.Target);
                    //proc.CodeRange.AddInterval(baseOffset, baseOffset + count);
                    //proc.ByteRange.AddInterval(baseOffset, baseOffset + count);
                    //for (int j = 0; j < count; j++)
                    //{
                    //    image[baseOffset + j].Procedure = proc;
                    //}
            #if false
                    proc.AddBasicBlock(block);
            #endif
                }
                CrossReferences.Add(entry);
            }
        }
        /// <summary>
        /// Decodes an instruction at the given offset, applying associated
        /// fix-up information if present.
        /// </summary>
        /// <returns>The decoded instruction.</returns>
        /// <remarks>
        /// When overridden, the method must guarantee that the instruction
        /// is contained in the image, and not into another segment.
        /// </remarks>
        /// <exception cref="ArgumentOutOfRangeException">If offset refers to
        /// a location outside of the image.</exception>
        protected virtual Instruction DecodeInstruction(Address address)
        {
            if (!image.IsAddressValid(address))
                throw new ArgumentOutOfRangeException("address");

            Instruction instruction ;
            try
            {
                instruction = X86Codec.Decoder.Decode(
                    image.GetBytes(address), CpuMode.RealAddressMode);
            }
            catch (Exception ex)
            {
                AddError(address, ErrorCode.InvalidInstruction, "Bad instruction: {0}", ex.Message);
                return null;
            }

            MakeRelativeOperandSourceAware(instruction, address);

            return instruction;
        }
        /// <summary>
        /// Creates an instruction starting at the given address. If the
        /// decoded instruction covers bytes that are already analyzed,
        /// returns null.
        /// </summary>
        /// <param name="image"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        protected virtual Instruction CreateInstruction(Address address, XRef entry)
        {
            Instruction instruction = DecodeInstruction(address);
            if (instruction == null)
                return null;

            // Check that the bytes covered by the decoded instruction are
            // unanalyzed.
            if (!image.CheckByteType(address, address + instruction.EncodedLength, ByteType.Unknown))
            {
                AddError(address, ErrorCode.OverlappingInstruction,
                    "Ran into the middle of code when processing block {0} referred from {1}",
                    entry.Target, entry.Source);
                return null;
            }

            // Create a code piece for this instruction.
            image.UpdateByteType(address, address + instruction.EncodedLength, ByteType.Code);
            image.Instructions.Add(address, instruction);

            // Return the decoded instruction.
            return instruction;
        }
        /// <summary>
        /// Creates a procedure with the given entry point.
        /// </summary>
        /// <returns></returns>
        protected virtual Procedure CreateProcedure(Address entryPoint)
        {
            // If there is already a procedure defined at the given entry
            // point, return that procedure.
            Procedure proc = Procedures.Find(entryPoint);
            if (proc != null)
                return proc;

            // Create a procedure at the entry point. The entry point must be
            // be the first byte of a basic block, or otherwise some flow
            // analysis error must have occurred. On the other hand, note
            // that multiple procedures may share one or more basic blocks
            // as part of their implementation.
            proc = new Procedure(entryPoint);
            AddBasicBlocksToProcedure(proc);
            //proc.Name = "TBD";

            // To determine the call type of the procedure, examine the
            // features of the basic blocks.
            CodeFeatures features = proc.Features;
            #if false
            foreach (BasicBlock block in proc.BasicBlocks)
            {
                features |= block.Features;
            }
            #endif

            CodeFeatures callFeatures = features & (
                CodeFeatures.HasRETN | CodeFeatures.HasRETF | CodeFeatures.HasIRET);
            switch (callFeatures)
            {
                case CodeFeatures.HasRETN:
                    proc.ReturnType |= ReturnType.Near;
                    break;
                case CodeFeatures.HasRETF:
                    proc.ReturnType |= ReturnType.Far;
                    break;
                case CodeFeatures.HasIRET:
                    proc.ReturnType |= ReturnType.Interrupt;
                    break;
                case CodeFeatures.None:
                    AddError(entryPoint, ErrorCode.InconsistentCall,
                        "Procedure at entry point {0} does not contain a RET/RETF/IRET instruction.",
                        entryPoint);
                    break;
                default:
                    AddError(entryPoint, ErrorCode.InconsistentCall,
                        "Procedure at entry point {0} contains inconsistent return instructions: {1}.",
                        entryPoint, callFeatures);
                    break;
            }
            return proc;
        }
        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 CreateFallThroughXRef(Address source, Address target)
 {
     XRef xref = new XRef(
         type: XRefType.FallThrough,
         source: source,
         target: target
         );
     return xref;
 }
        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
            );
        }
 protected void AddError(
     Address location, ErrorCode errorCode,
     string format, params object[] args)
 {
     Errors.Add(new Error(location, errorCode, string.Format(format, args)));
 }
 /// <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);
         }
     }
 }