Skip to content

Commit

Permalink
1. More strict check when searching for the instruction that spills r…
Browse files Browse the repository at this point in the history
…egister to stack

2. Add code for checking jump target for variable argument functions
  • Loading branch information
mxz297 committed Aug 15, 2017
1 parent 6ac4c79 commit 3e83b78
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 29 deletions.
93 changes: 69 additions & 24 deletions parseAPI/src/IndirectAnalyzer.C
Expand Up @@ -18,12 +18,49 @@
using namespace Dyninst::ParseAPI;
using namespace Dyninst::InstructionAPI;

static bool IsIndexing(AST::Ptr node, AbsRegion &index) {
RoseAST::Ptr n = boost::static_pointer_cast<RoseAST>(node);
if (n->val().op != ROSEOperation::sMultOp &&
n->val().op != ROSEOperation::uMultOp &&
n->val().op != ROSEOperation::shiftLOp) return false;
if (n->child(0)->getID() != AST::V_VariableAST) return false;
if (n->child(1)->getID() != AST::V_ConstantAST) return false;
VariableAST::Ptr var = boost::static_pointer_cast<VariableAST>(n->child(0));
index = var->val().reg;
return true;
}

static bool IsVariableArgumentFormat(AST::Ptr t, AbsRegion &index) {
if (t->getID() != AST::V_RoseAST) {
return false;
}
RoseAST::Ptr rt = boost::static_pointer_cast<RoseAST>(t);
if (rt->val().op != ROSEOperation::addOp) {
return false;
}
if (rt->child(0)->getID() != AST::V_ConstantAST || rt->child(1)->getID() != AST::V_RoseAST) {
return false;
}
RoseAST::Ptr c1 = boost::static_pointer_cast<RoseAST>(rt->child(1));
if (c1->val().op == ROSEOperation::addOp) {
if (c1->child(0)->getID() == AST::V_RoseAST && c1->child(1)->getID() == AST::V_ConstantAST) {
RoseAST::Ptr lc = boost::static_pointer_cast<RoseAST>(c1->child(0));
ConstantAST::Ptr rc = boost::static_pointer_cast<ConstantAST>(c1->child(1));
if (lc->val().op == ROSEOperation::invertOp && rc->val().val == 1) {
return IsIndexing(lc->child(0), index);
}
}
return false;
}
return IsIndexing(rt->child(1), index);

}

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() == 0x4c6dcc) dyn_debug_parsing=1; else dyn_debug_parsing=0;
// if (block->last() == 0xa8d7c9) 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 @@ -53,37 +90,45 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector<std::pair< Ad
// we do not try to resolve it
parsing_printf("In function %s, Address %lx, jump target format %s, index loc %s, index variable %s", func->name().c_str(), block->last(), jtfp.format().c_str(), jtfp.indexLoc ? jtfp.indexLoc->format().c_str() : "" , jtfp.index.format().c_str() );

bool variableArguFormat = false;
if (!jtfp.isJumpTableFormat()) {
parsing_printf(" not jump table\n");
return false;
if (jtfp.jumpTargetExpr && func->entry() == block && IsVariableArgumentFormat(jtfp.jumpTargetExpr, jtfp.index)) {
parsing_printf("\tVariable number of arguments format, index %s\n", jtfp.index.format().c_str());
variableArguFormat = true;
} else {
return false;
}
}

Slicer indexSlicer(jtfp.indexLoc, jtfp.indexLoc->block(), func, false, false);
JumpTableIndexPred jtip(func, block, jtfp.index, se);
jtip.setSearchForControlFlowDep(true);
slice = indexSlicer.backwardSlice(jtip);
StridedInterval b;
if (!variableArguFormat) {
Slicer indexSlicer(jtfp.indexLoc, jtfp.indexLoc->block(), func, false, false);
JumpTableIndexPred jtip(func, block, jtfp.index, se);
jtip.setSearchForControlFlowDep(true);
slice = indexSlicer.backwardSlice(jtip);

// if (!jtip.findBound && block->obj()->cs()->getArch() != Arch_aarch64) {
if (!jtip.findBound ) {
if (!jtip.findBound && block->obj()->cs()->getArch() != Arch_aarch64) {

// After the slicing is done, we do one last check to
// see if we can resolve the indirect jump by assuming
// one byte read is in bound [0,255]
GraphPtr g = jtip.BuildAnalysisGraph(indexSlicer.visitedEdges);

BoundFactsCalculator bfc(func, g, func->entry() == block, true, se);
bfc.CalculateBoundedFacts();
// After the slicing is done, we do one last check to
// see if we can resolve the indirect jump by assuming
// one byte read is in bound [0,255]
GraphPtr g = jtip.BuildAnalysisGraph(indexSlicer.visitedEdges);
BoundFactsCalculator bfc(func, g, func->entry() == block, true, se);
bfc.CalculateBoundedFacts();

StridedInterval target;
jtip.IsIndexBounded(g, bfc, target);
}
StridedInterval b;
if (jtip.findBound) {
parsing_printf(" bound %s", jtip.bound.format().c_str());
b = jtip.bound;
StridedInterval target;
jtip.IsIndexBounded(g, bfc, target);
}
if (jtip.findBound) {
parsing_printf(" bound %s", jtip.bound.format().c_str());
b = jtip.bound;
} else {
parsing_printf(" Cannot find bound, assume there are at most 256 entries and scan the table\n");
b = StridedInterval(1, 0, 255);
}
} else {
parsing_printf(" Cannot find bound, assume there are at most 256 entries and scan the table\n");
b = StridedInterval(1, 0, 255);
b = StridedInterval(1, 0, 8);
}
std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > > jumpTableOutEdges;
ReadTable(jtfp.jumpTargetExpr,
Expand Down
11 changes: 7 additions & 4 deletions parseAPI/src/JumpTableFormatPred.C
Expand Up @@ -233,9 +233,10 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P
index = jtfv.index;
findIndex = true;
}
jumpTargetExpr = jumpTarget;
if (jtfv.findIndex && jtfv.findTableBase) {
parsing_printf("\tRecord jump target expr\n");
jumpTargetExpr = jumpTarget;
findTableBase = true;
parsing_printf("\tFind both table index and table base, current jump target %s\n", jumpTargetExpr->format().c_str());
return false;
}

Expand Down Expand Up @@ -303,8 +304,10 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer::
if (addr > 0 && iit->first > addr) continue;
Instruction::Ptr i = iit->second;
// We find an the first instruction that only writes to memory
// and the memory operand has the exact AST as the memory read
if (!i->readsMemory() && i->writesMemory()) {
// and the memory operand has the exact AST as the memory read.
// Ideally, we need an architecture independent way to check whether this is a move instruction.
// Category c_NoCategory excludes lots of non-move instructions
if (!i->readsMemory() && i->writesMemory() && i->getCategory() == c_NoCategory) {
set<Expression::Ptr> memWrites;
i->getMemoryWriteOperands(memWrites);
if (memWrites.size() == 1 && *memRead == *(*memWrites.begin())) {
Expand Down
4 changes: 3 additions & 1 deletion parseAPI/src/JumpTableFormatPred.h
Expand Up @@ -21,6 +21,7 @@ class JumpTableFormatPred : public Slicer::Predicates {
bool jumpTableFormat;
bool unknownInstruction;
bool findIndex;
bool findTableBase;

AbsRegion index;
Assignment::Ptr indexLoc;
Expand All @@ -40,12 +41,13 @@ class JumpTableFormatPred : public Slicer::Predicates {
jumpTableFormat = true;
unknownInstruction = false;
findIndex = false;
findTableBase = false;
firstMemoryRead = true;
}

virtual bool modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::Ptr g, Slicer*);
std::string format();
bool isJumpTableFormat() { return jumpTableFormat && findIndex && jumpTargetExpr;}
bool isJumpTableFormat() { return jumpTableFormat && findIndex && findTableBase;}
bool findSpillRead(Graph::Ptr g, SliceNode::Ptr &);
bool adjustSliceFrame(Slicer::SliceFrame &frame, SliceNode::Ptr, Slicer*);
};
Expand Down

0 comments on commit 3e83b78

Please sign in to comment.