Skip to content

Commit

Permalink
1. An indirect jump may be shared by several different jump tables. A…
Browse files Browse the repository at this point in the history
…dd value set representations so that we can union jump targets from different tables.

2. Separate input absloc from absloc at the current address, as they may have different values
  • Loading branch information
mxz297 committed Nov 21, 2016
1 parent d43f8e4 commit d811f19
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 137 deletions.
2 changes: 1 addition & 1 deletion parseAPI/src/BoundFactCalculator.C
Expand Up @@ -392,7 +392,7 @@ BoundFact* BoundFactsCalculator::Meet(Node::Ptr curNode) {
first = false;
if (newCopy) newFact = prevFact; else newFact = new BoundFact(*prevFact);
} else {
newFact->Meet(*prevFact);
newFact->Meet(*prevFact, func->entry());
if (newCopy) delete prevFact;
}
}
Expand Down
93 changes: 65 additions & 28 deletions parseAPI/src/BoundFactData.C
Expand Up @@ -360,6 +360,7 @@ BoundValue::BoundValue(int64_t val):
targetBase(0),
tableReadSize(0),
multiply(1),
values(NULL),
isInverted(false),
isSubReadContent(false),
isZeroExtend(false) {}
Expand All @@ -369,6 +370,7 @@ BoundValue::BoundValue(const StridedInterval &si):
targetBase(0),
tableReadSize(0),
multiply(1),
values(NULL),
isInverted(false),
isSubReadContent(false),
isZeroExtend(false){}
Expand All @@ -378,6 +380,7 @@ BoundValue::BoundValue():
targetBase(0),
tableReadSize(0),
multiply(1),
values(NULL),
isInverted(false),
isSubReadContent(false),
isZeroExtend(false) {}
Expand All @@ -387,21 +390,37 @@ BoundValue::BoundValue(const BoundValue & bv):
targetBase(bv.targetBase),
tableReadSize(bv.tableReadSize),
multiply(bv.multiply),
values(NULL),
isInverted(bv.isInverted),
isSubReadContent(bv.isSubReadContent),
isZeroExtend(bv.isZeroExtend)
{
if (bv.values != NULL) {
values = new set<int>(*(bv.values));
}
}

BoundValue::~BoundValue() {
if (values != NULL) {
delete values;
values = NULL;
}
}

bool BoundValue::operator == (const BoundValue &bv) const {
return (interval == bv.interval) &&
(targetBase == bv.targetBase) &&
(tableReadSize == bv.tableReadSize) &&
(multiply == bv.multiply) &&
(isInverted == bv.isInverted) &&
(isSubReadContent == bv.isSubReadContent) &&
(isZeroExtend == bv.isZeroExtend);
if (values == NULL && bv.values == NULL) {
return (interval == bv.interval) &&
(targetBase == bv.targetBase) &&
(tableReadSize == bv.tableReadSize) &&
(multiply == bv.multiply) &&
(isInverted == bv.isInverted) &&
(isSubReadContent == bv.isSubReadContent) &&
(isZeroExtend == bv.isZeroExtend);
} else if (values != NULL && bv.values != NULL) {
return *values == *bv.values;
} else {
return false;
}
}

bool BoundValue::operator != (const BoundValue &bv) const {
Expand All @@ -417,18 +436,32 @@ BoundValue & BoundValue::operator = (const BoundValue &bv) {
isInverted = bv.isInverted;
isSubReadContent = bv.isSubReadContent;
isZeroExtend = bv.isZeroExtend;
if (values != NULL) {
delete values;
values = NULL;
}
if (bv.values != NULL) {
values = new set<int>(*bv.values);
}
return *this;

}

void BoundValue::Print() {
parsing_printf("Interval %s, ", interval.format().c_str() );
parsing_printf("targetBase %lx, ",targetBase);
parsing_printf("tableReadSize %d, ", tableReadSize);
parsing_printf("multiply %d, ", multiply);
parsing_printf("isInverted %d, ", isInverted);
parsing_printf("isSubReadContent %d, ", isSubReadContent);
parsing_printf("isZeroExtend %d\n", isZeroExtend);
if (values == NULL) {
parsing_printf("Interval %s, ", interval.format().c_str() );
parsing_printf("targetBase %lx, ",targetBase);
parsing_printf("tableReadSize %d, ", tableReadSize);
parsing_printf("multiply %d, ", multiply);
parsing_printf("isInverted %d, ", isInverted);
parsing_printf("isSubReadContent %d, ", isSubReadContent);
parsing_printf("isZeroExtend %d\n", isZeroExtend);
} else {
parsing_printf("Values:");
for (auto vit = values->begin(); vit != values->end(); ++vit)
parsing_printf(" %x", *vit);
parsing_printf("\n");
}
}


Expand Down Expand Up @@ -471,7 +504,7 @@ void BoundValue::DeleteElementFromInterval(int64_t val) {
interval.DeleteElement(val);
}

void BoundValue::Join(BoundValue &bv) {
void BoundValue::Join(BoundValue &bv, Block *b) {
// If one is a table read and the other is a constant,
// assume that the constant appears in the table read.
if (tableReadSize > 0 && bv.interval.stride == 0) {
Expand All @@ -481,6 +514,21 @@ void BoundValue::Join(BoundValue &bv) {
*this = bv;
return;
}
if (tableReadSize > 0 && bv.tableReadSize > 0) {
// If both paths represent a table read,
// it could be a case where multiple jump tables share
// an indirect jump.
// Example: 0x47947 at libc-2.17.so
set<int> left, right;
bool leftRet, rightRet;
leftRet = PerformTableRead(*this, left, b->obj()->cs());
rightRet = PerformTableRead(bv, right, b->obj()->cs());
if (leftRet && rightRet) {
left.insert(right.begin(), right.end());
values = new set<int> (left);
return;
}
}
if (tableReadSize != bv.tableReadSize) {
// Unless boths are table reads, we stop trakcing
// how the read is used.
Expand Down Expand Up @@ -694,15 +742,15 @@ void BoundValue::MemoryRead(Block* b, int readSize) {
}
}

void BoundFact::Meet(BoundFact &bf) {
void BoundFact::Meet(BoundFact &bf, Block* b) {
for (auto fit = fact.begin(); fit != fact.end();) {
BoundValue *val2 = bf.GetBound(fit->first);
// if ast fit->first cannot be found in bf,
// then fit->first is top on this path.
// Anything joins top becomes top
if (val2 != NULL) {
BoundValue *val1 = fit->second;
val1->Join(*val2);
val1->Join(*val2, b);
++fit;
} else {
auto toErase = fit;
Expand Down Expand Up @@ -1538,17 +1586,6 @@ AST::Ptr BoundFact::GetAlias(const AST::Ptr ast) {
}

void BoundFact::TrackAlias(AST::Ptr expr, AST::Ptr outAST, bool findBound) {
// This definition should kill all existing aliases
// involving outAST, as outAST is assigned to a new value
parsing_printf("\tTracking alias for %s = %s\n", outAST->format().c_str(), expr->format().c_str());
for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ) {
if (ContainAnAST(ait->second , outAST)) {
auto e = ait;
++ait;
aliasMap.erase(e);
} else ++ait;
}

expr = SubstituteAnAST(expr, aliasMap);
bool find = false;
for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ++ait) {
Expand Down
13 changes: 11 additions & 2 deletions parseAPI/src/BoundFactData.h
Expand Up @@ -81,6 +81,7 @@ struct BoundValue {
// Otherwise, tableReadSize reprenents the number bytes of the access
int tableReadSize;
int multiply;
std::set<int> * values;
bool isInverted;
bool isSubReadContent;
bool isZeroExtend;
Expand All @@ -89,6 +90,7 @@ struct BoundValue {
BoundValue();
BoundValue(const BoundValue & bv);
BoundValue& operator = (const BoundValue &bv);
~BoundValue();
bool operator< (const BoundValue &bv) const { return interval < bv.interval; }
bool operator== (const BoundValue &bv) const;
bool operator!= (const BoundValue &bv) const;
Expand All @@ -97,7 +99,7 @@ struct BoundValue {
void SetToBottom();
void IntersectInterval(StridedInterval &si);
void DeleteElementFromInterval(int64_t val);
void Join(BoundValue &bv);
void Join(BoundValue &bv, ParseAPI::Block* b);
void ClearTableCheck();
void Add(const BoundValue &rhs);
void And(const BoundValue &rhs);
Expand Down Expand Up @@ -152,6 +154,13 @@ struct BoundFact {

vector<RelationShip*> relation;

// We need to track aliases of each register and memory locations.
// The left hand side represents an abstract location at the current address
// and the right hand side represents an AST of input absloc locations.
// eax at the current location can be different from eax at the input absloc location
//
// Register abstract location with address 0 represents an absloc at the current address
// Register abstract location with address 1 represents an input absloc
typedef std::map<AST::Ptr, AST::Ptr> AliasMap;
AliasMap aliasMap;

Expand Down Expand Up @@ -210,7 +219,7 @@ struct BoundFact {
BoundValue* GetBound(const AST::Ptr ast);
BoundValue* GetBound(const AST* ast);
AST::Ptr GetAlias(const AST::Ptr ast);
void Meet(BoundFact &bf);
void Meet(BoundFact &bf, ParseAPI::Block* b);


bool ConditionalJumpBound(InstructionAPI::Instruction::Ptr insn, EdgeTypeEnum type);
Expand Down
109 changes: 108 additions & 1 deletion parseAPI/src/IndirectASTVisitor.C
Expand Up @@ -5,6 +5,11 @@
#include <algorithm>

using namespace Dyninst::ParseAPI;
#define SIGNEX_64_32 0xffffffff00000000LL
#define SIGNEX_64_16 0xffffffffffff0000LL
#define SIGNEX_64_8 0xffffffffffffff00LL
#define SIGNEX_32_16 0xffff0000
#define SIGNEX_32_8 0xffffff00

Address PCValue(Address cur, size_t insnSize, Architecture a) {
switch (a) {
Expand Down Expand Up @@ -288,7 +293,7 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) {
case ROSEOperation::ifOp:
if (IsResultBounded(ast->child(1)) && IsResultBounded(ast->child(2))) {
BoundValue *val = new BoundValue(*GetResultBound(ast->child(1)));
val->Join(*GetResultBound(ast->child(2)));
val->Join(*GetResultBound(ast->child(2)), block);
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
}
Expand Down Expand Up @@ -404,6 +409,12 @@ AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap) {
for (unsigned i = 0 ; i < totalChildren; ++i) {
ast->setChild(i, SubstituteAnAST(ast->child(i), aliasMap));
}
if (ast->getID() == AST::V_VariableAST) {
// If this variable is not in the aliasMap yet,
// this variable is from the input.
VariableAST::Ptr varAST = boost::static_pointer_cast<VariableAST>(ast);
return VariableAST::create(Variable(varAST->val().reg, 1));
}
return ast;

}
Expand Down Expand Up @@ -497,3 +508,99 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) {
}
return AST::Ptr();
}

bool PerformTableRead(BoundValue &target, set<int> & jumpTargets, CodeSource *cs) {

Address tableBase = (Address)target.interval.low;
Address tableLastEntry = (Address)target.interval.high;
int addressWidth = cs->getAddressWidth();
if (addressWidth == 4) {
tableBase &= 0xffffffff;
tableLastEntry &= 0xffffffff;
}

#if defined(os_windows)
tableBase -= cs->loadAddress();
tableLastEntry -= cs->loadAddress();
#endif

if (!cs->isCode(tableBase) && !cs->isData(tableBase)) {
parsing_printf("\ttableBase 0x%lx invalid, returning false\n", tableBase);
parsing_printf("Not jump table format!\n");
return false;
}
if (!cs->isReadOnly(tableBase)) {
parsing_printf("\ttableBase 0x%lx not read only, returning false\n", tableBase);
parsing_printf("Not jump table format!\n");
return false;
}


for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) {
if (!cs->isCode(tableEntry) && !cs->isData(tableEntry)) continue;
if (!cs->isReadOnly(tableEntry)) continue;
int targetAddress = 0;
if (target.tableReadSize > 0) {
switch (target.tableReadSize) {
case 8:
targetAddress = *(const uint64_t *) cs->getPtrToInstruction(tableEntry);
break;
case 4:
targetAddress = *(const uint32_t *) cs->getPtrToInstruction(tableEntry);
if (target.isZeroExtend) break;
if ((addressWidth == 8) && (targetAddress & 0x80000000)) {
targetAddress |= SIGNEX_64_32;
}
break;
case 2:
targetAddress = *(const uint16_t *) cs->getPtrToInstruction(tableEntry);
if (target.isZeroExtend) break;
if ((addressWidth == 8) && (targetAddress & 0x8000)) {
targetAddress |= SIGNEX_64_16;
}
if ((addressWidth == 4) && (targetAddress & 0x8000)) {
targetAddress |= SIGNEX_32_16;
}

break;
case 1:
targetAddress = *(const uint8_t *) cs->getPtrToInstruction(tableEntry);
if (target.isZeroExtend) break;
if ((addressWidth == 8) && (targetAddress & 0x80)) {
targetAddress |= SIGNEX_64_8;
}
if ((addressWidth == 4) && (targetAddress & 0x80)) {
targetAddress |= SIGNEX_32_8;
}

break;

default:
parsing_printf("Invalid memory read size %d\n", target.tableReadSize);
return false;
}
targetAddress *= target.multiply;
if (target.targetBase != 0) {
if (target.isSubReadContent)
targetAddress = target.targetBase - targetAddress;
else
targetAddress += target.targetBase;

}
#if defined(os_windows)
targetAddress -= cs->loadAddress();
#endif
} else targetAddress = tableEntry;

if (addressWidth == 4) targetAddress &= 0xffffffff;
parsing_printf("Jumping to target %lx,", targetAddress);
if (cs->isCode(targetAddress)) {
// Jump tables may contain may repetitious entries.
// We only want to create one edge for disctinct each jump target.
jumpTargets.insert(targetAddress);
}
// If the jump target is resolved to be a constant,
if (target.interval.stride == 0) break;
}
return true;
}
4 changes: 3 additions & 1 deletion parseAPI/src/IndirectASTVisitor.h
Expand Up @@ -5,7 +5,7 @@

#include "DynAST.h"
#include "SymEval.h"

#include "CodeSource.h"
#include "BoundFactData.h"

using namespace std;
Expand All @@ -17,6 +17,8 @@ AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr);
AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap);
AST::Ptr DeepCopyAnAST(AST::Ptr ast);
bool ContainAnAST(AST::Ptr root, AST::Ptr check);
bool PerformTableRead(BoundValue &target, set<int> & jumpTargets, CodeSource*);


// On x86 and x86-64, the value of PC is post-instruction,
// which is the current address plus the length of the instruction.
Expand Down

0 comments on commit d811f19

Please sign in to comment.