public IntPtr IdentifyFunctionStartAddress(IntPtr address) { if (!this.IsOpen) { return IntPtr.Zero; } if (!SysInteractor.IsInitialized) { SysInteractor.Init(); } Page p = null; IntPtr baseAddress = new IntPtr((address.ToInt64() / SysInteractor.PageSize) * SysInteractor.PageSize); foreach (Page cachedPage in this.pageCache) { if (cachedPage.Address.ToInt64() == baseAddress.ToInt64()) { p = cachedPage; break; } } if (p == null) { p = new Page(); p.Address = baseAddress; if (!this.Read(p.Address, p.Data)) { return IntPtr.Zero; } } if (p.InstructionsDecomposed.Length == 0 || p.InstructionsDisassembled.Count == 0) { if (this.Is64Bit) { if (!p.Disassemble(Distorm.DecodeType.Decode64Bits)) { return IntPtr.Zero; } } else { if (!p.Disassemble(Distorm.DecodeType.Decode32Bits)) { return IntPtr.Zero; } } } long targetInstIndex = -1; for (long i = 0; i < p.Data.Length; ++i) { if (p.InstructionsDecomposed[i].addr == (ulong)address.ToInt64()) { targetInstIndex = i; } } if (targetInstIndex == -1) { return IntPtr.Zero; } for (long i = targetInstIndex; i >= 0; --i) { //if (p.InstructionsDecomposed[i].InstructionType == Distorm.InstructionType.) } return IntPtr.Zero; }
/// <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; }