From cca9c3caf0601a8f31815376c1b1a64dad6d46f3 Mon Sep 17 00:00:00 2001 From: Xiaozhu Meng Date: Mon, 29 May 2017 10:01:07 -0500 Subject: [PATCH] 1. Allow jump targets to be from a jump table and multiple constant values2 2. Stop reading tables once one table entry leads to overlapping basic blocks --- parseAPI/src/IndirectASTVisitor.C | 4 ++- parseAPI/src/IndirectAnalyzer.C | 23 ++++++++++++-- parseAPI/src/IndirectAnalyzer.h | 1 + parseAPI/src/JumpTableFormatPred.C | 49 +++++++++++++++++++++++++++--- parseAPI/src/JumpTableFormatPred.h | 2 +- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index b46c430c2d..b852566179 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -272,11 +272,13 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { findIncorrectFormat = true; return AST::Ptr(); } +/* if (!b->obj()->cs()->isReadOnly(tableBase)) { parsing_printf("\ttableBase 0x%lx not read only, not jump table format\n", tableBase); findIncorrectFormat = true; return AST::Ptr(); } +*/ // Note that this table base may not be within a memory read. // Functions with variable arguments often have an indirect jump with form: // targetBase - index * 4 @@ -431,7 +433,7 @@ bool JumpTableReadVisitor::PerformMemoryRead(Address addr, int64_t &v) { addr -= cs->loadAddress(); #endif if (!cs->isCode(addr) && !cs->isData(addr)) return false; - if (!cs->isReadOnly(addr)) return false; +// if (!cs->isReadOnly(addr)) return false; switch (memoryReadSize) { case 8: v = *(const uint64_t *) cs->getPtrToInstruction(addr); diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index 2799005516..75f4467e3e 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -22,7 +22,8 @@ using namespace Dyninst::InstructionAPI; bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector >& outEdges) { parsing_printf("Apply indirect control flow analysis at %lx\n", block->last()); parsing_printf("Looking for thunk\n"); -// if (block->last() == 0x526e74) dyn_debug_parsing=1; else dyn_debug_parsing=0; + +// if (block->last() == 0xaa5be9) dyn_debug_parsing=1; else dyn_debug_parsing=0; // Find all blocks that reach the block containing the indirect jump // This is a prerequisit for finding thunks @@ -87,6 +88,7 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector &constAddr, std::vector > &targetEdges) { CodeSource *cs = block->obj()->cs(); set
jumpTargets; @@ -191,6 +194,17 @@ void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, JumpTableReadVisitor jtrv(index, v, cs, false, memoryReadSize); jumpTargetExpr->accept(&jtrv); if (jtrv.valid && cs->isCode(jtrv.targetAddress)) { + bool overlap = false; + set blocks; + block->obj()->findCurrentBlocks(block->region(), jtrv.targetAddress, blocks); + for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { + if ((*bit)->start() < jtrv.targetAddress && jtrv.targetAddress <= (*bit)->end()) { + overlap = true; + parsing_printf("WARNING: resolving jump tables leads to an address wihtin existing basic blocks (%lx)\n", jtrv.targetAddress); + break; + } + } + if (overlap) break; jumpTargets.insert(jtrv.targetAddress); } else { // We have a bad entry. We stop here, as we have wrong information @@ -200,6 +214,11 @@ void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, } if (indexBound.stride == 0) break; } + for (auto ait = constAddr.begin(); ait != constAddr.end(); ++ait) { + if (cs->isCode(*ait)) { + jumpTargets.insert(*ait); + } + } for (auto tit = jumpTargets.begin(); tit != jumpTargets.end(); ++tit) { targetEdges.push_back(make_pair(*tit, INDIRECT)); } @@ -215,7 +234,7 @@ int IndirectControlFlowAnalyzer::GetMemoryReadSize(Assignment::Ptr memLoc) { if (o.readsMemory()) { Expression::Ptr exp = o.getValue(); return exp->size(); - break; } } + return 0; } diff --git a/parseAPI/src/IndirectAnalyzer.h b/parseAPI/src/IndirectAnalyzer.h index 8f9f8d8361..d2a6c7feb0 100644 --- a/parseAPI/src/IndirectAnalyzer.h +++ b/parseAPI/src/IndirectAnalyzer.h @@ -21,6 +21,7 @@ class IndirectControlFlowAnalyzer { AbsRegion, StridedInterval &, int , + std::set
&, std::vector > &); int GetMemoryReadSize(Assignment::Ptr loc); diff --git a/parseAPI/src/JumpTableFormatPred.C b/parseAPI/src/JumpTableFormatPred.C index 3d7b4b9a53..cd98df046e 100644 --- a/parseAPI/src/JumpTableFormatPred.C +++ b/parseAPI/src/JumpTableFormatPred.C @@ -133,9 +133,46 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P } AST::Ptr rhs = exprs[p->assign()]; AST::Ptr lhs = VariableAST::create(Variable(p->assign()->out())); - // TODO: there may be more than one expression for a single variable - inputs[lhs] = rhs; + inputs.insert(make_pair(lhs, rhs)); + } + if (g->isExitNode(n)) { + // Here we try to detect the case where there are multiple + // paths to the indirect jump, and on some of the paths, the jump + // target has constnt values, and on some other path, the jump target + // may have a jump table format + int nonConstant = 0; + int match = 0; + for (auto iit = inputs.begin(); iit != inputs.end(); ++iit) { + AST::Ptr lhs = iit->first; + AST::Ptr rhs = iit->second; + if (*lhs == *exp) { + match++; + if (rhs->getID() == AST::V_ConstantAST) { + ConstantAST::Ptr c = boost::static_pointer_cast(rhs); + constAddr.insert(c->val().val); + } else { + nonConstant++; + jumpTarget = rhs; + } + } + } + if (match == 0) { + // Thiw will happen when the indirect jump directly reads from memory, + // instead of jumping to the value of a register. + exp = SymbolicExpression::SubstituteAnAST(exp, inputs); + jumpTarget = exp; + break; + } + if (nonConstant > 1) { + parsing_printf("Find %d different jump target formats\n", nonConstant); + jumpTableFormat = false; + return false; + } else if (nonConstant == 0) { + parsing_printf("Only constant target values found so far, no need to check jump target format\n"); + return true; + } + break; } // TODO: need to consider thunk exp = SymbolicExpression::SubstituteAnAST(exp, inputs); @@ -150,12 +187,16 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P working_list.push(p); } } + } + if (!jumpTarget) { + parsing_printf("\t Do not find a potential jump target expression\n"); + jumpTableFormat = false; + return false; - // The last expression should be the jump target - jumpTarget = exp; } parsing_printf("Check expression %s\n", jumpTarget->format().c_str()); JumpTableFormatVisitor jtfv(block); + assert(jumpTarget); jumpTarget->accept(&jtfv); if (jtfv.findIncorrectFormat) { jumpTableFormat = false; diff --git a/parseAPI/src/JumpTableFormatPred.h b/parseAPI/src/JumpTableFormatPred.h index 13650430e6..0fab4753ab 100644 --- a/parseAPI/src/JumpTableFormatPred.h +++ b/parseAPI/src/JumpTableFormatPred.h @@ -28,7 +28,7 @@ class JumpTableFormatPred : public Slicer::Predicates { Assignment::Ptr memLoc; AST::Ptr jumpTargetExpr; - + set
constAddr; JumpTableFormatPred(ParseAPI::Function *f, ParseAPI::Block *b,