Skip to content
Snippets Groups Projects
STARSInterface.cpp 9 KiB
Newer Older
jdh8d's avatar
jdh8d committed
#include <list>

#include "interfaces/SMPDBInterface.h"
#include "interfaces/abstract/all.h"
#include "interfaces/idapro/all.h"
#include "base/SMPBasicBlock.h"
#include "base/SMPFunction.h"
#include "base/SMPProgram.h"
#include "base/SMPStaticAnalyzer.h"

using namespace std;

// The choices that IDA makes for deciding which parent function of a
//  TAIL chunk is the primary owner of the tail can be counterintuitive.
//  A function entry can both fall into and jump to a tail chunk that
//  is contiguous with it, yet the "owner" might be a function that is
//  far below it in the executable address space. This function will
//  change the ownership to a more sensible arrangement.
void STARS_IDA_Interface_t::AuditTailChunkOwnership(void) 
{
	char FuncName[MAXSTR];
	// Iterate through all chunks in the program.
	size_t NumChunks = get_fchunk_qty();
	for (size_t ChunkIndex = 0; ChunkIndex < NumChunks; ++ChunkIndex) {
		func_t *ChunkInfo = getn_fchunk((int) ChunkIndex);
		if (is_func_tail(ChunkInfo)) {
			// For each TAIL chunk, find all the parent chunks. Find the last
			//  parent chunk with an address less than the TAIL chunk address.
			ea_t BestCandidate = 0;
			func_parent_iterator_t FuncParent(ChunkInfo);
#if SMP_DEBUG_CHUNKS
			SMP_msg("Tail chunk: %x ", ChunkInfo->startEA);
#endif
			for (bool ok = FuncParent.first(); ok; ok = FuncParent.next()) {
				ea_t parent = FuncParent.parent();
#if SMP_DEBUG_CHUNKS
				SMP_msg(" parent: %x ", parent);
#endif
				if ((parent > BestCandidate) && (parent < ChunkInfo->startEA))
					BestCandidate = parent;
			}
#if SMP_DEBUG_CHUNKS
			SMP_msg("\n");
#endif
			//  Make the best parent chunk the owner of the TAIL chunk if it is
			//  not already the owner.
			if (ChunkInfo->owner != BestCandidate) {
				if (0 < BestCandidate) {
					if (set_tail_owner(ChunkInfo, BestCandidate)) {
						func_t *FuncInfo = ::get_func(BestCandidate);
						SMP_msg("Set %lx as new owner of tail %lx\n",
							(unsigned long) BestCandidate, (unsigned long) ChunkInfo->startEA);
						// Reanalyze the parent function (and all its
						//  tail chunks) now that the structure has changed.
						reanalyze_function(FuncInfo);
					}
					else {
						SMP_msg("set_tail_owner failed for tail %lx and parent %lx\n",
							(unsigned long) ChunkInfo->startEA, (unsigned long) BestCandidate);
					}
				}
				else {
					func_t *FuncInfo = ::get_func(ChunkInfo->owner);
					::get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1);
#if SMP_DEBUG_CHUNKS
					SMP_msg("No good parent candidate before tail at %x\n",
						ChunkInfo->startEA);
					SMP_msg("Current parent is %x: %s\n", FuncInfo->startEA, FuncName);
#endif
					// Find out if a function entry chunk that comes before the
					//  tail is a better candidate for the owner (i.e. it falls
					//  through to the tail, or jumps to it).
					BestCandidate = 0;
#if SMP_DEBUG_CHUNKS
					SMP_msg("Finding parent func candidates for %x:", ChunkInfo->startEA);
#endif
					SMP_bounds_t CurrFunc;
					for (size_t FuncIndex = 0; FuncIndex < FuncBounds.size(); ++FuncIndex) {
						CurrFunc = FuncBounds[FuncIndex];
						if ((CurrFunc.startEA < ChunkInfo->startEA)
							&& (CurrFunc.startEA > BestCandidate)) {
							BestCandidate = CurrFunc.startEA;
#if SMP_DEBUG_CHUNKS
							SMP_msg(" candidate: %x tail: %x", BestCandidate,
								ChunkInfo->startEA);
#endif
						}
						else {
#if SMP_DEBUG_CHUNKS
							SMP_msg(" not a candidate: %x tail: %x best: %x\n",
								CurrFunc.startEA, ChunkInfo->startEA, BestCandidate);
#endif
							break;
						}
					} // end for (size_t FuncIndex = 0; ...)
					if (0 >= BestCandidate) { // highly unlikely
						SMP_msg("No good func entry parent candidate.\n");
					}
					else {
						FuncInfo = ::get_func(BestCandidate);
						get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1);
#if SMP_DEBUG_CHUNKS
						SMP_msg("Best func entry parent candidate: %s at %x",
							FuncName, BestCandidate);
						if (FuncInfo->endEA == ChunkInfo->startEA)
							SMP_msg(" Function endEA == tail chunk startEA");
						SMP_msg("\n");
#endif
					}
				}
			} // end if (ChunkInfo->owner != BestCandidate)
#if SMP_DEBUG_CHUNKS
			else {
				SMP_msg("Already best parent for %x is %x\n", ChunkInfo->startEA,
					ChunkInfo->owner);
			}
#endif
		} // end if (is_func_tail(ChunkInfo))
	} // end for (size_t ChunkIndex = 0; ...)

	return;
} // end of AuditTailChunkOwnership()


// Find the span of contiguous code that is not contained within any
//  function, starting at StartAddr, which should already be an example
//  of an instruction address that is outside of a function.
static STARS_ea_t FindNewFuncLimit(STARS_ea_t StartAddr) 
{

	STARS_ea_t LimitAddr = StartAddr;
	STARS_Segment_t *seg = SMP_getseg(StartAddr);
	if (NULL == seg)
		return LimitAddr;
	STARS_ea_t SegLimit = seg->get_endEA();

	for (STARS_ea_t addr = get_item_end(StartAddr); addr < SegLimit; addr = get_item_end(addr)) {
		flags_t InstrFlags = getFlags(addr);
		if (isCode(InstrFlags) && isHead(InstrFlags)) {
			LimitAddr = addr;
			func_t *FuncInfo = get_func(addr);
			if (NULL != FuncInfo)
				break; // ran into an existing function
		}
		else // Not a code head; time to stop.
			break;
	}
	return LimitAddr;
} // end of FindNewFuncLimit()

// Audit the IDA database with respect to branches and calls. They should
//  each have valid code targets (not data or unknown bytes) and the code
//  cross references should reflect the linkage.
void STARS_IDA_Interface_t::AuditCodeTargets(void) 
{
	// Cover all the code that IDA has grouped into functions by iterating
	//  through all function chunks in the program.
	size_t NumChunks = get_fchunk_qty();
	for (size_t ChunkIndex = 0; ChunkIndex < NumChunks; ++ChunkIndex) {
		func_t *ChunkInfo = getn_fchunk((int) ChunkIndex);
		char FuncName[MAXSTR];
		get_func_name(ChunkInfo->startEA, FuncName, sizeof(FuncName) - 1);

		// First, see if any calls to this function (if this chunk is
		//  an entry point) are not coming from within functions.
		if (is_func_entry(ChunkInfo)) {
			SMP_xref_t xb;
			ea_t addr = ChunkInfo->startEA;
			for (bool ok = xb.SMP_first_to(addr, XREF_ALL);	ok; ok = xb.SMP_next_to()) {
				uchar XrefType = xb.GetType() & XREF_MASK;
				if (xb.GetIscode()) {
					if ((XrefType == fl_U) || (XrefType == fl_USobsolete)) {
						SMP_msg("AUDIT: Bad xref type: %lx %s\n", (unsigned long) addr, FuncName);
					}
#if SMP_DEBUG_FIXUP_IDB
					else if ((XrefType == fl_JF) || (XrefType == fl_JN)) {
						SMP_msg("Jump to func: %x %s from: %x\n",
							addr, FuncName, xb.GetFrom());
					}
#endif
					else if (XrefType == fl_F) {
						SMP_msg("AUDIT: Fall through to func: %lx %s from: %lx\n",
							(unsigned long) addr, FuncName, (unsigned long) xb.GetFrom());
					}
					else if ((XrefType == fl_CF) || (XrefType == fl_CN)) {
						// Far call or Near call
						func_t *CallingFunc = ::get_func(xb.GetFrom());
						if (NULL == CallingFunc) {
							;
#if SMP_DEBUG_FIXUP_IDB
							SMP_msg("Call to %x Func %s from %x not in function.\n",
								addr, FuncName, xb.GetFrom());
#endif
						}
					}
				} // end if (xb.GetIscode())
				else { // DATA xref
					if (XrefType == dr_O) {
#if SMP_DEBUG_FIXUP_IDB
						SMP_msg("Data xref to %x Func %s from %x\n",
							addr, FuncName, xb.GetFrom());
#endif
					}
					else {
						SMP_msg("AUDIT: Strange data xref %d to %lx Func %s from %lx\n",
							XrefType, (unsigned long) addr, FuncName, (unsigned long) xb.GetFrom());
					}
				}
			} // end for (bool ok = xb.SMP_first_to(); ...)
		} // end if (is_func_entry(ChunkInfo))

		// Next, see if any call or branch in this chunk references
		//  a target address that is not in a function. If so, and the
		//  callee address code looks like a function prologue, then
		//  create a function for the contiguous code starting at that
		//  address and ask IDA to analyze it and store it in the
		//  IDA database. If it is a branch target, not a call target,
		//  create a new TAIL chunk for the current parent functions.
		for (ea_t addr = ChunkInfo->startEA; addr < ChunkInfo->endEA;
			addr = get_item_end(addr)) {
			flags_t InstrFlags = getFlags(addr);
			if (isCode(InstrFlags) && isHead(InstrFlags)) {
				SMPInstr CurrInst(addr);
				CurrInst.Analyze();
				if ((CALL|JUMP|COND_BRANCH) & CurrInst.GetDataFlowType()) {
					SMP_xref_t xb;
					for (bool ok = xb.SMP_first_from(addr, XREF_FAR); ok; ok = xb.SMP_next_from()) {
						if (xb.GetIscode()) {
							ea_t FirstAddr = xb.GetTo();
							func_t *FuncInfo = ::get_func(FirstAddr);
							if (NULL == FuncInfo) {
								// Found call to addr that is not in a func.
								// Find limits of contiguous code starting at FirstAddr.
								ea_t LastAddr = FindNewFuncLimit(FirstAddr);
								if (CALL == CurrInst.GetDataFlowType())
									SMP_msg("AUDIT: Found new func from %lx to %lx\n",
										(unsigned long) FirstAddr, (unsigned long) LastAddr);
								else
									SMP_msg("AUDIT: Found new chunk from %lx to %lx\n",
										(unsigned long) FirstAddr, (unsigned long) LastAddr);
							}
						}
					}
				}
			}
		}
	} // end for (size_t ChunkIndex = 0; ... )

	return;
} // end of AuditCodeTargets()