Ejemplo n.º 1
0
        /// <summary>
        /// Generates a new basic block that starts at the supplied base address.
        /// </summary>
        /// <param name="p">The process interactor used to read data from the target.</param>
        /// <param name="baseAddress">The base address of the basic block.</param>
        /// <param name="blocks">
        /// A set of basic blocks that relate to the current block through either direct or indirect connections.
        /// </param>
        /// <param name="maxDepth">
        /// The maximum number of code flow indirections to be followed. If set to -1, no maximum indirection count is
        /// enforced.
        /// </param>
        /// <returns>Returns a basic block that starts at the supplied address.</returns>
        public static BasicBlock GenerateBlock(
            PInteractor p,
            IntPtr baseAddress,
            out HashSet<BasicBlock> blocks,
            long maxDepth = -1)
        {
            SysInteractor.Init();
            blocks = new HashSet<BasicBlock>();
            HashSet<Page> pages = new HashSet<Page>();

            BasicBlock block = BasicBlock.GenerateBlock(p, baseAddress, ref blocks, ref pages, maxDepth);
            BasicBlock.RemoveDuplicateInstructions(ref blocks);

            return block;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Generates a new basic block that starts at the supplied base address.
        /// </summary>
        /// <param name="p">The process interactor used to read data from the target.</param>
        /// <param name="baseAddress">The base address of the basic block.</param>
        /// <param name="blocks">
        /// A set of basic blocks that relate to the current block through either direct or indirect connections.
        /// </param>
        /// <param name="pages">A set of pages that have been read while analyzing basic blocks.</param>
        /// <param name="maxDepth">
        /// The maximum number of code flow indirections to be followed. If set to -1, no maximum indirection count is
        /// enforced.
        /// </param>
        /// <param name="currentDepth">The current number of indirections that have been followed.</param>
        /// <returns>Returns a basic block that starts at the supplied address.</returns>
        /// <remarks>
        /// Unhandled ends to basic blocks (descriptions taken from wikipedia):
        /// - Instructions which may throw an exception
        /// - Function calls can be at the end of a basic block if they may not return, such as functions which throw
        ///   exceptions or special calls like C's longjmp and exit
        /// Unhandled beginnings to basic blocks (descriptions taken from wikipedia):
        /// - Instructions following ones that throw exceptions
        /// - Exception handlers.
        /// </remarks>
        public static BasicBlock GenerateBlock(
            PInteractor p,
            IntPtr baseAddress,
            ref HashSet<BasicBlock> blocks,
            ref HashSet<Page> pages,
            long maxDepth = -1,
            long currentDepth = 0)
        {
            // Prepare the base block.
            BasicBlock block = null;

            // If a block at this address already exists, return that block.
            foreach (BasicBlock b in blocks)
            {
                if (b.Instructions[0].Address == baseAddress)
                {
                    return b;
                }
            }

            // If the block did not exist, then create a new block.
            if (block == null)
            {
                block = new BasicBlock();
                blocks.Add(block);
            }

            // Get the address of the page where the block exists.
            Page currentPage = null;
            IntPtr pageBase = new IntPtr((baseAddress.ToInt64() / SysInteractor.PageSize) * SysInteractor.PageSize);
            foreach (Page page in pages)
            {
                if (page.Address.Equals(pageBase))
                {
                    currentPage = page;
                    break;
                }
            }

            // Read the data from the page where the block exists.
            if (currentPage == null)
            {
                currentPage = new Page();
                currentPage.Address = pageBase;
                currentPage.Data = new byte[SysInteractor.PageSize];

                if (!p.Read(currentPage.Address, currentPage.Data))
                {
                    Console.WriteLine("Unable to read address 0x" + currentPage.Address.ToInt32().ToString("x").PadLeft(8, '0'));
                    Console.WriteLine("Error: " + Marshal.GetLastWin32Error());
                    return new BasicBlock();
                }

                currentPage.Instructions =
                    BasicBlock.d.DisassembleInstructions(currentPage.Data, currentPage.Address).ToList();
                if (currentPage.Instructions.Count == 0)
                {
                    return new BasicBlock();
                }

                pages.Add(currentPage);
            }

            int i = 0;
            for (; i < currentPage.Instructions.Count; ++i)
            {
                if (currentPage.Instructions[i].Address == baseAddress)
                {
                    // Break once the instruction has been found.
                    break;
                }
                else if ((ulong)currentPage.Instructions[i].Address > (ulong)baseAddress)
                {
                    Console.WriteLine("Disassembly failed for address: 0x" + currentPage.Instructions[i].Address.ToString("x").PadLeft(8, '0'));
                    return new BasicBlock();
                }
            }

            if (i >= currentPage.Instructions.Count)
            {
                Console.WriteLine("Need to use scanner to identify and decompose regions, rather than single pages.");
                return new BasicBlock();
            }

            // Verify that no control flow instructions are added in the middle of a basic block.
            while (
                // TODO: verify this still works after adjusting the call verification logic.
                currentPage.Instructions[i].FlowType != Instruction.ControlFlow.Call &&
                currentPage.Instructions[i].FlowType != Instruction.ControlFlow.ConditionalBranch &&
                currentPage.Instructions[i].FlowType != Instruction.ControlFlow.Return &&
                currentPage.Instructions[i].FlowType != Instruction.ControlFlow.UnconditionalBranch)
            {
                // Add the non-control-modifying instructions.
                block.Instructions.Add(currentPage.Instructions[i++]);
                if (i >= currentPage.Instructions.Count)
                {
                    Console.WriteLine("Need to use scanner to identify and decompose regions, rather than single pages.");
                    return new BasicBlock();
                }
            }

            // Add the control-modifying instruction.
            block.Instructions.Add(currentPage.Instructions[i]);

            // End parsing if this is the end of the block.
            if (currentPage.Instructions[i].FlowType == Instruction.ControlFlow.Return)
            {
                return block;
            }

            // Parse the branch block.
            BasicBlock branchBlock;
            if (maxDepth == -1 || currentDepth <= maxDepth)
            {
                // TODO: verify this still works after adjusting the call verification logic.
                // This handles CND_BRANCH, UNC_BRANCH, and CALL.
                if (currentPage.Instructions[i].FlowType == Instruction.ControlFlow.Call)
                {
                    branchBlock = blocks.FirstOrDefault(
                        x => x.Instructions.Count > 0 &&
                             x.Instructions[0].Address == currentPage.Instructions[i].BranchTarget);
                    if (branchBlock == null)
                    {
                        // Do not expand calls. Add a stub block, instead.
                        branchBlock = new BasicBlock();

                        // TODO: verify that creating an invalid instruction works.
                        branchBlock.Instructions.Add(
                            Instruction.CreateInvalidInstruction(currentPage.Instructions[i].BranchTarget));
                        blocks.Add(branchBlock);
                    }
                }
                else
                {
                    branchBlock = GenerateBlock(
                        p, new IntPtr((long)currentPage.Instructions[i].BranchTarget), ref blocks, ref pages, maxDepth, currentDepth + 1);
                }

                block.Next.Add(branchBlock);
                branchBlock.Previous.Add(block);
            }

            if (currentPage.Instructions[i].FlowType == Instruction.ControlFlow.ConditionalBranch ||
                currentPage.Instructions[i].FlowType == Instruction.ControlFlow.Call)
            {
                BasicBlock nextBlock = GenerateBlock(
                    p, new IntPtr((long)currentPage.Instructions[++i].Address), ref blocks, ref pages, maxDepth, currentDepth);
                block.Next.Add(nextBlock);
                nextBlock.Previous.Add(block);
            }

            // Return results.
            return block;
        }