Newer
Older
#include <fpro.h>
#include <bytes.hpp>
#include <kernwin.hpp>
#include "interfaces/STARSTypes.h"
#include "interfaces/STARSIDATypes.h"
#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"
using namespace std;
int STARS_IDA_Interface_t::STARS_fprintf(FILE *fp, const char *format, ...) {
va_list va;
va_start(va, format);
int code = qvfprintf(fp, format, va);
va_end(va);
return code;
}
int STARS_IDA_Interface_t::STARS_fscanf(FILE *fp, const char *format, ...) {
va_list va;
va_start(va, format);
int code = qvfscanf(fp, format, va);
va_end(va);
return code;
}
long STARS_IDA_Interface_t::STARS_ftell(FILE *fp) {
return (long) qftell(fp);
}
char * STARS_IDA_Interface_t::STARS_fgets(char *buffer, int buflen, FILE *fp) {
return qfgets(buffer, buflen, fp);
}
int STARS_IDA_Interface_t::STARS_fseek(FILE *fp, long offset, int whence) {
return qfseek(fp, offset, whence);
}
int STARS_IDA_Interface_t::STARS_msg(const char *format, ...) {
va_list va;
va_start(va, format);
int nbytes = vmsg(format, va);
va_end(va);
return nbytes;
}
int STARS_IDA_Interface_t::STARS_snprintf(char *buffer, std::size_t n, const char *format, ...) {
va_list va;
va_start(va, format);
int code = qvsnprintf(buffer, n, format, va);
va_end(va);
return code;
}
// 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.
std::size_t NumChunks = get_fchunk_qty();
for (std::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.
STARS_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()) {
STARS_ea_t parent = FuncParent.parent();
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#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);
#if SMP_DEBUG_CHUNKS
::get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1);
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 (std::size_t FuncIndex = 0; FuncIndex < global_STARS_program->GetFuncBoundsSize(); ++FuncIndex) {
CurrFunc = global_STARS_program->GetFuncBounds(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 (std::size_t FuncIndex = 0; ...)
if (0 >= BestCandidate) { // highly unlikely
SMP_msg("No good func entry parent candidate.\n");
}
else {
FuncInfo = ::get_func(BestCandidate);
#if SMP_DEBUG_CHUNKS
::get_func_name(FuncInfo->startEA, FuncName, sizeof(FuncName) - 1);
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 (std::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 = SMP_get_item_end(StartAddr); addr < SegLimit; addr = SMP_get_item_end(addr)) {
if (SMP_isCode(InstrFlags) && SMP_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()
bool STARS_IDA_Interface_t::InstHasNoCodeXrefs(STARS_InstructionID_t InstID) const {
SMP_xref_t CurrXrefs;
STARS_ea_t InstAddr = InstID.GetIDWithinFile();
bool FoundCodeXref = false;
for (bool ok = CurrXrefs.SMP_first_to(InstAddr, XREF_ALL); ok; ok = CurrXrefs.SMP_next_to()) {
STARS_ea_t FromAddr = CurrXrefs.GetFrom();
if ((FromAddr != 0) && (CurrXrefs.GetIscode())) {
FoundCodeXref = true;
break;
}
}
return (!FoundCodeXref);
} // end of STARS_IDA_Interface_t::InstHasNoCodeXrefs()
bool STARS_IDA_Interface_t::IsInstJumpTarget(STARS_InstructionID_t InstID) const {
// Determine whether the instruction is a jump target by looking
// at its cross references and seeing if it has "TO" code xrefs.
bool InstIsJumpTarget = false;
SMP_xref_t xrefs;
// TODO: Why XREF_FAR? What about near jumps?
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
for (bool ok = xrefs.SMP_first_to(InstID.GetIDWithinFile(), XREF_FAR); ok; ok = xrefs.SMP_next_to()) {
if ((xrefs.GetFrom() != 0) && (xrefs.GetIscode())) {
InstIsJumpTarget = true;
break;
}
}
return InstIsJumpTarget;
}
STARS_InstructionID_t STARS_IDA_Interface_t::FindFirstCallTarget(STARS_InstructionID_t CallInstID) const {
SMP_xref_t xrefs;
STARS_ea_t CallTarget = STARS_BADADDR;
STARS_ea_t CallInstAddr = CallInstID.GetIDWithinFile();
for (bool ok = xrefs.SMP_first_from(CallInstAddr, XREF_ALL); ok; ok = xrefs.SMP_next_from()) {
if ((xrefs.GetTo() != 0) && (xrefs.GetIscode())) {
// Found a code target, with its address in xrefs.to
// Exclude the ordinary fall-through control flow type, fl_F
if (xrefs.GetIscode() && (xrefs.GetType() == fl_F)) {
// A call instruction will have two targets: the fall through to the
// next instruction, and the called function. We want to find
// the called function.
continue;
}
// We found a target, not the fall-through.
CallTarget = xrefs.GetTo();
SMP_msg("Found indirect call target %lx at %lx\n", (unsigned long) CallTarget, (unsigned long) CallInstAddr);
break;
}
} // end for all code xrefs
if (STARS_BADADDR == CallTarget)
SMP_msg("WARNING: Did not find indirect call target at %lx\n", (unsigned long) CallInstAddr);
return STARS_InstructionID_t(CallTarget);
} // end of STARS_IDA_Interface_t::FindFirstCallTarget()
// 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.
std::size_t NumChunks = get_fchunk_qty();
for (std::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;
STARS_ea_t addr = ChunkInfo->startEA;
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
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 (STARS_ea_t addr = ChunkInfo->startEA; addr < ChunkInfo->endEA;
addr = SMP_get_item_end(addr)) {
flags_t InstrFlags = SMP_getFlags(addr);
if (SMP_isCode(InstrFlags) && SMP_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()) {
STARS_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.
STARS_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 (std::size_t ChunkIndex = 0; ... )