Skip to content

Commit

Permalink
1. Allow jump targets to be from a jump table and multiple constant v…
Browse files Browse the repository at this point in the history
…alues2

2. Stop reading tables once one table entry leads to overlapping basic blocks
  • Loading branch information
mxz297 committed Aug 15, 2017
1 parent 3bd62f7 commit cca9c3c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 8 deletions.
4 changes: 3 additions & 1 deletion parseAPI/src/IndirectASTVisitor.C
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 21 additions & 2 deletions parseAPI/src/IndirectAnalyzer.C
Expand Up @@ -22,7 +22,8 @@ using namespace Dyninst::InstructionAPI;
bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > >& 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
Expand Down Expand Up @@ -87,6 +88,7 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector<std::pair< Ad
jtfp.index,
b,
GetMemoryReadSize(jtfp.memLoc),
jtfp.constAddr,
jumpTableOutEdges);
parsing_printf(", find %d edges\n", jumpTableOutEdges.size());
outEdges.insert(outEdges.end(), jumpTableOutEdges.begin(), jumpTableOutEdges.end());
Expand Down Expand Up @@ -183,6 +185,7 @@ void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr,
AbsRegion index,
StridedInterval &indexBound,
int memoryReadSize,
set<Address> &constAddr,
std::vector<std::pair<Address, Dyninst::ParseAPI::EdgeTypeEnum> > &targetEdges) {
CodeSource *cs = block->obj()->cs();
set<Address> jumpTargets;
Expand All @@ -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<Block*> 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
Expand All @@ -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));
}
Expand All @@ -215,7 +234,7 @@ int IndirectControlFlowAnalyzer::GetMemoryReadSize(Assignment::Ptr memLoc) {
if (o.readsMemory()) {
Expression::Ptr exp = o.getValue();
return exp->size();
break;
}
}
return 0;
}
1 change: 1 addition & 0 deletions parseAPI/src/IndirectAnalyzer.h
Expand Up @@ -21,6 +21,7 @@ class IndirectControlFlowAnalyzer {
AbsRegion,
StridedInterval &,
int ,
std::set<Address> &,
std::vector<std::pair<Address, Dyninst::ParseAPI::EdgeTypeEnum> > &);
int GetMemoryReadSize(Assignment::Ptr loc);

Expand Down
49 changes: 45 additions & 4 deletions parseAPI/src/JumpTableFormatPred.C
Expand Up @@ -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<ConstantAST>(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);
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion parseAPI/src/JumpTableFormatPred.h
Expand Up @@ -28,7 +28,7 @@ class JumpTableFormatPred : public Slicer::Predicates {
Assignment::Ptr memLoc;
AST::Ptr jumpTargetExpr;


set<Address> constAddr;

JumpTableFormatPred(ParseAPI::Function *f,
ParseAPI::Block *b,
Expand Down

0 comments on commit cca9c3c

Please sign in to comment.