示例#1
0
        private static void ComputeMore(
            HashAlgorithm hasher, Procedure procedure, BinaryImage image)
        {
            // TODO: add the traversal logic into Graph class.
            // or maybe GraphAlgorithms.Traversal(...).

            // Create a queue to simulate breadth-first-search. It doesn't
            // really matter whether DFS or BFS is used as long as we stick
            // to it, but BFS has the benefit that it's easier to understand.
            // Therefore we use it.
            Queue <Address> queue = new Queue <Address>();

            queue.Enqueue(procedure.EntryPoint);

            // Map the entry point address of a basic block to its index
            // in the sequence of blocks visited. Each block that is the
            // target of a none-fall-through control flow edge is assigned
            // an index the first time it is encountered. This index is
            // included in the hash to provide a hint of the graph's
            // structure.
            Dictionary <Address, int> visitOrder = new Dictionary <Address, int>();

            XRefCollection cfg = image.BasicBlocks.ControlFlowGraph.Graph;

            // Traverse the graph.
            while (queue.Count > 0)
            {
                Address source = queue.Dequeue();

                // Check if this block has been visited before. If it has,
                // we just hash its order and work on next one.
                int order;
                if (visitOrder.TryGetValue(source, out order)) // visited
                {
                    ComputeMore(hasher, order);
                    continue;
                }

                // If the block has not been visited, assign a unique order
                // to it, and hash this order.
                order = visitOrder.Count;
                visitOrder.Add(source, order);
                ComputeMore(hasher, order);

                // Next, we hash the instructions in the block. We follow any
                // fall-through edges so that the resulting hash will not be
                // affected by artificial blocks. To see this, consider the
                // following example:
                //
                // MySub:                LibSub1:
                //       mov ax, bx            mov ax, bx
                //                       LibSub2:
                //       mov bx, cx            mov bx, cx
                //       ret                   ret
                //
                // MySub and LibSub1 are identical procedures with three
                // instructions. However, if someone calls into the middle of
                // LibSub1, the block must be split in two and a fall-through
                // edge is created from LibSub1 to LibSub2. If we don't follow
                // the fall-through edge, it will generate a different hash
                // from the left-side one.
                while (true)
                {
                    BasicBlock block = image.BasicBlocks.Find(source);
                    System.Diagnostics.Debug.Assert(block != null);

                    // Hash the instructions in the block. Only the opcode
                    // part of each instruction is hashed; the displacement
                    // and immediate parts are potentially subject to fix-up,
                    // and are therefore ignored in the hash.
                    ComputeMore(hasher, block, image);

                    // Enumerate each block referred to from this block.
                    // We must order the (none-fall-through) outgoing flow
                    // edges in a way that depends only on the graph's
                    // structure and not on the particular arrangement of
                    // target blocks. (Note: this is not a concern if we only
                    // have one none-fall-through outgoing edge; but this may
                    // be of concern if we have multiple outgoing edges, such
                    // as in an indexed jump.)
                    //
                    // TBD: handle multiple outgoing edges.
                    XRef fallThroughEdge    = null;
                    XRef nonFallThroughEdge = null;
                    foreach (XRef flow in cfg.GetReferencesFrom(source))
                    {
                        if (flow.Type == XRefType.FallThrough)
                        {
                            if (fallThroughEdge != null)
                            {
                                throw new InvalidOperationException("Cannot have more than one fall-through edge.");
                            }
                            fallThroughEdge = flow;
                        }
                        else
                        {
                            if (nonFallThroughEdge != null)
                            {
                                throw new InvalidOperationException("Cannot have more than one non-fall-through edge.");
                            }
                            nonFallThroughEdge = flow;
                        }
                    }

                    // Hash the special flow type and add target to queue.
                    if (nonFallThroughEdge != null)
                    {
                        ComputeMore(hasher, (int)nonFallThroughEdge.Type);
                        queue.Enqueue(nonFallThroughEdge.Target);
                    }

                    // Fall through to the next block if any.
                    if (fallThroughEdge != null)
                    {
                        source = fallThroughEdge.Target;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }