diff --git a/include/interfaces/abstract/STARSInterface.h b/include/interfaces/abstract/STARSInterface.h index f9fc3713576677a559e90888e48a0c430cbb2f27..8fe44b4be925172ecfd880c66df338b4453f294c 100644 --- a/include/interfaces/abstract/STARSInterface.h +++ b/include/interfaces/abstract/STARSInterface.h @@ -104,7 +104,7 @@ class STARS_Interface_t // Detect IDA Pro func boundary problems, if code segment range; true if problems found virtual bool AuditFunctionBoundaries(const STARS_ea_t startEA, const STARS_ea_t endEA) const = 0; // Detect IDA Pro func boundary problems using EH_FRAME FDE info; true if problems found - virtual bool AuditEHFunctionBoundaries(void) const = 0; + virtual bool AuditEHFunctionBoundaries(void) = 0; virtual bool STARS_patch_byte(STARS_ea_t InstAddr, uint32_t ByteValue) = 0; // Patch IDA Pro database. diff --git a/include/interfaces/idapro/STARSInterface.h b/include/interfaces/idapro/STARSInterface.h index 87f227ff9c0aee2c310105464abc85f047831e0f..d7e5f4d6577017f17761503299f6ffe974820fc3 100644 --- a/include/interfaces/idapro/STARSInterface.h +++ b/include/interfaces/idapro/STARSInterface.h @@ -146,7 +146,7 @@ public: // Detect IDA Pro func boundary problems, if code segment range; true if problems found virtual bool AuditFunctionBoundaries(const STARS_ea_t startEA, const STARS_ea_t endEA) const; // Detect IDA Pro func boundary problems using EH_FRAME FDE info; true if problems found - virtual bool AuditEHFunctionBoundaries(void) const; + virtual bool AuditEHFunctionBoundaries(void); virtual bool STARS_patch_byte(STARS_ea_t InstAddr, uint32_t ByteValue); // Patch IDA Pro database. @@ -154,25 +154,33 @@ private: bool CGCBinary; - STARS_Segment_t* seg2Seg(segment_t* seg) - { - if (!seg) - return NULL; - if (segmap[seg] == NULL) - segmap[seg] = new STARS_IDA_Segment_t(seg); - return segmap[seg]; - } - std::map<segment_t*, STARS_Segment_t*> segmap; - - STARS_Function_t* func2Func(func_t* f) - { - if (!f) - return NULL; - if (funcmap[f] == NULL) - funcmap[f] = new STARS_IDA_Function_t(f); - return funcmap[f]; - } - std::map<func_t*, STARS_Function_t*> funcmap; + STARS_Segment_t* seg2Seg(segment_t* seg) + { + if (!seg) + return NULL; + if (segmap[seg] == NULL) + segmap[seg] = new STARS_IDA_Segment_t(seg); + return segmap[seg]; + } + std::map<segment_t*, STARS_Segment_t*> segmap; + + STARS_Function_t* func2Func(func_t* f) + { + if (!f) + return NULL; + if (funcmap[f] == NULL) + funcmap[f] = new STARS_IDA_Function_t(f); + return funcmap[f]; + } + std::map<func_t*, STARS_Function_t*> funcmap; + + // From StartAddr to LimitAddr - 1, make IDA Pro re-analyze so that one function contains all addrs. + // StartFunc is current IDA Pro func for StartAddr, EndFunc is current IDA Pro func for LimitAddr - 1. + // A nullptr value for either one indicates orphaned code, outside of any function. + bool RedefineIDAFuncBounds(func_t *StartFunc, func_t *EndFunc, const STARS_ea_t StartAddr, const STARS_ea_t LimitAddr); + + // From StartAddr to LimitAddr - 1, do we have nothing but no-op instructions? + bool IsNopInstSequence(const STARS_ea_t StartAddr, const STARS_ea_t LimitAddr); }; diff --git a/include/interfaces/irdb/STARSInterface.h b/include/interfaces/irdb/STARSInterface.h index 49c208e7048ab8e65db77819b341f8021908631e..ad9f4cf43f38d9e6ece876a26886df010c0b37af 100644 --- a/include/interfaces/irdb/STARSInterface.h +++ b/include/interfaces/irdb/STARSInterface.h @@ -213,7 +213,7 @@ public: // Detect IDA Pro func boundary problems, if code segment; true if problems found virtual bool AuditFunctionBoundaries(const STARS_ea_t startEA, const STARS_ea_t endEA) const { return false; }; // Detect IDA Pro func boundary problems using EH_FRAME FDE info; true if problems found - virtual bool AuditEHFunctionBoundaries(void) const { return false; }; + virtual bool AuditEHFunctionBoundaries(void) { return false; }; // Patch IDA Pro database. virtual bool STARS_patch_byte(STARS_ea_t InstAddr, uint32_t ByteValue) diff --git a/src/drivers/idapro/SMPStaticAnalyzer.cpp b/src/drivers/idapro/SMPStaticAnalyzer.cpp index 7d82886fa9793e8d1f4e4a5e234faced21c621c1..21d8557a4cec282b47fea0da5461384a11c02db9 100644 --- a/src/drivers/idapro/SMPStaticAnalyzer.cpp +++ b/src/drivers/idapro/SMPStaticAnalyzer.cpp @@ -1169,7 +1169,7 @@ bool MDPatchUnconvertedBytes(STARS_ea_t CurrDisasmAddr) { } SMPInstr PatchInstr(CurrDisasmAddr); PatchInstr.Analyze(); - int InstrLen = PatchInstr.GetSize(); + int InstrLen = (int) PatchInstr.GetSize(); if (0 >= InstrLen) { #if SMP_DEBUG_FIXUP_IDB SMP_msg("decode_insn() failed on patch location %x\n", CurrDisasmAddr); @@ -1430,7 +1430,7 @@ int FixupNewCodeChunks(void) { } list<STARS_ea_t>::iterator CurrInstr; for (CurrInstr = CurrRegion->FixupInstrs.begin(); CurrInstr != CurrRegion->FixupInstrs.end(); ++CurrInstr) { - int InstrLen = create_insn(*CurrInstr); + int InstrLen = ::create_insn(*CurrInstr); if (InstrLen > 0) { // Successfully converted to code SMPInstr NewInstr(*CurrInstr); NewInstr.Analyze(); diff --git a/src/interfaces/idapro/STARSInterface.cpp b/src/interfaces/idapro/STARSInterface.cpp index 46d588ea3edb164f59e6297ff36fa740dc3c26b5..d0e2d7ca6623dc0e2784ae9f911774027a4c8cda 100644 --- a/src/interfaces/idapro/STARSInterface.cpp +++ b/src/interfaces/idapro/STARSInterface.cpp @@ -9,7 +9,7 @@ #include "base/SMPFunction.h" #include "base/SMPProgram.h" -#define STARS_USE_EHP_LIB 0 +#define STARS_USE_EHP_LIB 1 #if STARS_USE_EHP_LIB #ifdef __X64__ #include <ehp.hpp> // SMPStaticAnalyzer/libehp/include/ehp.hpp @@ -467,10 +467,13 @@ bool STARS_IDA_Interface_t::AuditFunctionBoundaries(const STARS_ea_t startEA, co } // end of STARS_IDA_Interface_t::AuditFunctionBoundaries() // Detect IDA Pro func boundary problems using EH_FRAME FDE info; true if problems found -bool STARS_IDA_Interface_t::AuditEHFunctionBoundaries(void) const { +bool STARS_IDA_Interface_t::AuditEHFunctionBoundaries(void) { bool ProblemFound = false; #if STARS_USE_EHP_LIB #ifdef __X64__ // stub out for 32-bit plugins; libehp is 64 bits + if (64 > global_STARS_program->GetSTARS_ISA_Bitwidth()) + return ProblemFound; // stub out for 32-bit binaries, also + // Use the FDEs (Frame Descriptor Entries) from the eh_frame section // to perform the same algorithm as above: an FDE should contain only one func. const string ExeFileName = global_STARS_program->GetRootFileName(); @@ -487,9 +490,23 @@ bool STARS_IDA_Interface_t::AuditEHFunctionBoundaries(void) const { func_t *EndFunc = ::get_func(CurrEndEA - 1); if (StartFunc != EndFunc) { - ProblemFound = true; - SMP_msg("ERROR: FUNCBOUNDS: FDE range from %llx to %llx spans functions\n", - (uint64_t) CurrStartEA, (uint64_t) (CurrEndEA - 1)); + STARS_Segment_t *FuncSeg = this->getseg(CurrStartEA); + assert(nullptr != FuncSeg); + char SegName[STARS_MAXSTR]; + STARS_ssize_t SegNameLen = FuncSeg->GetSegmentName(SegName, STARS_MAXSTR - 1); + assert(0 < SegNameLen); + const bool PLTflag = (nullptr != strstr(SegName, "plt")); + const bool DYNflag = (nullptr != strstr(SegName, "dyn")); + if (!(PLTflag || DYNflag)) { + ProblemFound = true; + SMP_msg("INFO: FUNCBOUNDS: FDE range from %llx to %llx spans functions in segment %s\n", + (uint64_t) CurrStartEA, (uint64_t) (CurrEndEA - 1), SegName); + bool success = this->RedefineIDAFuncBounds(StartFunc, EndFunc, CurrStartEA, CurrEndEA); + if (success) + SMP_msg("INFO: Redefined IDA FuncBounds successfully.\n"); + else + SMP_msg("ERROR: Failed to redefine IDA FuncBounds.\n"); + } } } // end for (const auto FDEveciter : *FDEvecptr) @@ -501,5 +518,109 @@ bool STARS_IDA_Interface_t::AuditEHFunctionBoundaries(void) const { // Patch IDA Pro database. bool STARS_IDA_Interface_t::STARS_patch_byte(STARS_ea_t InstAddr, uint32_t ByteValue) { - return patch_byte(InstAddr, ByteValue); + return ::patch_byte(InstAddr, ByteValue); } + +// From StartAddr to LimitAddr - 1, make IDA Pro re-analyze so that one function contains all addrs. +// StartFunc is current IDA Pro func for StartAddr, EndFunc is current IDA Pro func for LimitAddr - 1. +// A nullptr value for either one indicates orphaned code, outside of any function. +bool STARS_IDA_Interface_t::RedefineIDAFuncBounds(func_t *StartFunc, func_t *EndFunc, const STARS_ea_t StartAddr, const STARS_ea_t LimitAddr) { + bool success = false; + const bool NullStartFunc = (nullptr == StartFunc); + const bool NullEndFunc = (nullptr == EndFunc); + const STARS_ea_t EndFuncStartAddr = NullEndFunc ? STARS_BADADDR : EndFunc->start_ea; + const STARS_ea_t StartFuncEndAddr = NullStartFunc ? STARS_BADADDR : StartFunc->end_ea; + + // Case 1: Orphaned code at StartAddr, make EndFunc start at StartAddr. + if (NullStartFunc && (!NullEndFunc)) { + if (this->IsNopInstSequence(StartAddr, EndFuncStartAddr)) { + SMP_msg("INFO: FUNCBOUNDS: Earlier orphaned code at %llx all nops, ignoring.\n", (uint64_t)StartAddr); + } + else { + int ReturnCode = ::set_func_start(LimitAddr - 1, StartAddr); + success = (ReturnCode == MOVE_FUNC_OK); + if (success) { + ::reanalyze_function(EndFunc); + SMP_msg("INFO: FUNCBOUNDS: Success: Earlier orphaned code at %llx merged into func after it.\n", + (uint64_t)StartAddr); + } + else { + SMP_msg("ERROR: FUNCBOUNDS: IDA set_func_start() returned code %d\n", ReturnCode); + } + } + } + else if (!NullStartFunc && NullEndFunc) { + // Case 2: Orphaned code after the first function; extend StartFunc to EndAddr. + if (this->IsNopInstSequence(StartFuncEndAddr, LimitAddr)) { + SMP_msg("INFO: FUNCBOUNDS: Later orphaned code at %llx all nops, ignoring.\n", (uint64_t)StartFuncEndAddr); + } + else { + success = ::set_func_end(StartAddr, LimitAddr); + if (success) { + ::reanalyze_function(StartFunc); + SMP_msg("INFO: FUNCBOUNDS: Success: Later orphaned code up to %llx merged into func before it.\n", + (uint64_t)(LimitAddr - 1)); + } + else { + SMP_msg("ERROR: FUNCBOUNDS: IDA set_func_end() returned false\n"); + } + } + } + else if (!NullStartFunc && (!NullEndFunc)) { + // Two funcs. If the two funcs occupy exactly the range specified by the FDE, then combine + // them into one function. + if ((EndFunc->end_ea == LimitAddr) && (StartFunc->end_ea == EndFuncStartAddr) && (StartAddr == StartFunc->start_ea)) { + // Delete the second function and expand the first function to take its space, then + // reanalyze the new function. + success = ::del_func(EndFuncStartAddr); + if (success) { + success = ::set_func_end(StartAddr, LimitAddr); + if (success) { + ::reanalyze_function(StartFunc); + SMP_msg("INFO: FUNCBOUNDS: Success: Later func at %llx merged into func before it starting at %llx.\n", + (uint64_t) EndFuncStartAddr, (uint64_t) StartAddr); + } + else { + SMP_msg("ERROR: FUNCBOUNDS: IDA set_func_end() returned false in two-function case.\n"); + // Undo the damage caused by deleting the EndFunc. + const bool success2 = ::add_func(EndFuncStartAddr, LimitAddr); + if (!success2) { + SMP_msg("ERROR: FUNCBOUNDS: add_func() failed on deleted func from %llx to %llx\n", + (uint64_t) EndFuncStartAddr, (uint64_t) LimitAddr); + } + SMP_msg("INFO: FUNCBOUNDS: Damage undone successfully.\n"); + } + } + else { + SMP_msg("ERROR: FUNCBOUNDS: del_func() failed on address %llx\n.", (uint64_t) EndFunc->start_ea); + } + } + else { + SMP_msg("INFO: FUNCBOUNDS: RedefineIDAFuncBounds() was passed two separate funcs not filling the FDE range, did nothing.\n"); + } + } + else { + SMP_msg("ERROR: FUNCBOUNDS: RedefineIDAFuncBounds() was passed no funcs.\n"); + } + // Other cases are too complex for now. + + return success; +} // end of STARS_IDA_Interface_t::RedefineIDAFuncBounds() + +// From StartAddr to LimitAddr - 1, do we have nothing but no-op instructions? +bool STARS_IDA_Interface_t::IsNopInstSequence(const STARS_ea_t StartAddr, const STARS_ea_t LimitAddr) { + bool NopSequence = true; + for (STARS_ea_t addr = StartAddr; addr < LimitAddr; addr = SMP_get_item_end(addr)) { + flags_t InstrFlags = SMP_getFlags(addr); + if (SMP_isHead(InstrFlags) && SMP_isCode(InstrFlags)) { + SMPInstr TempInst(addr); + TempInst.Analyze(); + int InstrLen = (int) TempInst.GetSize(); + if ((0 >= InstrLen) || (!TempInst.IsNop())) { + NopSequence = false; + break; + } + } + } + return NopSequence; +} // end of STARS_IDA_Interface_t::IsNopInstSequence()